text: /*
  * Kendo UI Web v2012.2.710 (http://kendoui.com)
  * Copyright 2012 Telerik AD. All rights reserved.
  *
  * Kendo UI Web commercial licenses may be obtained at http://kendoui.com/web-license
  * If you do not own a commercial license, this file shall be governed by the
  * GNU General Public License (GPL) version 3.
  * For GPL requirements, please review: http://www.gnu.org/copyleft/gpl.html
  */
  /**
   * @fileOverview Provides a TabStrip implementation which can be used to display a collection of tabs with associated
   * content
   */
  
  (function ($, undefined) {
      /**
       *
       * @name kendo.ui.TabStrip.Description
       *
       * @section
       * <p>
       *  A <strong>TabStrip</strong> displays a collection of tabs with associated content. It is composed of an
       *  unordered list of items - representing tabs - and a collection of div elements, which contain the content for
       *  each tab.
       * </p>
       * <h3>Getting Started</h3>
       *
       * @exampleTitle Create an unordered list for tabs with associated div elements for content
       * @example
       * <div id="tabStrip">
       *     <ul>
       *         <li>First tab</li>
       *         <li>Second tab</li>
       *     </ul>
       *     <div>First tab content</div>
       *     <div>Second tab content</div>
       * </div>
       *
       * @section
       * <p>
       *  Initialization of a <strong>TabStrip</strong> should occur after the DOM is fully loaded. It is recommended
       *  that initialization the <strong>TabStrip</strong> occur within a handler is provided to $(document).ready().
       * </p>
       *
       * @exampleTitle Initialize a TabStrip using a selector within $(document).ready()
       * @example
       * $(document).ready(function() {
       *     $("#tabStrip").kendoTabStrip();
       * });
       *
       * @exampleTitle Initialize the TabStrip using JSON data object
       * @example
       * $(document).ready(function() {
       *     $("#tabstrip").kendoTabStrip({
       *         dataTextField: "text",
       *         dataContentField: "content",
       *         dataUrlField: "url",
       *         dataImageUrlField: "imageUrl",
       *         dataSpriteCssClass: "spriteCssClass",
       *         dataContentUrlField: "contentUrl",
       *         dataSource:
       *         [{
       *             text: "Item 1",
       *             url: "http://www.kendoui.com"               // Link URL if navigation is needed, optional.
       *         },
       *         {
       *             text: "Item 2",
       *             content: "text"                             // Content for the content element
       *         },
       *         {
       *             text: "Item 3",
       *             contentUrl: "partialContent.html"           // From where to load the item content
       *         },
       *         {
       *             text: "Item 4",
       *             imageUrl: "http://www.kendoui.com/test.jpg" // Item image URL, optional.
       *         },
       *         {
       *             text: "Item 5",
       *             spriteCssClass: "imageClass3"               // Item image sprite CSS class, optional.
       *         }]
       *     });
       * });
       *
       * @section
       * <p>
       *  The tabs of a <strong>TabStrip</strong> are not required to have content. Should a tab have no content, it is
       *  safe to omit its associated div.
       * </p>
       * <h3>Loading TabStrip content with AJAX</h3>
       * <p>
       *  While any valid technique for loading AJAX content can be used, a <strong>TabStrip</strong> supports loading
       *  content from URLs in an asynchronous manner. These URLs should return HTML fragments that can be loaded in a
       *  TabStrip content area. Content DIVs are not required and if present should be completely empty for AJAX loading
       *  to work.
       * </p>
       *
       * @exampleTitle Loading Tab content asynchronously
       * @example
       * <div id="tabstrip">
       *     <ul>
       *         <li>First Tab</li>
       *         <li>Second Tab</li>
       *     </ul>
       *     <div></div>
       *     <div></div>
       *  </div>
       *
       * @exampleTitle Initialize TabStrip and configure one tab with async content loading
       * @example
       * $(document).ready(function(){
       *     $("#tabstrip").kendoTabStrip({
       *         contentUrls: [null, "html-content-snippet.html"]
       *     });
       *  });
       *
       * @section
       * <h3>Dynamically Configure TabStrip Tabs</h3>
       * <p>
       *  The <strong>TabStrip</strong> API provides several methods for dynamically adding or removing tabs. To add
       *  tabs, provide the new item as a JSON object along with a reference item that will be used to determine the
       *  placement in the <strong>TabStrip</strong>. Note: append() does not require a reference item.
       * <p>
       * <p>
       *  A reference item is simply a target DOM element of a tab that already exists in the TabStrip. Any valid
       *  selector may be used to obtain a reference to the target item.
       * </p>
       * <p>Removing an item requires a reference to the target element.</p>
       *
       * @exampleTitle Dynamically add a new tab
       * @example
       * var tabStrip = $("#tabStrip").data("kendoTabStrip");
       * tabStrip.insertAfter(
       *     { text: "New Tab" },
       *     tabstrip.tabGroup.children("li:last")
       * );
       *
       * @section
       * <h3>Selecting a Tab on Initial Load</h3>
       * <p>
       *  It is possible to select a tab and display its associated content upon its initial load. There are two (2) ways
       *  to accomplish this task:
       * </p>
       * <ol>
       *  <li>Add a "k-state-active" class to the DOM element of the tab</li>
       *  <li>Use select() to target and select a tab either by selector or index</li>
       * </ol>
       * <p>Both approaches produce the same result.</p>
       *
       * @exampleTitle Selecting a default tab manually using HTML
       * @example
       * <div id="tabstrip">
       *     <ul>
       *         <li class="k-state-active">First Tab</li>
       *         <li>Second Tab</li>
       *     </ul>
       *     <div></div>
       *     <div></div>
       * </div>
       *
       * @exampleTitle Initialize a TabStrip and select first tab via select(element)
       * @example
       * $(document).ready(function(){
       *     var tabstrip = $("#tabstrip").kendoTabStrip().data("kendoTabStrip");
       *     tabstrip.select(tabstrip.tabGroup.children("li:first"));
       * });
       *
       * @exampleTitle Initialize a TabStrip and select first tab via select(index)
       * @example
       * $(document).ready(function(){
       *     var tabstrip = $("#tabstrip").kendoTabStrip().data("kendoTabStrip");
       *     tabstrip.select(1);
       * });
       *
       * @section
       * <h3>Accessing an Existing TabStrip</h3>
       * <p>
       *  You can reference an existing <b>TabStrip</b> instance via
       *  <a href="http://api.jquery.com/jQuery.data/">jQuery.data()</a>. Once a reference has been established, you can
       *  use the API to control its behavior.
       * </p>
       *
       * @exampleTitle Accessing an existing TabStrip instance
       * @example
       * var tabStrip = $("#tabStrip").data("kendoTabStrip");
       *
       */
      var kendo = window.kendo,
          ui = kendo.ui,
          map = $.map,
          each = $.each,
          trim = $.trim,
          extend = $.extend,
          template = kendo.template,
          Widget = ui.Widget,
          excludedNodesRegExp = /^(a|div)$/i,
          IMG = "img",
          HREF = "href",
          LINK = "k-link",
          LAST = "k-last",
          CLICK = "click",
          ERROR = "error",
          EMPTY = ":empty",
          IMAGE = "k-image",
          FIRST = "k-first",
          SELECT = "select",
          ACTIVATE = "activate",
          CONTENT = "k-content",
          CONTENTURL = "contentUrl",
          MOUSEENTER = "mouseenter",
          MOUSELEAVE = "mouseleave",
          CONTENTLOAD = "contentLoad",
          CLICKABLEITEMS = ".k-tabstrip-items > .k-item:not(.k-state-disabled)",
          HOVERABLEITEMS = ".k-tabstrip-items > .k-item:not(.k-state-disabled):not(.k-state-active)",
          DISABLEDLINKS = ".k-tabstrip-items > .k-state-disabled .k-link",
          DISABLEDSTATE = "k-state-disabled",
          DEFAULTSTATE = "k-state-default",
          ACTIVESTATE = "k-state-active",
          HOVERSTATE = "k-state-hover",
          TABONTOP = "k-tab-on-top",
  
          templates = {
              content: template(
                  "<div class='k-content'#= contentAttributes(data) #>#= content(item) #</div>"
              ),
              itemWrapper: template(
                  "<#= tag(item) # class='k-link'#= contentUrl(item) ##= textAttributes(item) #>" +
                      "#= image(item) ##= sprite(item) ##= text(item) #" +
                  "</#= tag(item) #>"
              ),
              item: template(
                  "<li class='#= wrapperCssClass(group, item) #'>" +
                      "#= itemWrapper(data) #" +
                  "</li>"
              ),
              image: template("<img class='k-image' alt='' src='#= imageUrl #' />"),
              sprite: template("<span class='k-sprite #= spriteCssClass #'></span>"),
              empty: template("")
          },
  
          rendering = {
              wrapperCssClass: function (group, item) {
                  var result = "k-item",
                      index = item.index;
  
                  if (item.enabled === false) {
                      result += " k-state-disabled";
                  } else {
                      result += " k-state-default";
                  }
  
                  if (index === 0) {
                      result += " k-first";
                  }
  
                  if (index == group.length-1) {
                      result += " k-last";
                  }
  
                  return result;
              },
              textAttributes: function(item) {
                  return item.url ? " href='" + item.url + "'" : "";
              },
              text: function(item) {
                  return item.encoded === false ? item.text : kendo.htmlEncode(item.text);
              },
              tag: function(item) {
                  return item.url ? "a" : "span";
              },
              contentAttributes: function(content) {
                  return content.active !== true ? " style='display:none'" : "";
              },
              content: function(item) {
                  return item.content ? item.content : item.contentUrl ? "" : "&nbsp;";
              },
              contentUrl: function(item) {
                  return item.contentUrl ? kendo.attr("content-url") + '="' + item.contentUrl + '"' : "";
              }
          };
  
      function updateTabClasses (tabs) {
          tabs.children(IMG)
              .addClass(IMAGE);
  
          tabs.children("a")
              .addClass(LINK)
              .children(IMG)
              .addClass(IMAGE);
  
          tabs.filter(":not([disabled]):not([class*=k-state-disabled])")
              .addClass(DEFAULTSTATE);
  
          tabs.filter("li[disabled]")
              .addClass(DISABLEDSTATE)
              .removeAttr("disabled");
  
          tabs.filter(":not([class*=k-state])")
              .children("a")
              .filter(":focus")
              .parent()
              .addClass(ACTIVESTATE + " " + TABONTOP);
  
          tabs.each(function() {
              var item = $(this);
  
              if (!item.children("." + LINK).length) {
                  item
                      .contents()      // exclude groups, real links, templates and empty text nodes
                      .filter(function() { return (!this.nodeName.match(excludedNodesRegExp) && !(this.nodeType == 3 && !trim(this.nodeValue))); })
                      .wrapAll("<a class='" + LINK + "'/>");
              }
          });
  
      }
  
      function updateFirstLast (tabGroup) {
          var tabs = tabGroup.children(".k-item");
  
          tabs.filter(".k-first:not(:first-child)").removeClass(FIRST);
          tabs.filter(".k-last:not(:last-child)").removeClass(LAST);
          tabs.filter(":first-child").addClass(FIRST);
          tabs.filter(":last-child").addClass(LAST);
      }
  
      var TabStrip = Widget.extend({/** @lends kendo.ui.TabStrip.prototype */
          /**
           *
           * Creates a TabStrip instance.
           *
           * @constructs
           * @extends kendo.ui.Widget
           * @class TabStrip UI widget
           *
           * @param {Selector} element DOM element
           * @param {Object} options Configuration options.
           *
           * @option {Object} [animation]
           * A collection of visual animations used when <strong>TabStrip</strong> tab are selected through
           * user interactions. Setting this option to <strong>false</strong> will disable all animations.
           *
           * _exampleTitle Defining custom animations when selecting tabs
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     animation: {
           *         // fade-out current tab over 1000 milliseconds
           *         close: {
           *             duration: 1000,
           *             effects: "fadeOut"
           *         },
           *        // fade-in new tab over 500 milliseconds
           *        open: {
           *            duration: 500,
           *            effects: "fadeIn"
           *        }
           *    }
           * });
           *
           * @option {Object} [animation.open]
           * The visual animation(s) that will be used when the new tab is shown.
           *
           * _exampleTitle Defining a custom animation when new tab is shown that executes over 200 milliseconds
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     animation: {
           *         open: {
           *             duration: 200,
           *             effects: "expand:vertical"
           *         }
           *     }
           * });
           *
           * @option {Number} [animation.open.duration] <200>
           * The number of milliseconds used for the visual animation when a new tab is shown.
           *
           * _exampleTitle Defining animation when a new tab is shown that executes over 1000 milliseconds
           * _example
           * $("#tabstrip").kendoTabStrip({
           *  animation: {
           *       open: {
           *           duration: 1000
           *       }
           *    }
           * });
           *
           * @option {String} [animation.open.effects] <"expand:vertical fadeIn">
           * A whitespace-separated string of animation effects that are used when a new tab is shown. Options include
           * <strong>"expand:vertical"</strong> and <strong>"fadeIn"</strong>.
           *
           * @option {Boolean} [animation.open.show] <true>
           *
           * @option {Object} [animation.close]
           * The visual animation(s) that will be used when the current tab is closed.
           *
           * _exampleTitle Defining a custom animation for the current tab that
           * executes over 200 milliseconds
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     animation: {
           *         close: {
           *             duration: 200,
           *             effects: "fadeOut"
           *         }
           *     }
           * });
           *
           * @option {Number} [animation.close.duration] <200>
           * The number of milliseconds used for the visual animation when the current tab is closed.
           *
           * _exampleTitle Animating the current tab for 1000 milliseconds
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     animation: {
           *         close: {
                         duration: 1000
                     }
           *   }
           * });
           *
           * @option {String} [animation.close.effects]
           * A whitespace-delimited string of animation effects that are utilized when the current tab
           * is closed. By default not specified - uses the opening animation with reverse.
           *
           * _exampleTitle Fading-out the current tab for 1000 milliseconds
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     animation: {
           *         close: {
           *             duration: 1000,
           *             effects: "fadeOut"
           *         }
           *     }
           * });
           *
           * @option {String} [dataTextField] <""> Sets the field of the data item that provides the text name of the tab.
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     dataTextField: "Name",
           *     dataSource: data
           * });
           *
           * @option {String} [dataContentField] <""> Sets the field of the data item that provides the text content of
           * the tab content element.
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     dataTextField: "Name",
           *     dataContentField: "Content",
           *     dataSource: data
           * });
           *
           * @option {String} [dataImageUrlField] <""> Sets the field of the data item that provides the image URL of
           * the tab.
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     dataTextField: "Name",
           *     dataImageUrlField: "ImageUrl",
           *     dataSource: data
           * });
           *
           * @option {String} [dataUrlField] <""> Sets the field of the data item that provides the link URL for the
           * tab.
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     dataTextField: "Name",
           *     dataUrlField: "Url",
           *     dataSource: data
           * });
           *
           * @option {String} [dataSpriteCssClass] <""> Sets the field of the data item that provides the CSS class of
           * the tab.
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     dataTextField: "Name",
           *     dataSpriteCssClass: "CssClass",
           *     dataSource: data
           * });
           *
           * @option {String} [dataContentUrlField] <""> Sets the field of the data item that provides the URL for
           * the ajax loaded tab content.
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     dataTextField: "Name",
           *     dataContentUrlField: "ContentUrl",
           *     dataSource: data
           * });
           *
           * @option {Boolean} [collapsible] <false>
           * Specifies whether the TabStrip should be able to collapse completely when clicking an expanded tab.
           *
           * _exampleTitle Turning on tab collapsing
           * _example
           * $("#tabstrip").kendoTabStrip({
           *     collapsible: true
           * });
           *
           */
          init: function(element, options) {
              var that = this;
  
              that._animations(options);
  
              Widget.fn.init.call(that, element, options);
  
              if (that.element.is("ul")) {
                  that.wrapper = that.element.wrapAll("<div />").parent();
              } else {
                  that.wrapper = that.element;
              }
  
              options = that.options;
  
              that.wrapper
                  .delegate(CLICKABLEITEMS, CLICK, $.proxy(that._click, that))
                  .delegate(HOVERABLEITEMS, MOUSEENTER + " " + MOUSELEAVE, that._toggleHover)
                  .delegate(DISABLEDLINKS, CLICK, false);
  
              that._updateClasses();
  
              that._dataSource();
  
              if (options.dataSource) {
                  that.dataSource.fetch();
              }
  
              if (that.options.contentUrls) {
                  that.wrapper.find(".k-tabstrip-items > .k-item")
                      .each(function(index, item) {
                          $(item).find(">." + LINK).data(CONTENTURL, that.options.contentUrls[index]);
                      });
              }
  
              var selectedItems = that.wrapper.find("li." + ACTIVESTATE),
                  content = $(that.contentElement(selectedItems.parent().children().index(selectedItems)));
  
              if (content.length > 0 && content[0].childNodes.length === 0) {
                  that.activateTab(selectedItems.eq(0));
              }
  
              kendo.notify(that);
          },
  
          _dataSource: function() {
              var that = this;
  
              if (that.dataSource && that._refreshHandler) {
                  that.dataSource.unbind("change", that._refreshHandler);
              } else {
                  that._refreshHandler = $.proxy(that.refresh, that);
              }
  
              that.dataSource = kendo.data.DataSource.create(that.options.dataSource)
                                  .bind("change", that._refreshHandler);
          },
  
          setDataSource: function(dataSource) {
              this.options.dataSource = dataSource;
              this._dataSource();
              dataSource.fetch();
          },
  
          _animations: function(options) {
              if (options && ("animation" in options) && !options.animation) {
                  options.animation = { open: { effects: {}, show: true }, close: { effects: {} } }; // No animation
              }
          },
  
          refresh: function(e) {
              var that = this,
                  options = that.options,
                  text = kendo.getter(options.dataTextField),
                  content = kendo.getter(options.dataContentField),
                  contentUrl = kendo.getter(options.dataContentUrlField),
                  image = kendo.getter(options.dataImageUrlField),
                  url = kendo.getter(options.dataUrlField),
                  sprite = kendo.getter(options.dataSpriteCssClass),
                  idx,
                  tabs = [],
                  tab,
                  action,
                  view = that.dataSource.view(),
                  length;
  
  
              e = e || {};
              action = e.action;
  
              if (action) {
                 view = e.items;
              }
  
              for (idx = 0, length = view.length; idx < length; idx ++) {
                  tab = {
                      text: text(view[idx])
                  };
  
                  if (options.dataContentField) {
                      tab.content = content(view[idx]);
                  }
  
                  if (options.dataContentUrlField) {
                      tab.contentUrl = contentUrl(view[idx]);
                  }
  
                  if (options.dataUrlField) {
                      tab.url = url(view[idx]);
                  }
  
                  if (options.dataImageUrlField) {
                      tab.imageUrl = image(view[idx]);
                  }
  
                  if (options.dataSpriteCssClass) {
                      tab.spriteCssClass = sprite(view[idx]);
                  }
  
                  tabs[idx] = tab;
              }
  
              if (e.action == "add") {
                  if (e.index < that.tabGroup.children().length) {
                      that.insertBefore(tabs, that.tabGroup.children().eq(e.index));
                  } else {
                      that.append(tabs);
                  }
              } else if (e.action == "remove") {
                  for (idx = 0; idx < view.length; idx++) {
                     that.remove(e.index);
                  }
              } else if (e.action == "itemchange") {
                  idx = that.dataSource.view().indexOf(view[0]);
                  if (e.field === options.dataTextField) {
                      that.tabGroup.children().eq(idx).find(".k-link").text(view[0].get(e.field));
                  }
              } else {
                  that.trigger("dataBinding");
                  that.append(tabs);
                  that.trigger("dataBound");
              }
          },
  
          value: function(value) {
              var that = this;
  
              if (value !== undefined) {
                  if (value != that.value()) {
                     that.tabGroup.children().each(function() {
                          if ($.trim($(this).text()) == value) {
                              that.select(this);
                          }
                     });
                  }
              } else {
                  return that.select().text();
              }
          },
  
          items: function() {
              return this.tabGroup[0].children;
          },
  
          setOptions: function(options) {
              var animation = this.options.animation;
  
              this._animations(options);
  
              options.animation = extend(true, animation, options.animation);
  
              Widget.fn.setOptions.call(this, options);
          },
  
          events: [
              /**
               *
               * Triggered before a tab is selected.
               *
               * @name kendo.ui.TabStrip#select
               * @event
               *
               * @param {Event} e
               *
               * @param {HTMLElement} e.item
               * The selected item chosen by a user.
               *
               * @param {Element} e.contentElement
               * The content element of the tab going to be selected.
               *
               * @exampleTitle Attach select event handler during initialization; detach via unbind()
               * @example
               * // event handler for select
               * var onSelect = function(e) {
               *     // access the selected item via e.item (HTMLElement)
               * };
               *
               * // attach select event handler during initialization
               * var tabStrip = $("#tabStrip").kendoTabStrip({
               *     select: onSelect
               * });
               *
               * // detach select event handler via unbind()
               * tabStrip.data("kendoTabStrip").unbind("select", onSelect);
               *
               * @exampleTitle Attach select event handler via bind(); detach via unbind()
               * @example
               * // event handler for select
               * var onSelect = function(e) {
               *     // access the selected item via e.item (HTMLElement)
               * };
               *
               * // attach select event handler via bind()
               * $("#tabStrip").data("kendoTabStrip").bind("select", onSelect);
               *
               * // detach select event handler via unbind()
               * $("#tabStrip").data("kendoTabStrip").unbind("select", onSelect);
               *
               */
              SELECT,
              /**
               * Triggered just after a tab is being made visible, but before the end of the animation
               *
               * @name kendo.ui.TabStrip#activate
               * @event
               *
               * @param {Event} e
               *
               * @param {HTMLElement} e.item
               * The activated tab.
               *
               * @param {Element} e.contentElement
               * The content element of the activated tab.
               *
               * @exampleTitle Attach activate event handler during initialization; detach via unbind()
               * @example
               * // event handler for activate
               * var onActivate = function(e) {
               *     // access the activated item via e.item (HTMLElement)
               * };
               *
               * // attach activate event handler during initialization
               * var tabStrip = $("#tabStrip").kendoTabStrip({
               *     activate: onActivate
               * });
               *
               * // detach activate event handler via unbind()
               * tabStrip.data("kendoTabStrip").unbind("activate", onActivate);
               *
               * @exampleTitle Attach activate event handler via bind(); detach via unbind()
               * @example
               * // event handler for activate
               * var onActivate = function(e) {
               *     // access the activated item via e.item (HTMLElement)
               * };
               *
               * // attach activate event handler via bind()
               * $("#tabStrip").data("kendoTabStrip").bind("activate", onActivate);
               *
               * // detach activate event handler via unbind()
               * $("#tabStrip").data("kendoTabStrip").unbind("activate", onActivate);
               *
               */
              ACTIVATE,
              /**
               *
               * Triggered when an AJAX request results in an error.
               *
               * @name kendo.ui.TabStrip#error
               * @event
               *
               * @param {Event} e
               *
               * @param {jqXHR} e.xhr
               * The jqXHR object used to load the content
               *
               * @param {String} e.status
               * The returned status.
               *
               */
              ERROR,
              /**
               *
               * Triggered when content is fetched from an AJAX request.
               *
               * @name kendo.ui.TabStrip#contentLoad
               * @event
               *
               * @param {Event} e
               *
               * @param {Element} e.item
               * The selected item
               *
               * @param {Element} e.contentElement
               * The loaded content element that is retrieved via AJAX.
               *
               */
              CONTENTLOAD,
              "change",
              "dataBinding",
              "dataBound"
          ],
  
          options: {
              name: "TabStrip",
              dataTextField: "",
              dataContentField: "",
              dataImageUrlField: "",
              dataUrlField: "",
              dataSpriteCssClass: "",
              dataContentUrlField: "",
              animation: {
                  open: {
                      effects: "expand:vertical fadeIn",
                      duration: 200,
                      show: true
                  },
                  close: { // if close animation effects are defined, they will be used instead of open.reverse
                      duration: 200
                  }
              },
              collapsible: false
          },
  
          /**
           *
           * Selects the specified tab(s) within a <strong>TabStrip</strong>. If called without arguments, it returns the
           * currently selected tab.
           *
           * @param {Selector/Index} element or index
           * The target tab(s), specified as a selector or index in the tab group.
           *
           * @example
           * tabStrip.select("#tab1");
           *
           * @example
           * tabStrip.select(1);
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           */
          select: function (element) {
              var that = this;
  
              if (arguments.length === 0) {
                  return that.wrapper.find("li." + ACTIVESTATE);
              }
  
              if (!isNaN(element)) {
                  element = that.tabGroup.children().get(element);
              }
  
              element = that.element.find(element);
              $(element).each(function (index, item) {
                  item = $(item);
                  if (!item.hasClass(ACTIVESTATE) && !that.trigger(SELECT, { item: item[0], contentElement: that.contentElement(item.index()) })) {
                      that.activateTab(item);
                  }
              });
  
              return that;
          },
  
          /**
           *
           * Disables (<strong>false</strong>) or enables (<strong>true</strong>) a tab(s) of a <strong>TabStrip</strong>.
           *
           * @param {Selector} element
           * The target tab(s), specified as a selector, to be enabled (<strong>true</strong>) or disabled
           * (<strong>false</strong>).
           *
           * @param {Boolean} enable
           * Desired state of the tab(s) specified by the selector; enabled (<strong>true</strong>) or disabled
           * (<strong>false</strong>).
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           */
          enable: function (element, state) {
              this._toggleDisabled(element, state !== false);
  
              return this;
          },
  
          /**
           *
           * Disables a tab(s) of a <strong>TabStrip</strong>.
           *
           * @param {Selector} element
           * The target tab(s), specified as a selector, to be disabled.
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           */
          disable: function (element) {
              this._toggleDisabled(element, false);
  
              return this;
          },
  
          /**
           *
           * Reloads TabStrip tab(s) via AJAX.
           *
           * @param {Selector} element
           * The target tab(s), specified as a selector, to be reloaded via AJAX.
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           */
          reload: function (element) {
              element = this.tabGroup.find(element);
              var that = this;
  
              element.each(function () {
                  var item = $(this),
                      contentUrl = item.find("." + LINK).data(CONTENTURL);
  
                  if (contentUrl) {
                      that.ajaxRequest(item, $(that.contentElement(item.index())), null, contentUrl);
                  }
              });
  
              return that;
          },
  
          /**
           *
           * Appends a tab to the collection of tabs in a <strong>TabStrip</strong>.
           *
           * @param {Selector} tab
           * Target tab, specified as a JSON object. You can pass tab text, content or contentUrl here. Can handle an
           * HTML string or array of such strings or JSON.
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           * @example
           * tabStrip.append(
           *     [{
           *         text: "Item 1",
           *         url: "http://www.kendoui.com"               // Link URL if navigation is needed, optional.
           *     },
           *     {
           *         text: "<b>Item 2</b>",
           *         encoded: false,                             // Allows use of HTML for item text
           *         content: "text"                             // Content for the content element
           *     },
           *     {
           *         text: "Item 3",
           *         contentUrl: "partialContent.html"           // From where to load the item content
           *     },
           *     {
           *         text: "Item 4",
           *         imageUrl: "http://www.kendoui.com/test.jpg" // Item image URL, optional.
           *     },
           *     {
           *         text: "Item 5",
           *         spriteCssClass: "imageClass3"               // Item image sprite CSS class, optional.
           *     }]
           * );
           *
           */
          append: function (tab) {
              var that = this,
                  inserted = that._create(tab);
  
              each(inserted.tabs, function (idx) {
                  that.tabGroup.append(this);
                  that.wrapper.append(inserted.contents[idx]);
              });
  
              updateFirstLast(that.tabGroup);
              that._updateContentElements();
  
              return that;
          },
  
          /**
           *
           * Inserts a newly-created tab before a specified tab.
           *
           * @param {Selector} item
           * Target tab, specified as a JSON object. You can pass tab text, content or contentUrl here. Can handle an
           * HTML string or array of such strings or JSON.
           *
           * @param {Item} referenceTab
           * A reference tab to insert the new item before
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           * @example
           * tabStrip.insertBefore(
           *     [{
           *         text: "Item 1",
           *         url: "http://www.kendoui.com"               // Link URL if navigation is needed, optional.
           *     },
           *     {
           *         text: "<b>Item 2</b>",
           *         encoded: false,                             // Allows use of HTML for item text
           *         content: "text"                             // Content for the content element
           *     },
           *     {
           *         text: "Item 3",
           *         contentUrl: "partialContent.html"           // From where to load the item content
           *     },
           *     {
           *         text: "Item 4",
           *         imageUrl: "http://www.kendoui.com/test.jpg" // Item image URL, optional.
           *     },
           *     {
           *         text: "Item 5",
           *         spriteCssClass: "imageClass3"               // Item image sprite CSS class, optional.
           *     }],
           *     referenceItem
           * );
           */
          insertBefore: function (tab, referenceTab) {
              var that = this,
                  inserted = that._create(tab),
                  referenceContent = $(that.contentElement(referenceTab.index()));
  
              each(inserted.tabs, function (idx) {
                  referenceTab.before(this);
                  referenceContent.before(inserted.contents[idx]);
              });
  
              updateFirstLast(that.tabGroup);
              that._updateContentElements();
  
              return that;
          },
  
          /**
           *
           * Inserts a newly-created tab after a specified tab.
           *
           * @param {Selector} item
           * Target tab, specified as a JSON object. You can pass tab text, content or contentUrl here. Can handle an
           * HTML string or array of such strings or JSON.
           *
           * @param {Item} referenceTab
           * A reference tab to insert the new item after.
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           * @example
           * tabStrip.insertAfter(
           *     [{
           *         text: "Item 1",
           *         url: "http://www.kendoui.com"               // Link URL if navigation is needed, optional.
           *     },
           *     {
           *         text: "<b>Item 2</b>",
           *         encoded: false,                             // Allows use of HTML for item text
           *         content: "text"                             // Content for the content element
           *     },
           *     {
           *         text: "Item 3",
           *         contentUrl: "partialContent.html"           // From where to load the item content
           *     },
           *     {
           *         text: "Item 4",
           *         imageUrl: "http://www.kendoui.com/test.jpg" // Item image URL, optional.
           *     },
           *     {
           *         text: "Item 5",
           *         spriteCssClass: "imageClass3"               // Item image sprite CSS class, optional.
           *     }],
           *     referenceItem
           * );
           *
           */
          insertAfter: function (tab, referenceTab) {
              var that = this,
                  inserted = that._create(tab),
                  referenceContent = $(that.contentElement(referenceTab.index()));
  
              each(inserted.tabs, function (idx) {
                  referenceTab.after(this);
                  referenceContent.after(inserted.contents[idx]);
              });
  
              updateFirstLast(that.tabGroup);
              that._updateContentElements();
  
              return that;
          },
  
          /**
           *
           * Removes a specified tab from a TabStrip.
           *
           * @param {Selector} element
           * The target tab(s), specified as a selector, to be removed.
           *
           * @returns {TabStrip}
           * Returns the TabStrip object to support chaining.
           *
           * @exampleTitle Remove a tab with ID, tab1 from a TabStrip
           * @example
           * tabStrip.remove("#tab1");
           *
           */
          remove: function (element) {
              var that = this,
                  type = typeof element,
                  content;
  
              if (type === "string") {
                  element = that.tabGroup.find(element);
              } else if (type === "number") {
                  element = that.tabGroup.children().eq(element);
              }
  
              content = $(that.contentElement(element.index()));
  
              content.remove();
              element.remove();
  
              that._updateContentElements();
  
              return that;
          },
  
          _create: function (tab) {
              var plain = $.isPlainObject(tab),
                  that = this, tabs, contents;
  
              if (plain || $.isArray(tab)) {
                  tab = $.isArray(tab) ? tab : [tab];
  
                  tabs = map(tab, function (value, idx) {
                              return $(TabStrip.renderItem({
                                  group: that.tabGroup,
                                  item: extend(value, { index: idx })
                              }));
                          });
  
                  contents = map( tab, function (value, idx) {
                              if (value.content || value.contentUrl) {
                                  return $(TabStrip.renderContent({
                                      item: extend(value, { index: idx })
                                  }));
                              }
                          });
              } else {
                  tabs = $(tab);
                  contents = $("<div class='" + CONTENT + "'/>");
  
                  updateTabClasses(tabs);
              }
  
              return { tabs: tabs, contents: contents };
          },
  
          _toggleDisabled: function(element, enable) {
              element = this.tabGroup.find(element);
              element.each(function () {
                  $(this)
                      .toggleClass(DEFAULTSTATE, enable)
                      .toggleClass(DISABLEDSTATE, !enable);
              });
          },
  
          _updateClasses: function() {
              var that = this,
                  tabs, activeItem, activeTab;
  
              that.wrapper.addClass("k-widget k-header k-tabstrip");
  
              that.tabGroup = that.wrapper.children("ul").addClass("k-tabstrip-items k-reset");
  
              if (!that.tabGroup[0]) {
                  that.tabGroup = $("<ul class='k-tabstrip-items k-reset'/>").appendTo(that.wrapper);
              }
  
              tabs = that.tabGroup.find("li").addClass("k-item");
  
              if (tabs.length) {
                  activeItem = tabs.filter("." + ACTIVESTATE).index();
                  activeTab = activeItem >= 0 ? activeItem : undefined;
  
                  that.tabGroup // Remove empty text nodes
                      .contents()
                      .filter(function () { return (this.nodeType == 3 && !trim(this.nodeValue)); })
                      .remove();
              }
  
              tabs.eq(activeItem).addClass(TABONTOP);
  
              that.contentElements = that.wrapper.children("div");
  
              that.contentElements
                  .addClass(CONTENT)
                  .eq(activeTab)
                  .addClass(ACTIVESTATE)
                  .css({ display: "block" });
  
              if (tabs.length) {
                  updateTabClasses(tabs);
  
                  updateFirstLast(that.tabGroup);
                  that._updateContentElements();
              }
          },
  
          _updateContentElements: function() {
              var that = this,
                  contentUrls = that.options.contentUrls || [],
                  tabStripID = that.element.attr("id"),
                  contentElements = that.wrapper.children("div");
  
              that.tabGroup.find(".k-item").each(function(idx) {
                  var currentContent = contentElements.eq(idx),
                      id = tabStripID + "-" + (idx+1);
  
                  if (!currentContent.length && contentUrls[idx]) {
                      $("<div id='"+ id +"' class='" + CONTENT + "'/>").appendTo(that.wrapper);
                  } else {
                      currentContent.attr("id", id);
                  }
              });
  
              that.contentElements = that.contentAnimators = that.wrapper.children("div"); // refresh the contents
  
              if (kendo.support.touch && kendo.mobile.ui.Scroller) {
                  kendo.touchScroller(that.contentElements);
                  that.contentElements = that.contentElements.children(".km-scroll-container");
              }
          },
  
          _toggleHover: function(e) {
              $(e.currentTarget).toggleClass(HOVERSTATE, e.type == MOUSEENTER);
          },
  
          _click: function (e) {
              var that = this,
                  item = $(e.currentTarget),
                  link = item.find("." + LINK),
                  href = link.attr(HREF),
                  collapse = that.options.collapsible,
                  content = $(that.contentElement(item.index()));
  
              if (item.closest(".k-widget")[0] != that.wrapper[0]) {
                  return;
              }
  
              if (item.is("." + DISABLEDSTATE + (!collapse ? ",." + ACTIVESTATE : ""))) {
                  e.preventDefault();
                  return;
              }
  
              if (that.tabGroup.children("[data-animating], [data-in-request]").length) {
                  return;
              }
  
              if (that.trigger(SELECT, { item: item[0], contentElement: content[0] })) {
                  e.preventDefault();
              } else {
                  var isAnchor = link.data(CONTENTURL) || (href && (href.charAt(href.length - 1) == "#" || href.indexOf("#" + that.element[0].id + "-") != -1));
  
                  if (!href || isAnchor) {
                      e.preventDefault();
                  } else {
                      return;
                  }
  
                  if (collapse && item.is("." + ACTIVESTATE)) {
                      that.deactivateTab(item);
                      e.preventDefault();
  
                      return;
                  }
  
                  if (that.activateTab(item)) {
                      e.preventDefault();
                  }
              }
          },
  
          /**
           *
           * Deactivates a tab specified as a selector. Note: Invoking this method will not trigger any events.
           *
           * @param {Selector} item
           * The target tab, specified as a selector, to be deactivated.
           *
           * @example
           * var tabToDeactivate = $("#tab1");
           * $("#tabStrip").data("kendoTabStrip").deactivateTab(tabToActivate);
           *
           */
          deactivateTab: function (item) {
              var that = this,
                  animationSettings = that.options.animation,
                  animation = animationSettings.open,
                  close = extend({}, animationSettings.close),
                  hasCloseAnimation = close && "effects" in close;
              item = that.tabGroup.find(item);
  
              close = extend( hasCloseAnimation ? close : extend({ reverse: true }, animation), { show: false, hide: true });
  
              if (kendo.size(animation.effects)) {
                  item.kendoAddClass(DEFAULTSTATE, { duration: animation.duration });
                  item.kendoRemoveClass(ACTIVESTATE, { duration: animation.duration });
              } else {
                  item.addClass(DEFAULTSTATE);
                  item.removeClass(ACTIVESTATE);
              }
  
              that.contentAnimators
                      .filter("." + ACTIVESTATE)
                      .kendoStop(true, true)
                      .kendoAnimate( close )
                      .removeClass(ACTIVESTATE);
          },
  
          /**
           *
           * Activates a tab specified as a selector. Note: Invoking this method will not trigger any events.
           *
           * @param {Selector} item
           * The target tab, specified as a selector, to be activated.
           *
           * @returns {Boolean}
           * Returns <strong>true</strong> if successful; otherwise, <strong>false</strong>.
           *
           * @exampleTitle Activate a tab with ID, tab1 in a TabStrip
           * @example
           * var tabToActivate = $("#tab1");
           * $("#tabStrip").data("kendoTabStrip").activateTab(tabToActivate);
           *
           */
          activateTab: function (item) {
              item = this.tabGroup.find(item);
  
              var that = this,
                  animationSettings = that.options.animation,
                  animation = animationSettings.open,
                  close = extend({}, animationSettings.close),
                  hasCloseAnimation = close && "effects" in close,
                  neighbours = item.parent().children(),
                  oldTab = neighbours.filter("." + ACTIVESTATE),
                  itemIndex = neighbours.index(item);
  
              close = extend( hasCloseAnimation ? close : extend({ reverse: true }, animation), { show: false, hide: true });
              // deactivate previously active tab
              if (kendo.size(animation.effects)) {
                  oldTab.kendoRemoveClass(ACTIVESTATE, { duration: close.duration });
                  item.kendoRemoveClass(HOVERSTATE, { duration: close.duration });
              } else {
                  oldTab.removeClass(ACTIVESTATE);
                  item.removeClass(HOVERSTATE);
              }
  
              // handle content elements
              var contentAnimators = that.contentAnimators;
  
              if (contentAnimators.length === 0) {
                  oldTab.removeClass(TABONTOP);
                  item.addClass(TABONTOP) // change these directly to bring the tab on top.
                      .css("z-index");
  
                  item.addClass(ACTIVESTATE);
  
                  that.trigger("change");
  
                  return false;
              }
  
              var visibleContents = contentAnimators.filter("." + ACTIVESTATE);
  
              // find associated content element
              var content = $(that.contentElement(itemIndex));
  
              if (content.length === 0) {
                  visibleContents
                      .removeClass( ACTIVESTATE )
                      .kendoStop(true, true)
                      .kendoAnimate( close );
                  return false;
              }
  
              item.attr("data-animating", true);
  
              var isAjaxContent = (item.children("." + LINK).data(CONTENTURL) || false) && content.is(EMPTY),
                  showContentElement = function () {
                      oldTab.removeClass(TABONTOP);
                      item.addClass(TABONTOP) // change these directly to bring the tab on top.
                          .css("z-index");
  
                      if (kendo.size(animation.effects)) {
                          oldTab.kendoAddClass(DEFAULTSTATE, { duration: animation.duration });
                          item.kendoAddClass(ACTIVESTATE, { duration: animation.duration });
                      } else {
                          oldTab.addClass(DEFAULTSTATE);
                          item.addClass(ACTIVESTATE);
                      }
  
                      content
                          .closest(".k-content")
                          .addClass(ACTIVESTATE)
                          .kendoStop(true, true)
                          .kendoAnimate( extend({ init: function () {
                              that.trigger(ACTIVATE, { item: item[0], contentElement: content[0] });
                          } }, animation, { complete: function () {
                                                          item.removeAttr("data-animating");
                                                      } } ) );
                  },
                  showContent = function() {
                      if (!isAjaxContent) {
                          showContentElement();
                          that.trigger("change");
                      } else {
                          that.ajaxRequest(item, content, function () {
                              showContentElement();
                              that.trigger("change");
                          });
                      }
                  };
  
              visibleContents
                      .removeClass(ACTIVESTATE);
  
              if (visibleContents.length) {
                  visibleContents
                      .kendoStop(true, true)
                      .kendoAnimate(extend( {
                          complete: showContent
                     }, close ));
              } else {
                  showContent();
              }
  
              return true;
          },
  
          /**
           *
           * Obtains the DOM element representing a tab by its index in the <strong>TabStrip</strong>.
           *
           * @param {int} itemIndex
           * The index of the tab in the TabStrip.
           *
           * @returns {HTMLElement}
           * The DOM element representing a tab by its index in the <strong>TabStrip</strong>.
           *
           * @exampleTitle Obtain the DOM element representing the first tab in a TabStrip
           * @example
           * var tabContent = $("#tabStrip").data("kendoTabStrip").contentElement(0);
           *
           */
          contentElement: function (itemIndex) {
              if (isNaN(itemIndex - 0)) {
                  return;
              }
  
              var contentElements = this.contentElements,
                  idTest = new RegExp("-" + (itemIndex + 1) + "$");
  
              for (var i = 0, len = contentElements.length; i < len; i++) {
                  if (idTest.test(contentElements.closest(".k-content")[i].id)) {
                      return contentElements[i];
                  }
              }
          },
  
          ajaxRequest: function (element, content, complete, url) {
              element = this.tabGroup.find(element);
              if (element.find(".k-loading").length) {
                  return;
              }
  
              var that = this,
                  link = element.find("." + LINK),
                  data = {},
                  statusIcon = null,
                  loadingIconTimeout = setTimeout(function () {
                      statusIcon = $("<span class='k-icon k-loading'/>").prependTo(link);
                  }, 100);
  
              element.attr("data-in-request", true);
  
              $.ajax({
                  type: "GET",
                  cache: false,
                  url: url || link.data(CONTENTURL) || link.attr(HREF),
                  dataType: "html",
                  data: data,
  
                  error: function (xhr, status) {
                      element.removeAttr("data-animating");
                      if (that.trigger("error", { xhr: xhr, status: status })) {
                          this.complete();
                      }
                  },
  
                  complete: function () {
                      element.removeAttr("data-in-request");
  
                      clearTimeout(loadingIconTimeout);
                      if (statusIcon !== null) {
                          statusIcon.remove();
                      }
                  },
  
                  success: function (data, textStatus) {
                      content.html(data);
  
                      if (complete) {
                          complete.call(that, content);
                      }
  
                      that.trigger(CONTENTLOAD, { item: element[0], contentElement: content[0] });
                  }
              });
          }
      });
  
      // client-side rendering
      extend(TabStrip, {
          renderItem: function (options) {
              options = extend({ tabStrip: {}, group: {} }, options);
  
              var empty = templates.empty,
                  item = options.item;
  
              return templates.item(extend(options, {
                  image: item.imageUrl ? templates.image : empty,
                  sprite: item.spriteCssClass ? templates.sprite : empty,
                  itemWrapper: templates.itemWrapper
              }, rendering));
          },
  
          renderContent: function (options) {
              return templates.content(extend(options, rendering));
          }
      });
  
      kendo.ui.plugin(TabStrip);
  
  })(jQuery);
  ;