text: /**
   * Elements in a tree structure
   * @module Ink.UI.TreeView_1
   * @version 1
   */
  Ink.createModule('Ink.UI.TreeView', '1', ['Ink.UI.Common_1','Ink.Dom.Event_1','Ink.Dom.Css_1','Ink.Dom.Element_1','Ink.Dom.Selector_1','Ink.Util.Array_1'], function(Common, Event, Css, Element, Selector, InkArray ) {
      'use strict';
  
  
      /**
       * Shows elements in a tree structure which can be expanded and contracted.
       * A TreeView is built with "node"s and "children". "node"s are `li` tags, and "children" are `ul` tags.
       * You can build your TreeView out of a regular UL and  LI element structure which you already use to display lists with several levels.
       * If you want a node to be open when the TreeView is built, just add the data-open="true" attribute to it.
       * 
       * @class Ink.UI.TreeView
       * @constructor
       * @version 1
       * @param {String|DOMElement}   selector                    Element or selector.
       * @param {String}              [options]                   Options object, containing:
       * @param {String}              [options.node]              Selector for the nodes. Defaults to 'li'.
       * @param {String}              [options.children]          Selector for the children. Defaults to 'ul'.
       * @param {String}              [options.parentClass]       CSS classes to be added to parent nodes. Defaults to 'parent'.
       * @param {String}              [options.openClass]         CSS classes to be added to the icon when a parent is open. Defaults to 'fa fa-minus-circle'.
       * @param {String}              [options.closedClass]       CSS classes to be added to the icon when a parent is closed. Defaults to 'fa fa-plus-circle'.
       * @param {String}              [options.hideClass]         CSS Class to toggle visibility of the children. Defaults to 'hide-all'.
       * @param {String}              [options.iconTag]           The name of icon tag. The component tries to find a tag with that name as a direct child of the node. If it doesn't find it, it creates it. Defaults to 'i'.
       * @param {Boolean}             [options.stopDefault]       Flag to stops the default behavior of the click handler. Defaults to true.
       * @example
       *      <ul class="ink-tree-view">
       *        <li data-open="true"><a href="#">root</a>
       *          <ul>
       *            <li><a href="#">child 1</a></li>
       *            <li><a href="#">child 2</a>
       *              <ul>
       *                <li><a href="#">grandchild 2a</a></li>
       *                <li><a href="#">grandchild 2b</a>
       *                  <ul>
       *                    <li><a href="#">grandgrandchild 1bA</a></li>
       *                    <li><a href="#">grandgrandchild 1bB</a></li>
       *                  </ul>
       *                </li>
       *              </ul>
       *            </li>
       *            <li><a href="#">child 3</a></li>
       *          </ul>
       *        </li>
       *      </ul>
       *      <script>
       *          Ink.requireModules( ['Ink.Dom.Selector_1','Ink.UI.TreeView_1'], function( Selector, TreeView ){
       *              var treeViewElement = Ink.s('.ink-tree-view');
       *              var treeViewObj = new TreeView( treeViewElement );
       *          });
       *      </script>
       * 
       * @sample Ink_UI_TreeView_1.html
       */
      function TreeView() {
          Common.BaseUIComponent.apply(this, arguments);
      }
  
      TreeView._name = 'TreeView_1';
  
      TreeView._optionDefinition = {
          'node':   ['String', 'li'],
          'children':  ['String','ul'],
          'parentClass': ['String','parent'],
          'openNodeClass': ['String', 'open'],
          'openClass': ['String','fa fa-minus-circle'],
          'closedClass': ['String','fa fa-plus-circle'],
          'hideClass': ['String','hide-all'],
          'iconTag': ['String', 'i'],
          'stopDefault' : ['Boolean', true]
      };
  
      TreeView.prototype = {
          /**
           * Init function called by the constructor. Sets the necessary event handlers.
           * 
           * @method _init
           * @private
           */
          _init: function(){
              this._handlers = {
                  click: Ink.bindEvent(this._onClick,this)
              };
  
              Event.on(this._element, 'click', this._options.node, this._handlers.click);
  
              InkArray.each(Ink.ss(this._options.node, this._element), Ink.bind(function(item){
                  if( this.isParent(item) ) {
                      Css.addClassName(item, this._options.parentClass);
  
                      var isOpen = this.isOpen(item);
                      if( !this._getIcon(item) ){
                          Element.create(this._options.iconTag, { insertTop: item });
                      }
  
                      this._setNodeOpen(item, isOpen);
                  }
              },this));
          },
  
          _getIcon: function (node) {
              return Ink.s('> ' + this._options.iconTag, node);
          },
  
          /**
           * Checks if a node is open.
           *
           * @method isOpen
           * @param {DOMElement} node  The tree node to check
           **/
          isOpen: function (node) {
              if (!this._getChild(node)) {
                  throw new Error('not a node!');
              }
  
              return Element.data(node).open === 'true' ||
                  Css.hasClassName(node, this._options.openNodeClass);
          },
  
          /**
           * Checks if a node is a parent.
           *
           * @method isParent
           * @param {DOMElement} node     Node to check
           **/
          isParent: function (node) {
              return Css.hasClassName(node, this._options.parentClass) ||
                  this._getChild(node) != null;
          },
  
          _setNodeOpen: function (node, beOpen) {
              var child = this._getChild(node);
              if (child) {
                  Css.setClassName(child, this._options.hideClass, !beOpen);
                  var icon = this._getIcon(node);
  
                  node.setAttribute('data-open', beOpen);
  
                  /*
                   * Don't refactor this to
                   *
                   * setClassName(el, className, status); setClassName(el, className, !status);
                   *
                   * because it won't work with multiple classes.
                   *
                   * Doing:
                   * setClassName(el, 'fa fa-whatever', true);setClassName(el, 'fa fa-whatever-else', false);
                   *
                   * will remove 'fa' although it is a class we want.
                   */
  
                  var toAdd = beOpen ? this._options.openClass : this._options.closedClass;
                  var toRemove = beOpen ? this._options.closedClass : this._options.openClass;
                  Css.removeClassName(icon, toRemove);
                  Css.addClassName(icon, toAdd);
  
                  Css.setClassName(node, this._options.openNodeClass, beOpen);
              } else {
                  Ink.error('Ink.UI.TreeView: node', node, 'is not a node!');
              }
          },
  
          /**
           * Opens one of the tree nodes
           *
           * Make sure you pass the node's DOMElement
           * @method open
           * @param {DOMElement} node     The node you wish to open.
           **/
          open: function (node) {
              this._setNodeOpen(node, true);
          },
  
          /**
           * Closes one of the tree nodes
           *
           * Make sure you pass the node's DOMElement
           * @method close
           * @param {DOMElement} node     The node you wish to close.
           **/
          close: function (node) {
              this._setNodeOpen(node, false);
          },
  
          /**
           * Toggles a node state
           *
           * @method toggle
           * @param {DOMElement} node     The node to toggle.
           **/
          toggle: function (node) {
              if (this.isOpen(node)) {
                  this.close(node);
              } else {
                  this.open(node);
              }
          },
  
          _getChild: function (node) {
              return Selector.select(this._options.children, node)[0] || null;
          },
  
          /**
           * Handles the click event (as specified in the _init function).
           * 
           * @method _onClick
           * @param {Event} event
           * @private
           */
          _onClick: function(ev){
              /**
               * Summary:
               * If the clicked element is a "node" as defined in the options, will check if it has any "child".
               * If so, will toggle its state and stop the event's default behavior if the stopDefault option is true.
               **/
  
              if (!this.isParent(ev.currentTarget) ||
                      Selector.matchesSelector(ev.target, this._options.node) ||
                      Selector.matchesSelector(ev.target, this._options.children)) {
                  return;
              }
  
              if (this._options.stopDefault){
                  ev.preventDefault();
              }
  
              this.toggle(ev.currentTarget);
          }
      };
  
      Common.createUIComponent(TreeView);
  
      return TreeView;
  });
  