JAVASCRIPT   13

lists.js

Guest on 18th July 2021 05:07:42 PM

  1. /*
  2. ListJS Beta 0.2.0
  3. By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
  4.  
  5. OBS. The API is not frozen. It MAY change!
  6.  
  7. License (MIT)
  8.  
  9. Copyright (c) 2011 Jonny Strömberg http://jonnystromberg.com
  10.  
  11. Permission is hereby granted, free of charge, to any person
  12. obtaining a copy of this software and associated documentation
  13. files (the "Software"), to deal in the Software without restriction,
  14. including without limitation the rights to use, copy, modify, merge,
  15. publish, distribute, sublicense, and/or sell copies of the Software,
  16. and to permit persons to whom the Software is furnished to do so,
  17. subject to the following conditions:
  18.  
  19. The above copyright notice and this permission notice shall be
  20. included in all copies or substantial portions of the Software.
  21.  
  22. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  24. OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  26. HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  27. WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  28. FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  29. OTHER DEALINGS IN THE SOFTWARE.
  30. */.
  31. */
  32. (function( window, undefined ) {
  33. "use strict";
  34. var document = window.document,
  35.     h;
  36.  
  37. var List = function(id, options, values) {
  38.     var self = this,
  39.         templater,
  40.         init,
  41.         initialItems,
  42.         Item,
  43.         Templater,
  44.         sortButtons,
  45.         events = {
  46.             'updated': []
  47.         };
  48.     this.listContainer = (typeof(id) == 'string') ? document.getElementById(id) : id;
  49. // Check if the container exists. If not return instead of breaking the javascript
  50. ipt
  51.     if (!this.listContainer)
  52.         return;
  53.  
  54.     this.items = [];
  55.     this.visibleItems = // These are the items currently visible
  56. ble
  57.     this.matchingItems = // These are the items currently matching filters and search, regadlessof visible count
  58. unt
  59.     this.searched = false;
  60.     this.filtered = false;
  61.  
  62.     this.list = null;
  63.     this.templateEngines = {};
  64.  
  65.     this.page = options.page || 200;
  66.     this.i = options.i || 1;
  67.  
  68.     init = {
  69.         start: function(values, options) {
  70.             options.plugins = options.plugins || {};
  71.             this.classes(options);
  72.             templater = new Templater(self, options);
  73.             this.callbacks(options);
  74.             this.items.start(values, options);
  75.             self.update();
  76.             this.plugins(options.plugins);
  77.         },
  78.         classes: function(options) {
  79.             options.listClass = options.listClass || 'list';
  80.             options.searchClass = options.searchClass || 'search';
  81.             options.sortClass = options.sortClass || 'sort';
  82.         },
  83.         callbacks: function(options) {
  84.             self.list = h.getByClass(options.listClass, self.listContainer, true);
  85.             h.addEvent(h.getByClass(options.searchClass, self.listContainer), 'keyup', self.search);
  86.             sortButtons = h.getByClass(options.sortClass, self.listContainer);
  87.             h.addEvent(sortButtons, 'click', self.sort);
  88.         },
  89.         items: {
  90.             start: function(values, options) {
  91.                 if (options.valueNames) {
  92.                     var itemsToIndex = this.get(),
  93.                     valueNames = options.valueNames;
  94.                     if (options.indexAsync) {
  95.                         this.indexAsync(itemsToIndex, valueNames);
  96.                     } else {
  97.                         this.index(itemsToIndex, valueNames);
  98.                     }
  99.                 }
  100.                 if (values !== undefined) {
  101.                     self.add(values);
  102.                 }
  103.             },
  104.             get: function() {
  105.             // return h.getByClass('item', self.list);
  106. t);
  107.                 var nodes = self.list.childNodes,
  108.                 items = [];
  109.                 for (var i = 0, il = nodes.length; i < il; i++) {
  110.                 // Only textnodes have a data attribute
  111. ute
  112.                     if (nodes[i].data === undefined) {
  113.                         items.push(nodes[i]);
  114.                     }
  115.                 }
  116.                 return items;
  117.             },
  118.             index: function(itemElements, valueNames) {
  119.                 for (var i = 0, il = itemElements.length; i < il; i++) {
  120.                     self.items.push(new Item(valueNames, itemElements[i]));
  121.                 }
  122.             },
  123.             indexAsync: function(itemElements, valueNames) {
  124.                 var itemsToIndex = itemElements.splice(0, 10// TODO: If < 100 items, what happens in IE etc?
  125. tc?
  126.                 this.index(itemsToIndex, valueNames);
  127.                 if (itemElements.length > 0) {
  128.                     setTimeout(function() {
  129.                         init.items.indexAsync(itemElements, valueNames);
  130.                         },
  131.                     10);
  132.                 } else {
  133.                     self.update();
  134.                 // TODO: Add indexed callback
  135. ack
  136.                 }
  137.             }
  138.         },
  139.         plugins: function(plugins) {
  140.             var locals = {
  141.                 templater: templater,
  142.                 init: init,
  143.                 initialItems: initialItems,
  144.                 Item: Item,
  145.                 Templater: Templater,
  146.                 sortButtons: sortButtons,
  147.                 events: events,
  148.                 reset: reset
  149.             };
  150.             for (var i = 0; i < plugins.length; i++) {
  151.                 plugins[i][1] = plugins[i][1] || {};
  152.                 var pluginName = plugins[i][1].name || plugins[i][0];
  153.                 self[pluginName] = self.plugins[plugins[i][0]].call(self, locals, plugins[i][1]);
  154.             }
  155.         }
  156.     };
  157.  
  158.  
  159. /*
  160.     * Add object to list
  161.     */  */
  162.     this.add = function(values, callback) {
  163.         if (callback) {
  164.             addAsync(values, callback);
  165.         }
  166.         var added = [],
  167.             notCreate = false;
  168.         if (values[0] === undefined){
  169.             values = [values];
  170.         }
  171.         for (var i = 0, il = values.length; i < il; i++) {
  172.             var item = null;
  173.             if (values[i] instanceof Item) {
  174.                 item = values[i];
  175.                 item.reload();
  176.             } else {
  177.                 notCreate = (self.items.length > self.page) ? true : false;
  178.                 item = new Item(values[i], undefined, notCreate);
  179.             }
  180.             self.items.push(item);
  181.             added.push(item);
  182.         }
  183.         self.update();
  184.         return added;
  185.     };
  186.  
  187. /*
  188.     * Adds items asynchronous to the list, good for adding huge amount of
  189.     * data. Defaults to add 100 items a time
  190.     */  */
  191.     var addAsync = function(values, callback, items) {
  192.         var valuesToAdd = values.splice(0, 100);
  193.         items = items || [];
  194.         items = items.concat(self.add(valuesToAdd));
  195.         if (values.length > 0) {
  196.             setTimeout(function() {
  197.                 addAsync(values, callback, items);
  198.             }, 10);
  199.         } else {
  200.             self.update();
  201.             callback(items);
  202.         }
  203.     };
  204.  
  205.     this.show = function(i, page) {
  206.         this.i = i;
  207.         this.page = page;
  208.         self.update();
  209.     };
  210.  
  211. /* Removes object from list.
  212.     * Loops through the list and removes objects where
  213.     * property "valuename" === value
  214.     */  */
  215.     this.remove = function(valueName, value, options) {
  216.         var found = 0;
  217.         for (var i = 0, il = self.items.length; i < il; i++) {
  218.             if (self.items[i].values()[valueName] == value) {
  219.                 templater.remove(self.items[i], options);
  220.                 self.items.splice(i,1);
  221.                 il--;
  222.                 found++;
  223.             }
  224.         }
  225.         self.update();
  226.         return found;
  227.     };
  228.  
  229. /* Gets the objects in the list which
  230.     * property "valueName" === value
  231.     */  */
  232.     this.get = function(valueName, value) {
  233.         var matchedItems = [];
  234.         for (var i = 0, il = self.items.length; i < il; i++) {
  235.             var item = self.items[i];
  236.             if (item.values()[valueName] == value) {
  237.                 matchedItems.push(item);
  238.             }
  239.         }
  240.         if (matchedItems.length == 0) {
  241.             return null;
  242.         } else if (matchedItems.length == 1) {
  243.             return matchedItems[0];
  244.         } else {
  245.             return matchedItems;
  246.         }
  247.     };
  248.  
  249. /* Sorts the list.
  250.     * @valueOrEvent Either a JavaScript event object or a valueName
  251.     * @sortFunction (optional) Define if natural sorting does not fullfill your needs
  252.     */  */
  253.     this.sort = function(valueName, options) {
  254.         var length = self.items.length,
  255.             value = null,
  256.             target = valueName.target || valueName.srcEleme/* IE have srcElement */t */
  257.             sorting = '',
  258.             isAsc = false,
  259.             asc = ',
  260.            desc = ' = 'desc',
  261.             options = options || {};
  262.  
  263.         if (target === undefined) {
  264.             value = valueName;
  265.             isAsc = options.asc || false;
  266.         } else {
  267.             value = h.getAttribute(target, 'data-sort');
  268.             isAsc = h.hasClass(target, asc) ? false : true;
  269.         }
  270.         for (var i = 0, il = sortButtons.length; i < il; i++) {
  271.             h.removeClass(sortButtons[i], asc);
  272.             h.removeClass(sortButtons[i], desc);
  273.         }
  274.         if (isAsc) {
  275.             if (target !== undefined) {
  276.                 h.addClass(target, asc);
  277.             }
  278.             isAsc = true;
  279.         } else {
  280.             if (target !== undefined) {
  281.                 h.addClass(target, desc);
  282.             }
  283.             isAsc = false;
  284.         }
  285.  
  286.         if (options.sortFunction) {
  287.             options.sortFunction = options.sortFunction;
  288.         } else {
  289.             options.sortFunction = function(a, b) {
  290.                 return h.sorter.alphanum(a.values()[value].toLowerCase(), b.values()[value].toLowerCase(), isAsc);
  291.             };
  292.         }
  293.         self.items.sort(options.sortFunction);
  294.         self.update();
  295.     };
  296.  
  297. /*
  298.     * Searches the list after values with content "searchStringOrEvent".
  299.     * The columns parameter defines if all values should be included in the search,
  300.     * defaults to undefined which means "all".
  301.     */  */
  302.     this.search = function(searchString, columns) {
  303.         self.i =// Reset paging
  304. ing
  305.         var matching = [],
  306.             found,
  307.             item,
  308.             text,
  309.             values,
  310.             is,
  311.             columns = (columns === undefined) ? self.items[0].values() : columns,
  312.             searchString = (searchString === undefined) ? "" : searchString,
  313.             target = searchString.target || searchString.srcEleme/* IE have srcElement */t */
  314.  
  315.         searchString = (target === undefined) ? (""+searchString).toLowerCase() : ""+target.value.toLowerCase();
  316.         is = self.items;
  317.     // Escape regular expression characters
  318. ers
  319.         searchString = searchString.replace(\]{}()*+?.,\\^$|#\s]/g, "\, "\\$&");
  320.  
  321.         templater.clear();
  322.         if (searchString === "" ) {
  323.             reset.search();
  324.             self.searched = false;
  325.             self.update();
  326.         } else {
  327.             self.searched = true;
  328.  
  329.             for (var k = 0, kl = is.length; k < kl; k++) {
  330.                 found = false;
  331.                 item = is[k];
  332.                 values = item.values();
  333.  
  334.                 for(var j in columns) {
  335.                     if(values.hasOwnProperty(j) && columns[j] !== null) {
  336.                         text = (values[j] != null) ? values[j].toString().toLowerCase() : "";
  337.                         if ((searchString !== "") && (text.search(searchString) > -1)) {
  338.                             found = true;
  339.                         }
  340.                     }
  341.                 }
  342.                 if (found) {
  343.                     item.found = true;
  344.                     matching.push(item);
  345.                 } else {
  346.                     item.found = false;
  347.                 }
  348.             }
  349.             self.update();
  350.         }
  351.         return self.visibleItems;
  352.     };
  353.  
  354. /*
  355.     * Filters the list. If filterFunction() returns False hides the Item.
  356.     * if filterFunction == false are the filter removed
  357.     */  */
  358.     this.filter = function(filterFunction) {
  359.         self.i =// Reset paging
  360. ing
  361.         reset.filter();
  362.         if (filterFunction === undefined) {
  363.             self.filtered = false;
  364.         } else {
  365.             self.filtered = true;
  366.             var is = self.items;
  367.             for (var i = 0, il = is.length; i < il; i++) {
  368.                 var item = is[i];
  369.                 if (filterFunction(item)) {
  370.                     item.filtered = true;
  371.                 } else {
  372.                     item.filtered = false;
  373.                 }
  374.             }
  375.         }
  376.         self.update();
  377.         return self.visibleItems;
  378.     };
  379.  
  380. /*
  381.     * Get size of the list
  382.     */  */
  383.     this.size = function() {
  384.         return self.items.length;
  385.     };
  386.  
  387. /*
  388.     * Removes all items from the list
  389.     */  */
  390.     this.clear = function() {
  391.         templater.clear();
  392.         self.items = [];
  393.     };
  394.  
  395.     this.on = function(event, callback) {
  396.         events[event].push(callback);
  397.     };
  398.  
  399.     var trigger = function(event) {
  400.         var i = events[event].length;
  401.         while(i--) {
  402.             events[event][i]();
  403.         }
  404.     };
  405.  
  406.     var reset = {
  407.         filter: function() {
  408.             var is = self.items,
  409.                 il = is.length;
  410.             while (il--) {
  411.                 is[il].filtered = false;
  412.             }
  413.         },
  414.         search: function() {
  415.             var is = self.items,
  416.                 il = is.length;
  417.             while (il--) {
  418.                 is[il].found = false;
  419.             }
  420.         }
  421.     };
  422.  
  423.  
  424.     this.update = function() {
  425.         var is = self.items,
  426.             il = is.length;
  427.  
  428.         self.visibleItems = [];
  429.         self.matchingItems = [];
  430.         templater.clear();
  431.         for (var i = 0; i < il; i++) {
  432.             if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
  433.                 is[i].show();
  434.                 self.visibleItems.push(is[i]);
  435.                 self.matchingItems.push(is[i]);
  436.             } else if (is[i].matching()) {
  437.                 self.matchingItems.push(is[i]);
  438.                 is[i].hide();
  439.             } else {
  440.                 is[i].hide();
  441.             }
  442.         }
  443.         trigger('updated');
  444.     };
  445.  
  446.     Item = function(initValues, element, notCreate) {
  447.         var item = this,
  448.             values = {};
  449.  
  450.         this.found = fal// Show if list.searched == true and this.found == true
  451. rue
  452.         this.filtered = fa// Show if list.filtered == true and this.filtered == true
  453. rue
  454.  
  455.         var init = function(initValues, element, notCreate) {
  456.             if (element === undefined) {
  457.                 if (notCreate) {
  458.                     item.values(initValues, notCreate);
  459.                 } else {
  460.                     item.values(initValues);
  461.                 }
  462.             } else {
  463.                 item.elm = element;
  464.                 var values = templater.get(item, initValues);
  465.                 item.values(values);
  466.             }
  467.         };
  468.         this.values = function(newValues, notCreate) {
  469.             if (newValues !== undefined) {
  470.                 for(var name in newValues) {
  471.                     values[name] = newValues[name];
  472.                 }
  473.                 if (notCreate !== true) {
  474.                     templater.set(item, item.values());
  475.                 }
  476.             } else {
  477.                 return values;
  478.             }
  479.         };
  480.         this.show = function() {
  481.             templater.show(item);
  482.         };
  483.         this.hide = function() {
  484.             templater.hide(item);
  485.         };
  486.         this.matching = function() {
  487.             return (
  488.                 (self.filtered && self.searched && item.found && item.filtered) ||
  489.                 (self.filtered && !self.searched && item.filtered) ||
  490.                 (!self.filtered && self.searched && item.found) ||
  491.                 (!self.filtered && !self.searched)
  492.             );
  493.         };
  494.         this.visible = function() {
  495.             return (item.elm.parentNode) ? true : false;
  496.         };
  497.         init(initValues, element, notCreate);
  498.     };
  499.  
  500. /* Templater with different kinds of template engines.
  501.     * All engines have these methods
  502.     * - reload(item)
  503.     * - remove(item)
  504.     */  */
  505.     Templater = function(list, settings) {
  506.         if (settings.engine === undefined) {
  507.             settings.engine = "standard";
  508.         } else {
  509.             settings.engine = settings.engine.toLowerCase();
  510.         }
  511.         return new self.constructor.prototype.templateEngines[settings.engine](list, settings);
  512.     };
  513.  
  514.     init.start(values, options);
  515. };
  516.  
  517. List.prototype.templateEngines = {};
  518. List.prototype.plugins = {};
  519.  
  520. List.prototype.templateEngines.standard = function(list, settings) {
  521.     var listSource = h.getByClass(settings.listClass, list.listContainer, true),
  522.         itemSource = getItemSource(settings.item),
  523.         templater = this;
  524.  
  525.     function getItemSource(item) {
  526.         if (item === undefined) {
  527.             var nodes = listSource.childNodes,
  528.                 items = [];
  529.  
  530.             for (var i = 0, il = nodes.length; i < il; i++) {
  531.             // Only textnodes have a data attribute
  532. ute
  533.                 if (nodes[i].data === undefined) {
  534.                     return nodes[i];
  535.                 }
  536.             }
  537.             return null;
  538.         } else if (item.indexOf("<") !== -1// Try create html element of list, do not work for tables!!
  539. s!!
  540.             var div = document.createElement(');
  541.            div.innerHTML = item;
  542.            return div.firstChild;
  543.        } else {
  544.            return document.getElementById(settings.item);
  545.        }
  546.    }
  547.  
  548.    var ensure = {
  549.        created: function(item) {
  550.            if (item.elm === undefined) {
  551.                templater.create(item);
  552.            }
  553.        }
  554.    };
  555.  
  556.    /* Get values from element */
  557.    this.get = function(item, valueNames) {
  558.        ensure.created(item);
  559.        var values = {};
  560.        for(var i = 0, il = valueNames.length; i < il; i++) {
  561.            var elm = h.getByClass(valueNames[i], item.elm, true);
  562.            values[valueNames[i]] = elm ? elm.innerHTML : "";
  563.        }
  564.        return values;
  565.    };
  566.  
  567.    /* Sets values at element */
  568.    this.set = function(item, values) {
  569.        ensure.created(item);
  570.        for(var v in values) {
  571.            if (values.hasOwnProperty(v)) {
  572.                // TODO speed up if possible
  573.                var elm = h.getByClass(v, item.elm, true);
  574.                if (elm) {
  575.                    elm.innerHTML = values[v];
  576.                }
  577.            }
  578.        }
  579.    };
  580.  
  581.    this.create = function(item) {
  582.        if (item.elm !== undefined) {
  583.            return;
  584.        }
  585.        /* If item source does not exists, use the first item in list as
  586.        source for new items */
  587.        var newItem = itemSource.cloneNode(true);
  588.        newItem.id = "";
  589.        item.elm = newItem;
  590.        templater.set(item, item.values());
  591.    };
  592.    this.remove = function(item) {
  593.        listSource.removeChild(item.elm);
  594.    };
  595.    this.show = function(item) {
  596.        ensure.created(item);
  597.        listSource.appendChild(item.elm);
  598.    };
  599.    this.hide = function(item) {
  600.        if (item.elm !== undefined && item.elm.parentNode === listSource) {
  601.            listSource.removeChild(item.elm);
  602.        }
  603.    };
  604.    this.clear = function() {
  605.        /* .innerHTML = ' = ''; fucks up IE */
  606.         if (listSource.hasChildNodes()) {
  607.             while (listSource.childNodes.length >= 1)
  608.             {
  609.                 listSource.removeChild(listSource.firstChild);
  610.             }
  611.         }
  612.     };
  613. }/*
  614. * These helper functions are not written by List.js author Jonny (they may have been
  615. * adjusted, thought).
  616. */.
  617. */
  618. h = {
  619. /*
  620.     * Cross browser getElementsByClassName, which uses native
  621.     * if it exists. Modified version of Dustin Diaz function:
  622.     * http://www.dustindiaz.com/getelementsbyclass
  623.     */  */
  624.     getByClass: (function() {
  625.         if (document.getElementsByClassName) {
  626.             return function(searchClass,node,single) {
  627.                 if (single) {
  628.                     return node.getElementsByClassName(searchClass)[0];
  629.                 } else {
  630.                     return node.getElementsByClassName(searchClass);
  631.                 }
  632.             };
  633.         } else {
  634.             return function(searchClass,node,single) {
  635.                 var classElements = [],
  636.                     tag = '*';
  637.                 if (node == null) {
  638.                     node = document;
  639.                 }
  640.                 var els = node.getElementsByTagName(tag);
  641.                 var elsLen = els.length;
  642.                 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
  643.                 for (var i = 0, j = 0; i < elsLen; i++) {
  644.                     if ( pattern.test(els[i].className) ) {
  645.                         if (single) {
  646.                             return els[i];
  647.                         } else {
  648.                             classElements[j] = els[i];
  649.                             j++;
  650.                         }
  651.                     }
  652.                 }
  653.                 return classElements;
  654.             };
  655.         }
  656.     })(),
  657. /* (elm, 'event' callback) Source: http://net.tutsplus.com/tutorials/javascript-ajax/javascript-from-null-cross-browser-event-binding/ *// */
  658.     addEvent: (function( window, document ) {
  659.         if ( document.addEventListener ) {
  660.             return function( elem, type, cb ) {
  661.                 if ((elem && !(elem instanceof Array) && !elem.length && !h.isNodeList(elem) && (elem.length !== 0)) || elem === window ) {
  662.                     elem.addEventListener(type, cb, false );
  663.                 } else if ( elem && elem[0] !== undefined ) {
  664.                     var len = elem.length;
  665.                     for ( var i = 0; i < len; i++ ) {
  666.                         h.addEvent(elem[i], type, cb);
  667.                     }
  668.                 }
  669.             };
  670.         }
  671.         else if ( document.attachEvent ) {
  672.             return function ( elem, type, cb ) {
  673.                 if ((elem && !(elem instanceof Array) && !elem.length && !h.isNodeList(elem) && (elem.length !== 0)) || elem === window ) {
  674.                     elem.attachEvent( 'on' + type, function() { return cb.call(elem, window.event); } );
  675.                 } else if ( elem && elem[0] !== undefined ) {
  676.                     var len = elem.length;
  677.                     for ( var i = 0; i < len; i++ ) {
  678.                         h.addEvent( elem[i], type, cb );
  679.                     }
  680.                 }
  681.             };
  682.         }
  683.     })(this, document),
  684. /* (elm, attribute) Source: http://stackoverflow.com/questions/3755227/cross-browser-javascript-getattribute-method */d */
  685.     getAttribute: function(ele, attr) {
  686.         var result = (ele.getAttribute && ele.getAttribute(attr)) || null;
  687.         if( !result ) {
  688.             var attrs = ele.attributes;
  689.             var length = attrs.length;
  690.             for(var i = 0; i < length; i++) {
  691.                 if (attr[i] !== undefined) {
  692.                     if(attr[i].nodeName === attr) {
  693.                         result = attr[i].nodeValue;
  694.                     }
  695.                 }
  696.             }
  697.         }
  698.         return result;
  699.     },
  700. /* http://stackoverflow.com/questions/7238177/detect-htmlcollection-nodelist-in-javascript */t */
  701.     isNodeList: function(nodes) {
  702.         var result = Object.prototype.toString.call(nodes);
  703.         if (typeof nodes === 'object' && object (HTMLCollection|NodeList|Object)\]$/.tes.test(result) && (nodes.length == 0 || (typeof nodes[0] === "object" && nodes[0].nodeType > 0))) {
  704.             return true;
  705.         }
  706.         return false;
  707.     },
  708.     hasClass: function(ele, classN) {
  709.         var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
  710.         return (classes.search(classN) > -1);
  711.     },
  712.     addClass: function(ele, classN) {
  713.         if (!this.hasClass(ele, classN)) {
  714.             var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
  715.             classes = classes + ' ' + classN + ' ';
  716.             classes = classes.replace(2,}/g, ' , ' ');
  717.             ele.setAttribute('class', classes);
  718.         }
  719.     },
  720.     removeClass: function(ele, classN) {
  721.         if (this.hasClass(ele, classN)) {
  722.             var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
  723.             classes = classes.replace(classN, '');
  724.             ele.setAttribute('class', classes);
  725.         }
  726.     },
  727. /*
  728.     * The sort function. From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
  729.     */  */
  730.     sorter: {
  731.         alphanum: function(a,b,asc) {
  732.             if (a === undefined || a === null) {
  733.                 a = "";
  734.             }
  735.             if (b === undefined || b === null) {
  736.                 b = "";
  737.             }
  738.             a = a.toString().replace(t|gt);/g, fu, function (strMatch, p1){
  739.                 return (p1 == "lt"<" "<">" ">";
  740.             });
  741.             a = a.replace(?[^>]+(>|$)/g, "", "");
  742.  
  743.             b = b.toString().replace(t|gt);/g, fu, function (strMatch, p1){
  744.                 return (p1 == "lt"<" "<">" ">";
  745.             });
  746.             b = b.replace(?[^>]+(>|$)/g, "", "");
  747.             var aa = this.chunkify(a);
  748.             var bb = this.chunkify(b);
  749.  
  750.             for (var x = 0; aa[x] && bb[x]; x++) {
  751.                 if (aa[x] !== bb[x]) {
  752.                     var c = Number(aa[x]), d = Number(bb[x]);
  753.                     if (asc) {
  754.                         if (c == aa[x] && d == bb[x]) {
  755.                             return c - d;
  756.                         } else {
  757.                             return (aa[x] > bb[x]) ? 1 : -1;
  758.                         }
  759.                     } else {
  760.                         if (c == aa[x] && d == bb[x]) {
  761.                             return //c - d;
  762.  d;
  763.                         } else {
  764.                             return (aa[x] > bb[x]) ? -1 ://(aa[x] > bb[x]) ? 1 : -1;
  765. -1;
  766.                         }
  767.                     }
  768.                 }
  769.             }
  770.             return aa.length - bb.length;
  771.         },
  772.         chunkify: function(t) {
  773.             var tz = [], x = 0, y = -1, n = 0, i, j;
  774.  
  775.             while (i = (j = t.charAt(x++)).charCodeAt(0)) {
  776.                 var m = (i == 45 || i == 46 || (i >=48 && i <= 57));
  777.                 if (m !== n) {
  778.                     tz[++y] = "";
  779.                     n = m;
  780.                 }
  781.                 tz[y] += j;
  782.             }
  783.             return tz;
  784.         }
  785.     }
  786. };
  787.  
  788. window.List = List;
  789. window.ListJsHelpers = h;
  790. })(wind

Raw Paste


Login or Register to edit or fork this paste. It's free.