Source: components/list/list.js


/**
 * Class representing a single list component.
 * @namespace MobileAge.Component.List
 * @class
 * @name MobileAge.Component.List
 * @extends MobileAge.Component
 * @classdesc List-Component
 * @param {string} dom Id, css-query or a ElementNode to connect to.
* @param {Object} options
* @param {String} [options.templateListWrapper=<ul><%%></ul>] HTML template used for the list element. The template must include the anonym placeholder "<%%>", which will be filled with the resulted list items.
* @param {String} [options.templateListItemWrapper=<li><%%></li>] HTML template used for every single list item. The template must include placeholders, which will be filled with the requested data. If the response data is an one-dimensional array, the template must use the anonym placeholder "<%%>". If the response data is an associative array, the template must used named placeholder like "<%name%>", where "name" is the index of the response array.
* @param {String} [options.templateListItem=""] HTML template used for every single item inside the templateListItemWrapper. The template must include placeholders, which will be filled with the requested data. If the response data is an one-dimensional array, the template must used the anonym placeholder "<%%>". If the response data is an associative array, the template must used named placeholder like "<%name%>", where "name" is the index of the response array.
* @param {Boolean} [options.autorequest=true] Indicates if the first request should be sended during the initialisation of the list.
* @param {String} [options.dataLimit=""] Limits the printed list items to the stated amount
* @param {Boolean} [options.clientFiltering=false] Indicates if the first results should be filtered after they are recieved and before they are printed.
* @param {Boolean} [options.clear=false] Specifies, wether the content of the dom element is deleted before adding the list.
* @param {function} [options.onTemplateListItem=""] Callback-function called every time before list item will be printed. The functions parameter "data" contains the data assosiated with the item. The callback-funktion should return a template string.
* @param {function} [options.onDataItem=""] Callback-function called every time when the data for a list item should be prepared. The functions parameter "data" contains the data assosiated with the actual item. The callback-funktion should return a associative array representing the item's data. (default: null)
* @param {function} [options.onSelect=""] Callback-function called, when a list item is selected by touch, mouse-click or keyboard selection.
 */

(function() {
  var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    hasProp = {}.hasOwnProperty;

  MobileAge.Component.List = (function(superClass) {
    extend(List, superClass);

    function List(element, options) {
      var defaultOptions;
      this._data = null;
      this._listdata = null;
      this._listout = null;
      this._listin = null;
      defaultOptions = {
        templateListWrapper: "<ul><%%></ul>",
        templateListItemWrapper: "<li><%%></li>",
        templateListItem: "",
        autorequest: true,
        dataLimit: 0,
        clientFiltering: false,
        clear: true,
        onTemplateListItem: null,
        onDataItem: null,
        onSelect: null
      };
      List.__super__.constructor.call(this, element, this._assignOptions(defaultOptions, options));
      this._create();
    }


    /**
     * Creates a List-Component
     * @memberOf MobileAge.Component.List
     * @function _create
     */

    List.prototype._create = function() {
      if (this._isAttached()) {
        if (this._isSingle()) {
          if (this._options.clear) {
            this.removeAllChildren(this._domElement);
          }
          if (this._options.bem) {
            this.bemify(this._domElement, this._options.bemBlock, this._options.bemElement, this._options.bemModifier);
          }
          if (this._options.data) {
            this._data = this._options.data;
            return this._onRequestData(this._data);
          } else {
            if (this._options.autorequest) {
              return this.queryData();
            }
          }
        } else if (this._isList()) {
          return console.log("Error: MobileAge.Component.List only available for single DOM-Elements, yet");
        }
      }
    };

    List.prototype.setData = function(data) {
      return this._data = data;
    };


    /**
     *
     */

    List.prototype.filterData = function(query) {
      if (this._data && this._data.length > 0) {
        this.removeItems();
        this._listdata = this._data.filter(function(el) {
          return el.toLowerCase().indexOf(query.toLowerCase()) !== -1;
        });
        if (typeof this._options.onData === 'function') {
          this._options.onData(this._listdata);
        }
        if (this._listdata.length > 0) {
          return this._addItems(this._listdata, this._domElement);
        } else {
          return this._createNoData();
        }
      }
    };


    /**
     *
     */

    List.prototype.addQuery = function(param, query) {
      return this._options.xhrQuery[param] = query;
    };


    /**
     * Replaces the list data with given data
     * @memberof MobileAge.Component.List
     * @function replaceData
     * @param {String | array} data
     */

    List.prototype.removeItems = function() {
      return this.removeAllChildren(this._domElement);
    };


    /**
     * Callback function called when requested data is received
     * @memberof MobileAge.Component.List
     * @function _onRequestData
     * @param {object} data - requested data
     */

    List.prototype._onRequestData = function(data) {
      if (data !== void 0) {
        this._parseData(data);
        this._assignTemplate();
      }
    };


    /**
     * creates a okay-message on the page
     * @memberof MobileAge.Component.List
     * @function _createOkay
     */

    List.prototype._createNoData = function() {

      /*
      hdone = document.createElement "div"
      hdone.setAttribute "class", "ma-alert ma-alert--error"
      hdone.setAttribute "role", "alert">
      hdone.appendChild document.createTextNode "No data"
      if @_options.bem
        @bemify hdone, @_options.bemBlock, "nodata", ""
      
      @_domElement.appendChild hdone
      #@_domElement.parentNode.replaceChild(hdone, @_domElement);
       */
    };


    /**
     * Creates a List element with all received options
     * @memberof MobileAge.Component.List
     * @function _createList
     * @param {array} items - array of List-options
     */

    List.prototype._createElement = function(list) {
      var temp;
      if (this._options.templateListWrapper) {
        if (this._options.templateListWrapper === "<%%>") {
          this._addItems(list, this._domElement);
          return;
        } else {
          this._listout = this.html2DomElement(this.template(this._options.templateListWrapper, "<span id='mobile-age-id'>"));
          temp = this._listout.querySelector('#mobile-age-id');
          if (temp) {
            this._listin = temp.parentNode;
            this._listin.removeChild(temp);
          } else {
            this._listout = this.html2DomElement(this.template(this._options.templateListWrapper, "<tr id='mobile-age-id'>"));
            temp = this._listout.querySelector('#mobile-age-id');
            if (temp) {
              this._listin = temp.parentNode;
            } else {
              this._listin = this._listout;
            }
          }
          temp = this._listin.querySelectorAll('tbody');
          if (temp.length > 0) {
            this._listin = temp[0];
          }
        }
      } else {
        this._listin = document.createElement("ul");
        this._listout = this._listin;
      }
      this._addItems(list, this._listin);
      return this._domElement.appendChild(this._listout);

      /*
      @_ul = document.createElement "ul"
      
      if @_options.wrapperList
        wrapper = @html2DomElement(@_options.wrapperList)
        wrapper.appendChild @_ul
        @_domElement.appendChild wrapper
      else
        @_domElement.appendChild @_ul
       */
    };


    /**
     * Creates a List element with all received options
     * @memberof MobileAge.Component.List
     * @function _addItems
     * @param {array} items - array of List-options
     */

    List.prototype._addItems = function(items, domElement) {
      var documentFragment, i, item, len;
      if (this._options.dataLimit) {
        items = items.slice(0, this._options.dataLimit);
      }
      documentFragment = document.createDocumentFragment();
      for (i = 0, len = items.length; i < len; i++) {
        item = items[i];
        documentFragment.appendChild(this._createItem(item));
      }
      return domElement.appendChild(documentFragment);
    };


    /**
     * Creates and returns an list element with text
     * @memberof MobileAge.Component.List
     * @function _createItem
     * @param {array} item - array of item.text and item.id
     * @returns {node} created DOM-Element
     */

    List.prototype._createItem = function(item) {
      var _li, listItem, tmp;
      if (typeof this._options.onDataItem === 'function') {
        this._options.onDataItem(item);
      }
      if (typeof this._options.onTemplateListItem === 'function') {
        tmp = this._options.onTemplateListItem(item);
        _li = this.html2DomElement(this.template(tmp, item));
      } else {
        listItem = this.template(this._options.templateListItem, item);
        _li = this.html2DomElement(this.template(this._options.templateListItemWrapper, listItem));
      }
      if (typeof this._options.onSelect === 'function') {
        _li.addEventListener('click', this._options.onSelect, true);
        _li.addEventListener('keyup', this._onKeyPress.bind(this), true);
      }
      return _li;

      /*
      _li = document.createElement( "li" )
      _li.setAttribute("tabindex", 0)
      _li.setAttribute("role", "button")
      _li.setAttribute("data-value", item)
      
       * if item is wrapped by an object
      if typeof item == 'object'
        for key of item
          `key = key`
          if typeof key != 'undefined' && typeof item[key] == 'object'
            item = item[key]
      
       * apply template <%value3%>
      #if @_options.template
       *  item = @template @_options.template, item
      #_li.innerHTML = item
      
       * attach eventListener
      if typeof @_options.onSelect == 'function'
        _li.addEventListener 'click', @_options.onSelect, true
        #_li.addEventListener 'keyup', @_onKeyPress.bind(this), true ##TODO: Hier!
      
      return _li
       */
    };

    List.prototype._onKeyPress = function(e) {
      if (e.keyCode === 13 || e.keyCode === 32) {
        this._options.onSelect(e);
        return false;
      }
    };


    /* */


    /* */


    /*  
    
     * Creates a List element with all received options
     * @memberof MobileAge.Component.List
     * @function _createList
     * @param {array} items - array of List-options
    
    getList: () ->
      @_ul
    
     * Appends given data to an existing list
     * @memberof MobileAge.Component.List
     * @function appendData
     * @param {String | array} data
    
    appendData: (data) ->
      @_parseData(data)
      if @_data.length > 0
        #@_createLabel(data[1])
        @_addItems(@_data)
    
     * Replaces the list data with given data
     * @memberof MobileAge.Component.List
     * @function replaceData
     * @param {String | array} data
    replaceData: (data) ->
      @_parseData(data)
      @removeAllChildren @_ul
      if @_data.length > 0
        @_addItems(@_data)
    
     * Returns list data
     * @memberof MobileAge.Component.List
     * @function getData
     * @returns {array} data
    getData: () ->
      @_data
    
     * Returns child at given index
     * @memberof MobileAge.Component.List
     * @function getData
     * @param {Number} index
     * @returns {array} data
    getChildAt: (index) ->
      @_ul.children[index]
     */

    return List;

  })(MobileAge.Component);

}).call(this);