Merge branch '3618-column-ordering' closes #3618
[arvados.git] / apps / workbench / app / assets / javascripts / list.js
1 ;(function(){
2
3 /**
4  * Require the given path.
5  *
6  * @param {String} path
7  * @return {Object} exports
8  * @api public
9  */
10
11 function require(path, parent, orig) {
12   var resolved = require.resolve(path);
13
14   // lookup failed
15   if (null == resolved) {
16     orig = orig || path;
17     parent = parent || 'root';
18     var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
19     err.path = orig;
20     err.parent = parent;
21     err.require = true;
22     throw err;
23   }
24
25   var module = require.modules[resolved];
26
27   // perform real require()
28   // by invoking the module's
29   // registered function
30   if (!module._resolving && !module.exports) {
31     var mod = {};
32     mod.exports = {};
33     mod.client = mod.component = true;
34     module._resolving = true;
35     module.call(this, mod.exports, require.relative(resolved), mod);
36     delete module._resolving;
37     module.exports = mod.exports;
38   }
39
40   return module.exports;
41 }
42
43 /**
44  * Registered modules.
45  */
46
47 require.modules = {};
48
49 /**
50  * Registered aliases.
51  */
52
53 require.aliases = {};
54
55 /**
56  * Resolve `path`.
57  *
58  * Lookup:
59  *
60  *   - PATH/index.js
61  *   - PATH.js
62  *   - PATH
63  *
64  * @param {String} path
65  * @return {String} path or null
66  * @api private
67  */
68
69 require.resolve = function(path) {
70   if (path.charAt(0) === '/') path = path.slice(1);
71
72   var paths = [
73     path,
74     path + '.js',
75     path + '.json',
76     path + '/index.js',
77     path + '/index.json'
78   ];
79
80   for (var i = 0; i < paths.length; i++) {
81     var path = paths[i];
82     if (require.modules.hasOwnProperty(path)) return path;
83     if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
84   }
85 };
86
87 /**
88  * Normalize `path` relative to the current path.
89  *
90  * @param {String} curr
91  * @param {String} path
92  * @return {String}
93  * @api private
94  */
95
96 require.normalize = function(curr, path) {
97   var segs = [];
98
99   if ('.' != path.charAt(0)) return path;
100
101   curr = curr.split('/');
102   path = path.split('/');
103
104   for (var i = 0; i < path.length; ++i) {
105     if ('..' == path[i]) {
106       curr.pop();
107     } else if ('.' != path[i] && '' != path[i]) {
108       segs.push(path[i]);
109     }
110   }
111
112   return curr.concat(segs).join('/');
113 };
114
115 /**
116  * Register module at `path` with callback `definition`.
117  *
118  * @param {String} path
119  * @param {Function} definition
120  * @api private
121  */
122
123 require.register = function(path, definition) {
124   require.modules[path] = definition;
125 };
126
127 /**
128  * Alias a module definition.
129  *
130  * @param {String} from
131  * @param {String} to
132  * @api private
133  */
134
135 require.alias = function(from, to) {
136   if (!require.modules.hasOwnProperty(from)) {
137     throw new Error('Failed to alias "' + from + '", it does not exist');
138   }
139   require.aliases[to] = from;
140 };
141
142 /**
143  * Return a require function relative to the `parent` path.
144  *
145  * @param {String} parent
146  * @return {Function}
147  * @api private
148  */
149
150 require.relative = function(parent) {
151   var p = require.normalize(parent, '..');
152
153   /**
154    * lastIndexOf helper.
155    */
156
157   function lastIndexOf(arr, obj) {
158     var i = arr.length;
159     while (i--) {
160       if (arr[i] === obj) return i;
161     }
162     return -1;
163   }
164
165   /**
166    * The relative require() itself.
167    */
168
169   function localRequire(path) {
170     var resolved = localRequire.resolve(path);
171     return require(resolved, parent, path);
172   }
173
174   /**
175    * Resolve relative to the parent.
176    */
177
178   localRequire.resolve = function(path) {
179     var c = path.charAt(0);
180     if ('/' == c) return path.slice(1);
181     if ('.' == c) return require.normalize(p, path);
182
183     // resolve deps by returning
184     // the dep in the nearest "deps"
185     // directory
186     var segs = parent.split('/');
187     var i = lastIndexOf(segs, 'deps') + 1;
188     if (!i) i = 0;
189     path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
190     return path;
191   };
192
193   /**
194    * Check if module is defined at `path`.
195    */
196
197   localRequire.exists = function(path) {
198     return require.modules.hasOwnProperty(localRequire.resolve(path));
199   };
200
201   return localRequire;
202 };
203 require.register("component-classes/index.js", function(exports, require, module){
204 /**
205  * Module dependencies.
206  */
207
208 var index = require('indexof');
209
210 /**
211  * Whitespace regexp.
212  */
213
214 var re = /\s+/;
215
216 /**
217  * toString reference.
218  */
219
220 var toString = Object.prototype.toString;
221
222 /**
223  * Wrap `el` in a `ClassList`.
224  *
225  * @param {Element} el
226  * @return {ClassList}
227  * @api public
228  */
229
230 module.exports = function(el){
231   return new ClassList(el);
232 };
233
234 /**
235  * Initialize a new ClassList for `el`.
236  *
237  * @param {Element} el
238  * @api private
239  */
240
241 function ClassList(el) {
242   if (!el) throw new Error('A DOM element reference is required');
243   this.el = el;
244   this.list = el.classList;
245 }
246
247 /**
248  * Add class `name` if not already present.
249  *
250  * @param {String} name
251  * @return {ClassList}
252  * @api public
253  */
254
255 ClassList.prototype.add = function(name){
256   // classList
257   if (this.list) {
258     this.list.add(name);
259     return this;
260   }
261
262   // fallback
263   var arr = this.array();
264   var i = index(arr, name);
265   if (!~i) arr.push(name);
266   this.el.className = arr.join(' ');
267   return this;
268 };
269
270 /**
271  * Remove class `name` when present, or
272  * pass a regular expression to remove
273  * any which match.
274  *
275  * @param {String|RegExp} name
276  * @return {ClassList}
277  * @api public
278  */
279
280 ClassList.prototype.remove = function(name){
281   if ('[object RegExp]' == toString.call(name)) {
282     return this.removeMatching(name);
283   }
284
285   // classList
286   if (this.list) {
287     this.list.remove(name);
288     return this;
289   }
290
291   // fallback
292   var arr = this.array();
293   var i = index(arr, name);
294   if (~i) arr.splice(i, 1);
295   this.el.className = arr.join(' ');
296   return this;
297 };
298
299 /**
300  * Remove all classes matching `re`.
301  *
302  * @param {RegExp} re
303  * @return {ClassList}
304  * @api private
305  */
306
307 ClassList.prototype.removeMatching = function(re){
308   var arr = this.array();
309   for (var i = 0; i < arr.length; i++) {
310     if (re.test(arr[i])) {
311       this.remove(arr[i]);
312     }
313   }
314   return this;
315 };
316
317 /**
318  * Toggle class `name`, can force state via `force`.
319  *
320  * For browsers that support classList, but do not support `force` yet,
321  * the mistake will be detected and corrected.
322  *
323  * @param {String} name
324  * @param {Boolean} force
325  * @return {ClassList}
326  * @api public
327  */
328
329 ClassList.prototype.toggle = function(name, force){
330   // classList
331   if (this.list) {
332     if ("undefined" !== typeof force) {
333       if (force !== this.list.toggle(name, force)) {
334         this.list.toggle(name); // toggle again to correct
335       }
336     } else {
337       this.list.toggle(name);
338     }
339     return this;
340   }
341
342   // fallback
343   if ("undefined" !== typeof force) {
344     if (!force) {
345       this.remove(name);
346     } else {
347       this.add(name);
348     }
349   } else {
350     if (this.has(name)) {
351       this.remove(name);
352     } else {
353       this.add(name);
354     }
355   }
356
357   return this;
358 };
359
360 /**
361  * Return an array of classes.
362  *
363  * @return {Array}
364  * @api public
365  */
366
367 ClassList.prototype.array = function(){
368   var str = this.el.className.replace(/^\s+|\s+$/g, '');
369   var arr = str.split(re);
370   if ('' === arr[0]) arr.shift();
371   return arr;
372 };
373
374 /**
375  * Check if class `name` is present.
376  *
377  * @param {String} name
378  * @return {ClassList}
379  * @api public
380  */
381
382 ClassList.prototype.has =
383 ClassList.prototype.contains = function(name){
384   return this.list
385     ? this.list.contains(name)
386     : !! ~index(this.array(), name);
387 };
388
389 });
390 require.register("segmentio-extend/index.js", function(exports, require, module){
391
392 module.exports = function extend (object) {
393     // Takes an unlimited number of extenders.
394     var args = Array.prototype.slice.call(arguments, 1);
395
396     // For each extender, copy their properties on our object.
397     for (var i = 0, source; source = args[i]; i++) {
398         if (!source) continue;
399         for (var property in source) {
400             object[property] = source[property];
401         }
402     }
403
404     return object;
405 };
406 });
407 require.register("component-indexof/index.js", function(exports, require, module){
408 module.exports = function(arr, obj){
409   if (arr.indexOf) return arr.indexOf(obj);
410   for (var i = 0; i < arr.length; ++i) {
411     if (arr[i] === obj) return i;
412   }
413   return -1;
414 };
415 });
416 require.register("component-event/index.js", function(exports, require, module){
417 var bind = window.addEventListener ? 'addEventListener' : 'attachEvent',
418     unbind = window.removeEventListener ? 'removeEventListener' : 'detachEvent',
419     prefix = bind !== 'addEventListener' ? 'on' : '';
420
421 /**
422  * Bind `el` event `type` to `fn`.
423  *
424  * @param {Element} el
425  * @param {String} type
426  * @param {Function} fn
427  * @param {Boolean} capture
428  * @return {Function}
429  * @api public
430  */
431
432 exports.bind = function(el, type, fn, capture){
433   el[bind](prefix + type, fn, capture || false);
434   return fn;
435 };
436
437 /**
438  * Unbind `el` event `type`'s callback `fn`.
439  *
440  * @param {Element} el
441  * @param {String} type
442  * @param {Function} fn
443  * @param {Boolean} capture
444  * @return {Function}
445  * @api public
446  */
447
448 exports.unbind = function(el, type, fn, capture){
449   el[unbind](prefix + type, fn, capture || false);
450   return fn;
451 };
452 });
453 require.register("timoxley-to-array/index.js", function(exports, require, module){
454 /**
455  * Convert an array-like object into an `Array`.
456  * If `collection` is already an `Array`, then will return a clone of `collection`.
457  *
458  * @param {Array | Mixed} collection An `Array` or array-like object to convert e.g. `arguments` or `NodeList`
459  * @return {Array} Naive conversion of `collection` to a new `Array`.
460  * @api public
461  */
462
463 module.exports = function toArray(collection) {
464   if (typeof collection === 'undefined') return []
465   if (collection === null) return [null]
466   if (collection === window) return [window]
467   if (typeof collection === 'string') return [collection]
468   if (isArray(collection)) return collection
469   if (typeof collection.length != 'number') return [collection]
470   if (typeof collection === 'function' && collection instanceof Function) return [collection]
471
472   var arr = []
473   for (var i = 0; i < collection.length; i++) {
474     if (Object.prototype.hasOwnProperty.call(collection, i) || i in collection) {
475       arr.push(collection[i])
476     }
477   }
478   if (!arr.length) return []
479   return arr
480 }
481
482 function isArray(arr) {
483   return Object.prototype.toString.call(arr) === "[object Array]";
484 }
485
486 });
487 require.register("javve-events/index.js", function(exports, require, module){
488 var events = require('event'),
489   toArray = require('to-array');
490
491 /**
492  * Bind `el` event `type` to `fn`.
493  *
494  * @param {Element} el, NodeList, HTMLCollection or Array
495  * @param {String} type
496  * @param {Function} fn
497  * @param {Boolean} capture
498  * @api public
499  */
500
501 exports.bind = function(el, type, fn, capture){
502   el = toArray(el);
503   for ( var i = 0; i < el.length; i++ ) {
504     events.bind(el[i], type, fn, capture);
505   }
506 };
507
508 /**
509  * Unbind `el` event `type`'s callback `fn`.
510  *
511  * @param {Element} el, NodeList, HTMLCollection or Array
512  * @param {String} type
513  * @param {Function} fn
514  * @param {Boolean} capture
515  * @api public
516  */
517
518 exports.unbind = function(el, type, fn, capture){
519   el = toArray(el);
520   for ( var i = 0; i < el.length; i++ ) {
521     events.unbind(el[i], type, fn, capture);
522   }
523 };
524
525 });
526 require.register("javve-get-by-class/index.js", function(exports, require, module){
527 /**
528  * Find all elements with class `className` inside `container`.
529  * Use `single = true` to increase performance in older browsers
530  * when only one element is needed.
531  *
532  * @param {String} className
533  * @param {Element} container
534  * @param {Boolean} single
535  * @api public
536  */
537
538 module.exports = (function() {
539   if (document.getElementsByClassName) {
540     return function(container, className, single) {
541       if (single) {
542         return container.getElementsByClassName(className)[0];
543       } else {
544         return container.getElementsByClassName(className);
545       }
546     };
547   } else if (document.querySelector) {
548     return function(container, className, single) {
549       className = '.' + className;
550       if (single) {
551         return container.querySelector(className);
552       } else {
553         return container.querySelectorAll(className);
554       }
555     };
556   } else {
557     return function(container, className, single) {
558       var classElements = [],
559         tag = '*';
560       if (container == null) {
561         container = document;
562       }
563       var els = container.getElementsByTagName(tag);
564       var elsLen = els.length;
565       var pattern = new RegExp("(^|\\s)"+className+"(\\s|$)");
566       for (var i = 0, j = 0; i < elsLen; i++) {
567         if ( pattern.test(els[i].className) ) {
568           if (single) {
569             return els[i];
570           } else {
571             classElements[j] = els[i];
572             j++;
573           }
574         }
575       }
576       return classElements;
577     };
578   }
579 })();
580
581 });
582 require.register("javve-get-attribute/index.js", function(exports, require, module){
583 /**
584  * Return the value for `attr` at `element`.
585  *
586  * @param {Element} el
587  * @param {String} attr
588  * @api public
589  */
590
591 module.exports = function(el, attr) {
592   var result = (el.getAttribute && el.getAttribute(attr)) || null;
593   if( !result ) {
594     var attrs = el.attributes;
595     var length = attrs.length;
596     for(var i = 0; i < length; i++) {
597       if (attr[i] !== undefined) {
598         if(attr[i].nodeName === attr) {
599           result = attr[i].nodeValue;
600         }
601       }
602     }
603   }
604   return result;
605 }
606 });
607 require.register("javve-natural-sort/index.js", function(exports, require, module){
608 /*
609  * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license
610  * Author: Jim Palmer (based on chunking idea from Dave Koelle)
611  */
612
613 module.exports = function(a, b, options) {
614   var re = /(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,
615     sre = /(^[ ]*|[ ]*$)/g,
616     dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
617     hre = /^0x[0-9a-f]+$/i,
618     ore = /^0/,
619     options = options || {},
620     i = function(s) { return options.insensitive && (''+s).toLowerCase() || ''+s },
621     // convert all to strings strip whitespace
622     x = i(a).replace(sre, '') || '',
623     y = i(b).replace(sre, '') || '',
624     // chunk/tokenize
625     xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
626     yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
627     // numeric, hex or date detection
628     xD = parseInt(x.match(hre)) || (xN.length != 1 && x.match(dre) && Date.parse(x)),
629     yD = parseInt(y.match(hre)) || xD && y.match(dre) && Date.parse(y) || null,
630     oFxNcL, oFyNcL,
631     mult = options.desc ? -1 : 1;
632   // first try and sort Hex codes or Dates
633   if (yD)
634     if ( xD < yD ) return -1 * mult;
635     else if ( xD > yD ) return 1 * mult;
636   // natural sorting through split numeric strings and default strings
637   for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) {
638     // find floats not starting with '0', string or 0 if not defined (Clint Priest)
639     oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0;
640     oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0;
641     // handle numeric vs string comparison - number < string - (Kyle Adams)
642     if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; }
643     // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
644     else if (typeof oFxNcL !== typeof oFyNcL) {
645       oFxNcL += '';
646       oFyNcL += '';
647     }
648     if (oFxNcL < oFyNcL) return -1 * mult;
649     if (oFxNcL > oFyNcL) return 1 * mult;
650   }
651   return 0;
652 };
653
654 /*
655 var defaultSort = getSortFunction();
656
657 module.exports = function(a, b, options) {
658   if (arguments.length == 1) {
659     options = a;
660     return getSortFunction(options);
661   } else {
662     return defaultSort(a,b);
663   }
664 }
665 */
666 });
667 require.register("javve-to-string/index.js", function(exports, require, module){
668 module.exports = function(s) {
669     s = (s === undefined) ? "" : s;
670     s = (s === null) ? "" : s;
671     s = s.toString();
672     return s;
673 };
674
675 });
676 require.register("component-type/index.js", function(exports, require, module){
677 /**
678  * toString ref.
679  */
680
681 var toString = Object.prototype.toString;
682
683 /**
684  * Return the type of `val`.
685  *
686  * @param {Mixed} val
687  * @return {String}
688  * @api public
689  */
690
691 module.exports = function(val){
692   switch (toString.call(val)) {
693     case '[object Date]': return 'date';
694     case '[object RegExp]': return 'regexp';
695     case '[object Arguments]': return 'arguments';
696     case '[object Array]': return 'array';
697     case '[object Error]': return 'error';
698   }
699
700   if (val === null) return 'null';
701   if (val === undefined) return 'undefined';
702   if (val !== val) return 'nan';
703   if (val && val.nodeType === 1) return 'element';
704
705   return typeof val.valueOf();
706 };
707
708 });
709 require.register("list.js/index.js", function(exports, require, module){
710 /*
711 ListJS with beta 1.0.0
712 By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
713 */
714 (function( window, undefined ) {
715 "use strict";
716
717 var document = window.document,
718     getByClass = require('get-by-class'),
719     extend = require('extend'),
720     indexOf = require('indexof');
721
722 var List = function(id, options, values) {
723
724     var self = this,
725                 init,
726         Item = require('./src/item')(self),
727         addAsync = require('./src/add-async')(self),
728         parse = require('./src/parse')(self);
729
730     init = {
731         start: function() {
732             self.listClass      = "list";
733             self.searchClass    = "search";
734             self.sortClass      = "sort";
735             self.page           = 200;
736             self.i              = 1;
737             self.items          = [];
738             self.visibleItems   = [];
739             self.matchingItems  = [];
740             self.searched       = false;
741             self.filtered       = false;
742             self.handlers       = { 'updated': [] };
743             self.plugins        = {};
744             self.helpers        = {
745                 getByClass: getByClass,
746                 extend: extend,
747                 indexOf: indexOf
748             };
749
750             extend(self, options);
751
752             self.listContainer = (typeof(id) === 'string') ? document.getElementById(id) : id;
753             if (!self.listContainer) { return; }
754             self.list           = getByClass(self.listContainer, self.listClass, true);
755
756             self.templater      = require('./src/templater')(self);
757             self.search         = require('./src/search')(self);
758             self.filter         = require('./src/filter')(self);
759             self.sort           = require('./src/sort')(self);
760
761             this.items();
762             self.update();
763             this.plugins();
764         },
765         items: function() {
766             parse(self.list);
767             if (values !== undefined) {
768                 self.add(values);
769             }
770         },
771         plugins: function() {
772             for (var i = 0; i < self.plugins.length; i++) {
773                 var plugin = self.plugins[i];
774                 self[plugin.name] = plugin;
775                 plugin.init(self);
776             }
777         }
778     };
779
780
781     /*
782     * Add object to list
783     */
784     this.add = function(values, callback) {
785         if (callback) {
786             addAsync(values, callback);
787             return;
788         }
789         var added = [],
790             notCreate = false;
791         if (values[0] === undefined){
792             values = [values];
793         }
794         for (var i = 0, il = values.length; i < il; i++) {
795             var item = null;
796             if (values[i] instanceof Item) {
797                 item = values[i];
798                 item.reload();
799             } else {
800                 notCreate = (self.items.length > self.page) ? true : false;
801                 item = new Item(values[i], undefined, notCreate);
802             }
803             self.items.push(item);
804             added.push(item);
805         }
806         self.update();
807         return added;
808     };
809
810         this.show = function(i, page) {
811                 this.i = i;
812                 this.page = page;
813                 self.update();
814         return self;
815         };
816
817     /* Removes object from list.
818     * Loops through the list and removes objects where
819     * property "valuename" === value
820     */
821     this.remove = function(valueName, value, options) {
822         var found = 0;
823         for (var i = 0, il = self.items.length; i < il; i++) {
824             if (self.items[i].values()[valueName] == value) {
825                 self.templater.remove(self.items[i], options);
826                 self.items.splice(i,1);
827                 il--;
828                 i--;
829                 found++;
830             }
831         }
832         self.update();
833         return found;
834     };
835
836     /* Gets the objects in the list which
837     * property "valueName" === value
838     */
839     this.get = function(valueName, value) {
840         var matchedItems = [];
841         for (var i = 0, il = self.items.length; i < il; i++) {
842             var item = self.items[i];
843             if (item.values()[valueName] == value) {
844                 matchedItems.push(item);
845             }
846         }
847         return matchedItems;
848     };
849
850     /*
851     * Get size of the list
852     */
853     this.size = function() {
854         return self.items.length;
855     };
856
857     /*
858     * Removes all items from the list
859     */
860     this.clear = function() {
861         self.templater.clear();
862         self.items = [];
863         return self;
864     };
865
866     this.on = function(event, callback) {
867         self.handlers[event].push(callback);
868         return self;
869     };
870
871     this.off = function(event, callback) {
872         var e = self.handlers[event];
873         var index = indexOf(e, callback);
874         if (index > -1) {
875             e.splice(index, 1);
876         }
877         return self;
878     };
879
880     this.trigger = function(event) {
881         var i = self.handlers[event].length;
882         while(i--) {
883             self.handlers[event][i](self);
884         }
885         return self;
886     };
887
888     this.reset = {
889         filter: function() {
890             var is = self.items,
891                 il = is.length;
892             while (il--) {
893                 is[il].filtered = false;
894             }
895             return self;
896         },
897         search: function() {
898             var is = self.items,
899                 il = is.length;
900             while (il--) {
901                 is[il].found = false;
902             }
903             return self;
904         }
905     };
906
907     this.update = function() {
908         var is = self.items,
909                         il = is.length;
910
911         self.visibleItems = [];
912         self.matchingItems = [];
913         self.templater.clear();
914         for (var i = 0; i < il; i++) {
915             if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
916                 is[i].show();
917                 self.visibleItems.push(is[i]);
918                 self.matchingItems.push(is[i]);
919                         } else if (is[i].matching()) {
920                 self.matchingItems.push(is[i]);
921                 is[i].hide();
922                         } else {
923                 is[i].hide();
924                         }
925         }
926         self.trigger('updated');
927         return self;
928     };
929
930     init.start();
931 };
932
933 module.exports = List;
934
935 })(window);
936
937 });
938 require.register("list.js/src/search.js", function(exports, require, module){
939 var events = require('events'),
940     getByClass = require('get-by-class'),
941     toString = require('to-string');
942
943 module.exports = function(list) {
944     var item,
945         text,
946         columns,
947         searchString,
948         customSearch;
949
950     var prepare = {
951         resetList: function() {
952             list.i = 1;
953             list.templater.clear();
954             customSearch = undefined;
955         },
956         setOptions: function(args) {
957             if (args.length == 2 && args[1] instanceof Array) {
958                 columns = args[1];
959             } else if (args.length == 2 && typeof(args[1]) == "function") {
960                 customSearch = args[1];
961             } else if (args.length == 3) {
962                 columns = args[1];
963                 customSearch = args[2];
964             }
965         },
966         setColumns: function() {
967             columns = (columns === undefined) ? prepare.toArray(list.items[0].values()) : columns;
968         },
969         setSearchString: function(s) {
970             s = toString(s).toLowerCase();
971             s = s.replace(/[-[\]{}()*+?.,\\^$|#]/g, "\\$&"); // Escape regular expression characters
972             searchString = s;
973         },
974         toArray: function(values) {
975             var tmpColumn = [];
976             for (var name in values) {
977                 tmpColumn.push(name);
978             }
979             return tmpColumn;
980         }
981     };
982     var search = {
983         list: function() {
984             for (var k = 0, kl = list.items.length; k < kl; k++) {
985                 search.item(list.items[k]);
986             }
987         },
988         item: function(item) {
989             item.found = false;
990             for (var j = 0, jl = columns.length; j < jl; j++) {
991                 if (search.values(item.values(), columns[j])) {
992                     item.found = true;
993                     return;
994                 }
995             }
996         },
997         values: function(values, column) {
998             if (values.hasOwnProperty(column)) {
999                 text = toString(values[column]).toLowerCase();
1000                 if ((searchString !== "") && (text.search(searchString) > -1)) {
1001                     return true;
1002                 }
1003             }
1004             return false;
1005         },
1006         reset: function() {
1007             list.reset.search();
1008             list.searched = false;
1009         }
1010     };
1011
1012     var searchMethod = function(str) {
1013         list.trigger('searchStart');
1014
1015         prepare.resetList();
1016         prepare.setSearchString(str);
1017         prepare.setOptions(arguments); // str, cols|searchFunction, searchFunction
1018         prepare.setColumns();
1019
1020         if (searchString === "" ) {
1021             search.reset();
1022         } else {
1023             list.searched = true;
1024             if (customSearch) {
1025                 customSearch(searchString, columns);
1026             } else {
1027                 search.list();
1028             }
1029         }
1030
1031         list.update();
1032         list.trigger('searchComplete');
1033         return list.visibleItems;
1034     };
1035
1036     list.handlers.searchStart = list.handlers.searchStart || [];
1037     list.handlers.searchComplete = list.handlers.searchComplete || [];
1038
1039     events.bind(getByClass(list.listContainer, list.searchClass), 'keyup', function(e) {
1040         var target = e.target || e.srcElement, // IE have srcElement
1041             alreadyCleared = (target.value === "" && !list.searched);
1042         if (!alreadyCleared) { // If oninput already have resetted the list, do nothing
1043             searchMethod(target.value);
1044         }
1045     });
1046
1047     // Used to detect click on HTML5 clear button
1048     events.bind(getByClass(list.listContainer, list.searchClass), 'input', function(e) {
1049         var target = e.target || e.srcElement;
1050         if (target.value === "") {
1051             searchMethod('');
1052         }
1053     });
1054
1055     list.helpers.toString = toString;
1056     return searchMethod;
1057 };
1058
1059 });
1060 require.register("list.js/src/sort.js", function(exports, require, module){
1061 var naturalSort = require('natural-sort'),
1062     classes = require('classes'),
1063     events = require('events'),
1064     getByClass = require('get-by-class'),
1065     getAttribute = require('get-attribute');
1066
1067 module.exports = function(list) {
1068     list.sortFunction = list.sortFunction || function(itemA, itemB, options) {
1069         options.desc = options.order == "desc" ? true : false; // Natural sort uses this format
1070         return naturalSort(itemA.values()[options.valueName], itemB.values()[options.valueName], options);
1071     };
1072
1073     var buttons = {
1074         els: undefined,
1075         clear: function() {
1076             for (var i = 0, il = buttons.els.length; i < il; i++) {
1077                 classes(buttons.els[i]).remove('asc');
1078                 classes(buttons.els[i]).remove('desc');
1079             }
1080         },
1081         getOrder: function(btn) {
1082             var predefinedOrder = getAttribute(btn, 'data-order');
1083             if (predefinedOrder == "asc" || predefinedOrder == "desc") {
1084                 return predefinedOrder;
1085             } else if (classes(btn).has('desc')) {
1086                 return "asc";
1087             } else if (classes(btn).has('asc')) {
1088                 return "desc";
1089             } else {
1090                 return "asc";
1091             }
1092         },
1093         getInSensitive: function(btn, options) {
1094             var insensitive = getAttribute(btn, 'data-insensitive');
1095             if (insensitive === "true") {
1096                 options.insensitive = true;
1097             } else {
1098                 options.insensitive = false;
1099             }
1100         },
1101         setOrder: function(options) {
1102             for (var i = 0, il = buttons.els.length; i < il; i++) {
1103                 var btn = buttons.els[i];
1104                 if (getAttribute(btn, 'data-sort') !== options.valueName) {
1105                     continue;
1106                 }
1107                 var predefinedOrder = getAttribute(btn, 'data-order');
1108                 if (predefinedOrder == "asc" || predefinedOrder == "desc") {
1109                     if (predefinedOrder == options.order) {
1110                         classes(btn).add(options.order);
1111                     }
1112                 } else {
1113                     classes(btn).add(options.order);
1114                 }
1115             }
1116         }
1117     };
1118     var sort = function() {
1119         list.trigger('sortStart');
1120         options = {};
1121
1122         var target = arguments[0].currentTarget || arguments[0].srcElement || undefined;
1123
1124         if (target) {
1125             options.valueName = getAttribute(target, 'data-sort');
1126             buttons.getInSensitive(target, options);
1127             options.order = buttons.getOrder(target);
1128         } else {
1129             options = arguments[1] || options;
1130             options.valueName = arguments[0];
1131             options.order = options.order || "asc";
1132             options.insensitive = (typeof options.insensitive == "undefined") ? true : options.insensitive;
1133         }
1134         buttons.clear();
1135         buttons.setOrder(options);
1136
1137         options.sortFunction = options.sortFunction || list.sortFunction;
1138         list.items.sort(function(a, b) {
1139             return options.sortFunction(a, b, options);
1140         });
1141         list.update();
1142         list.trigger('sortComplete');
1143     };
1144
1145     // Add handlers
1146     list.handlers.sortStart = list.handlers.sortStart || [];
1147     list.handlers.sortComplete = list.handlers.sortComplete || [];
1148
1149     buttons.els = getByClass(list.listContainer, list.sortClass);
1150     events.bind(buttons.els, 'click', sort);
1151     list.on('searchStart', buttons.clear);
1152     list.on('filterStart', buttons.clear);
1153
1154     // Helpers
1155     list.helpers.classes = classes;
1156     list.helpers.naturalSort = naturalSort;
1157     list.helpers.events = events;
1158     list.helpers.getAttribute = getAttribute;
1159
1160     return sort;
1161 };
1162
1163 });
1164 require.register("list.js/src/item.js", function(exports, require, module){
1165 module.exports = function(list) {
1166     return function(initValues, element, notCreate) {
1167         var item = this;
1168
1169         this._values = {};
1170
1171         this.found = false; // Show if list.searched == true and this.found == true
1172         this.filtered = false;// Show if list.filtered == true and this.filtered == true
1173
1174         var init = function(initValues, element, notCreate) {
1175             if (element === undefined) {
1176                 if (notCreate) {
1177                     item.values(initValues, notCreate);
1178                 } else {
1179                     item.values(initValues);
1180                 }
1181             } else {
1182                 item.elm = element;
1183                 var values = list.templater.get(item, initValues);
1184                 item.values(values);
1185             }
1186         };
1187         this.values = function(newValues, notCreate) {
1188             if (newValues !== undefined) {
1189                 for(var name in newValues) {
1190                     item._values[name] = newValues[name];
1191                 }
1192                 if (notCreate !== true) {
1193                     list.templater.set(item, item.values());
1194                 }
1195             } else {
1196                 return item._values;
1197             }
1198         };
1199         this.show = function() {
1200             list.templater.show(item);
1201         };
1202         this.hide = function() {
1203             list.templater.hide(item);
1204         };
1205         this.matching = function() {
1206             return (
1207                 (list.filtered && list.searched && item.found && item.filtered) ||
1208                 (list.filtered && !list.searched && item.filtered) ||
1209                 (!list.filtered && list.searched && item.found) ||
1210                 (!list.filtered && !list.searched)
1211             );
1212         };
1213         this.visible = function() {
1214             return (item.elm.parentNode == list.list) ? true : false;
1215         };
1216         init(initValues, element, notCreate);
1217     };
1218 };
1219
1220 });
1221 require.register("list.js/src/templater.js", function(exports, require, module){
1222 var getByClass = require('get-by-class');
1223
1224 var Templater = function(list) {
1225     var itemSource = getItemSource(list.item),
1226         templater = this;
1227
1228     function getItemSource(item) {
1229         if (item === undefined) {
1230             var nodes = list.list.childNodes,
1231                 items = [];
1232
1233             for (var i = 0, il = nodes.length; i < il; i++) {
1234                 // Only textnodes have a data attribute
1235                 if (nodes[i].data === undefined) {
1236                     return nodes[i];
1237                 }
1238             }
1239             return null;
1240         } else if (item.indexOf("<") !== -1) { // Try create html element of list, do not work for tables!!
1241             var div = document.createElement('div');
1242             div.innerHTML = item;
1243             return div.firstChild;
1244         } else {
1245             return document.getElementById(list.item);
1246         }
1247     }
1248
1249     /* Get values from element */
1250     this.get = function(item, valueNames) {
1251         templater.create(item);
1252         var values = {};
1253         for(var i = 0, il = valueNames.length; i < il; i++) {
1254             var elm = getByClass(item.elm, valueNames[i], true);
1255             values[valueNames[i]] = elm ? elm.innerHTML : "";
1256         }
1257         return values;
1258     };
1259
1260     /* Sets values at element */
1261     this.set = function(item, values) {
1262         if (!templater.create(item)) {
1263             for(var v in values) {
1264                 if (values.hasOwnProperty(v)) {
1265                     // TODO speed up if possible
1266                     var elm = getByClass(item.elm, v, true);
1267                     if (elm) {
1268                         /* src attribute for image tag & text for other tags */
1269                         if (elm.tagName === "IMG" && values[v] !== "") {
1270                             elm.src = values[v];
1271                         } else {
1272                             elm.innerHTML = values[v];
1273                         }
1274                     }
1275                 }
1276             }
1277         }
1278     };
1279
1280     this.create = function(item) {
1281         if (item.elm !== undefined) {
1282             return false;
1283         }
1284         /* If item source does not exists, use the first item in list as
1285         source for new items */
1286         var newItem = itemSource.cloneNode(true);
1287         newItem.removeAttribute('id');
1288         item.elm = newItem;
1289         templater.set(item, item.values());
1290         return true;
1291     };
1292     this.remove = function(item) {
1293         list.list.removeChild(item.elm);
1294     };
1295     this.show = function(item) {
1296         templater.create(item);
1297         list.list.appendChild(item.elm);
1298     };
1299     this.hide = function(item) {
1300         if (item.elm !== undefined && item.elm.parentNode === list.list) {
1301             list.list.removeChild(item.elm);
1302         }
1303     };
1304     this.clear = function() {
1305         /* .innerHTML = ''; fucks up IE */
1306         if (list.list.hasChildNodes()) {
1307             while (list.list.childNodes.length >= 1)
1308             {
1309                 list.list.removeChild(list.list.firstChild);
1310             }
1311         }
1312     };
1313 };
1314
1315 module.exports = function(list) {
1316     return new Templater(list);
1317 };
1318
1319 });
1320 require.register("list.js/src/filter.js", function(exports, require, module){
1321 module.exports = function(list) {
1322
1323     // Add handlers
1324     list.handlers.filterStart = list.handlers.filterStart || [];
1325     list.handlers.filterComplete = list.handlers.filterComplete || [];
1326
1327     return function(filterFunction) {
1328         list.trigger('filterStart');
1329         list.i = 1; // Reset paging
1330         list.reset.filter();
1331         if (filterFunction === undefined) {
1332             list.filtered = false;
1333         } else {
1334             list.filtered = true;
1335             var is = list.items;
1336             for (var i = 0, il = is.length; i < il; i++) {
1337                 var item = is[i];
1338                 if (filterFunction(item)) {
1339                     item.filtered = true;
1340                 } else {
1341                     item.filtered = false;
1342                 }
1343             }
1344         }
1345         list.update();
1346         list.trigger('filterComplete');
1347         return list.visibleItems;
1348     };
1349 };
1350
1351 });
1352 require.register("list.js/src/add-async.js", function(exports, require, module){
1353 module.exports = function(list) {
1354     return function(values, callback, items) {
1355         var valuesToAdd = values.splice(0, 100);
1356         items = items || [];
1357         items = items.concat(list.add(valuesToAdd));
1358         if (values.length > 0) {
1359             setTimeout(function() {
1360                 addAsync(values, callback, items);
1361             }, 10);
1362         } else {
1363             list.update();
1364             callback(items);
1365         }
1366     };
1367 };
1368 });
1369 require.register("list.js/src/parse.js", function(exports, require, module){
1370 module.exports = function(list) {
1371
1372     var Item = require('./item')(list);
1373
1374     var getChildren = function(parent) {
1375         var nodes = parent.childNodes,
1376             items = [];
1377         for (var i = 0, il = nodes.length; i < il; i++) {
1378             // Only textnodes have a data attribute
1379             if (nodes[i].data === undefined) {
1380                 items.push(nodes[i]);
1381             }
1382         }
1383         return items;
1384     };
1385
1386     var parse = function(itemElements, valueNames) {
1387         for (var i = 0, il = itemElements.length; i < il; i++) {
1388             list.items.push(new Item(valueNames, itemElements[i]));
1389         }
1390     };
1391     var parseAsync = function(itemElements, valueNames) {
1392         var itemsToIndex = itemElements.splice(0, 100); // TODO: If < 100 items, what happens in IE etc?
1393         parse(itemsToIndex, valueNames);
1394         if (itemElements.length > 0) {
1395             setTimeout(function() {
1396                 init.items.indexAsync(itemElements, valueNames);
1397             }, 10);
1398         } else {
1399             list.update();
1400             // TODO: Add indexed callback
1401         }
1402     };
1403
1404     return function() {
1405         var itemsToIndex = getChildren(list.list),
1406             valueNames = list.valueNames;
1407
1408         if (list.indexAsync) {
1409             parseAsync(itemsToIndex, valueNames);
1410         } else {
1411             parse(itemsToIndex, valueNames);
1412         }
1413     };
1414 };
1415
1416 });
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437 require.alias("component-classes/index.js", "list.js/deps/classes/index.js");
1438 require.alias("component-classes/index.js", "classes/index.js");
1439 require.alias("component-indexof/index.js", "component-classes/deps/indexof/index.js");
1440
1441 require.alias("segmentio-extend/index.js", "list.js/deps/extend/index.js");
1442 require.alias("segmentio-extend/index.js", "extend/index.js");
1443
1444 require.alias("component-indexof/index.js", "list.js/deps/indexof/index.js");
1445 require.alias("component-indexof/index.js", "indexof/index.js");
1446
1447 require.alias("javve-events/index.js", "list.js/deps/events/index.js");
1448 require.alias("javve-events/index.js", "events/index.js");
1449 require.alias("component-event/index.js", "javve-events/deps/event/index.js");
1450
1451 require.alias("timoxley-to-array/index.js", "javve-events/deps/to-array/index.js");
1452
1453 require.alias("javve-get-by-class/index.js", "list.js/deps/get-by-class/index.js");
1454 require.alias("javve-get-by-class/index.js", "get-by-class/index.js");
1455
1456 require.alias("javve-get-attribute/index.js", "list.js/deps/get-attribute/index.js");
1457 require.alias("javve-get-attribute/index.js", "get-attribute/index.js");
1458
1459 require.alias("javve-natural-sort/index.js", "list.js/deps/natural-sort/index.js");
1460 require.alias("javve-natural-sort/index.js", "natural-sort/index.js");
1461
1462 require.alias("javve-to-string/index.js", "list.js/deps/to-string/index.js");
1463 require.alias("javve-to-string/index.js", "list.js/deps/to-string/index.js");
1464 require.alias("javve-to-string/index.js", "to-string/index.js");
1465 require.alias("javve-to-string/index.js", "javve-to-string/index.js");
1466 require.alias("component-type/index.js", "list.js/deps/type/index.js");
1467 require.alias("component-type/index.js", "type/index.js");
1468 if (typeof exports == "object") {
1469   module.exports = require("list.js");
1470 } else if (typeof define == "function" && define.amd) {
1471   define(function(){ return require("list.js"); });
1472 } else {
1473   this["List"] = require("list.js");
1474 }})();