775 lines
26 KiB
JavaScript
775 lines
26 KiB
JavaScript
/*
|
|
ListJS Beta 0.2.0
|
|
By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
|
|
|
|
OBS. The API is not frozen. It MAY change!
|
|
|
|
License (MIT)
|
|
|
|
Copyright (c) 2011 Jonny Strömberg http://jonnystromberg.com
|
|
|
|
Permission is hereby granted, free of charge, to any person
|
|
obtaining a copy of this software and associated documentation
|
|
files (the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge,
|
|
publish, distribute, sublicense, and/or sell copies of the Software,
|
|
and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be
|
|
included in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
(function( window, undefined ) {
|
|
"use strict";
|
|
var document = window.document,
|
|
h;
|
|
|
|
var List = function(id, options, values) {
|
|
var self = this,
|
|
templater,
|
|
init,
|
|
initialItems,
|
|
Item,
|
|
Templater,
|
|
sortButtons,
|
|
events = {
|
|
'updated': []
|
|
};
|
|
this.listContainer = (typeof(id) == 'string') ? document.getElementById(id) : id;
|
|
// Check if the container exists. If not return instead of breaking the javascript
|
|
if (!this.listContainer)
|
|
return;
|
|
|
|
this.items = [];
|
|
this.visibleItems = []; // These are the items currently visible
|
|
this.matchingItems = []; // These are the items currently matching filters and search, regadlessof visible count
|
|
this.searched = false;
|
|
this.filtered = false;
|
|
|
|
this.list = null;
|
|
this.templateEngines = {};
|
|
|
|
this.page = options.page || 200;
|
|
this.i = options.i || 1;
|
|
|
|
init = {
|
|
start: function(values, options) {
|
|
options.plugins = options.plugins || {};
|
|
this.classes(options);
|
|
templater = new Templater(self, options);
|
|
this.callbacks(options);
|
|
this.items.start(values, options);
|
|
self.update();
|
|
this.plugins(options.plugins);
|
|
},
|
|
classes: function(options) {
|
|
options.listClass = options.listClass || 'list';
|
|
options.searchClass = options.searchClass || 'search';
|
|
options.sortClass = options.sortClass || 'sort';
|
|
},
|
|
callbacks: function(options) {
|
|
self.list = h.getByClass(options.listClass, self.listContainer, true);
|
|
h.addEvent(h.getByClass(options.searchClass, self.listContainer), 'keyup', self.search);
|
|
sortButtons = h.getByClass(options.sortClass, self.listContainer);
|
|
h.addEvent(sortButtons, 'click', self.sort);
|
|
},
|
|
items: {
|
|
start: function(values, options) {
|
|
if (options.valueNames) {
|
|
var itemsToIndex = this.get(),
|
|
valueNames = options.valueNames;
|
|
if (options.indexAsync) {
|
|
this.indexAsync(itemsToIndex, valueNames);
|
|
} else {
|
|
this.index(itemsToIndex, valueNames);
|
|
}
|
|
}
|
|
if (values !== undefined) {
|
|
self.add(values);
|
|
}
|
|
},
|
|
get: function() {
|
|
// return h.getByClass('item', self.list);
|
|
var nodes = self.list.childNodes,
|
|
items = [];
|
|
for (var i = 0, il = nodes.length; i < il; i++) {
|
|
// Only textnodes have a data attribute
|
|
if (nodes[i].data === undefined) {
|
|
items.push(nodes[i]);
|
|
}
|
|
}
|
|
return items;
|
|
},
|
|
index: function(itemElements, valueNames) {
|
|
for (var i = 0, il = itemElements.length; i < il; i++) {
|
|
self.items.push(new Item(valueNames, itemElements[i]));
|
|
}
|
|
},
|
|
indexAsync: function(itemElements, valueNames) {
|
|
var itemsToIndex = itemElements.splice(0, 100); // TODO: If < 100 items, what happens in IE etc?
|
|
this.index(itemsToIndex, valueNames);
|
|
if (itemElements.length > 0) {
|
|
setTimeout(function() {
|
|
init.items.indexAsync(itemElements, valueNames);
|
|
},
|
|
10);
|
|
} else {
|
|
self.update();
|
|
// TODO: Add indexed callback
|
|
}
|
|
}
|
|
},
|
|
plugins: function(plugins) {
|
|
var locals = {
|
|
templater: templater,
|
|
init: init,
|
|
initialItems: initialItems,
|
|
Item: Item,
|
|
Templater: Templater,
|
|
sortButtons: sortButtons,
|
|
events: events,
|
|
reset: reset
|
|
};
|
|
for (var i = 0; i < plugins.length; i++) {
|
|
plugins[i][1] = plugins[i][1] || {};
|
|
var pluginName = plugins[i][1].name || plugins[i][0];
|
|
self[pluginName] = self.plugins[plugins[i][0]].call(self, locals, plugins[i][1]);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
* Add object to list
|
|
*/
|
|
this.add = function(values, callback) {
|
|
if (callback) {
|
|
addAsync(values, callback);
|
|
}
|
|
var added = [],
|
|
notCreate = false;
|
|
if (values[0] === undefined){
|
|
values = [values];
|
|
}
|
|
for (var i = 0, il = values.length; i < il; i++) {
|
|
var item = null;
|
|
if (values[i] instanceof Item) {
|
|
item = values[i];
|
|
item.reload();
|
|
} else {
|
|
notCreate = (self.items.length > self.page) ? true : false;
|
|
item = new Item(values[i], undefined, notCreate);
|
|
}
|
|
self.items.push(item);
|
|
added.push(item);
|
|
}
|
|
self.update();
|
|
return added;
|
|
};
|
|
|
|
/*
|
|
* Adds items asynchronous to the list, good for adding huge amount of
|
|
* data. Defaults to add 100 items a time
|
|
*/
|
|
var addAsync = function(values, callback, items) {
|
|
var valuesToAdd = values.splice(0, 100);
|
|
items = items || [];
|
|
items = items.concat(self.add(valuesToAdd));
|
|
if (values.length > 0) {
|
|
setTimeout(function() {
|
|
addAsync(values, callback, items);
|
|
}, 10);
|
|
} else {
|
|
self.update();
|
|
callback(items);
|
|
}
|
|
};
|
|
|
|
this.show = function(i, page) {
|
|
this.i = i;
|
|
this.page = page;
|
|
self.update();
|
|
};
|
|
|
|
/* Removes object from list.
|
|
* Loops through the list and removes objects where
|
|
* property "valuename" === value
|
|
*/
|
|
this.remove = function(valueName, value, options) {
|
|
var found = 0;
|
|
for (var i = 0, il = self.items.length; i < il; i++) {
|
|
if (self.items[i].values()[valueName] == value) {
|
|
templater.remove(self.items[i], options);
|
|
self.items.splice(i,1);
|
|
il--;
|
|
found++;
|
|
}
|
|
}
|
|
self.update();
|
|
return found;
|
|
};
|
|
|
|
/* Gets the objects in the list which
|
|
* property "valueName" === value
|
|
*/
|
|
this.get = function(valueName, value) {
|
|
var matchedItems = [];
|
|
for (var i = 0, il = self.items.length; i < il; i++) {
|
|
var item = self.items[i];
|
|
if (item.values()[valueName] == value) {
|
|
matchedItems.push(item);
|
|
}
|
|
}
|
|
if (matchedItems.length == 0) {
|
|
return null;
|
|
} else if (matchedItems.length == 1) {
|
|
return matchedItems[0];
|
|
} else {
|
|
return matchedItems;
|
|
}
|
|
};
|
|
|
|
/* Sorts the list.
|
|
* @valueOrEvent Either a JavaScript event object or a valueName
|
|
* @sortFunction (optional) Define if natural sorting does not fullfill your needs
|
|
*/
|
|
this.sort = function(valueName, options) {
|
|
var length = self.items.length,
|
|
value = null,
|
|
target = valueName.target || valueName.srcElement, /* IE have srcElement */
|
|
sorting = '',
|
|
isAsc = false,
|
|
asc = 'asc',
|
|
desc = 'desc',
|
|
options = options || {};
|
|
|
|
if (target === undefined) {
|
|
value = valueName;
|
|
isAsc = options.asc || false;
|
|
} else {
|
|
value = h.getAttribute(target, 'data-sort');
|
|
isAsc = h.hasClass(target, asc) ? false : true;
|
|
}
|
|
for (var i = 0, il = sortButtons.length; i < il; i++) {
|
|
h.removeClass(sortButtons[i], asc);
|
|
h.removeClass(sortButtons[i], desc);
|
|
}
|
|
if (isAsc) {
|
|
if (target !== undefined) {
|
|
h.addClass(target, asc);
|
|
}
|
|
isAsc = true;
|
|
} else {
|
|
if (target !== undefined) {
|
|
h.addClass(target, desc);
|
|
}
|
|
isAsc = false;
|
|
}
|
|
|
|
if (options.sortFunction) {
|
|
options.sortFunction = options.sortFunction;
|
|
} else {
|
|
options.sortFunction = function(a, b) {
|
|
return h.sorter.alphanum(a.values()[value].toLowerCase(), b.values()[value].toLowerCase(), isAsc);
|
|
};
|
|
}
|
|
self.items.sort(options.sortFunction);
|
|
self.update();
|
|
};
|
|
|
|
/*
|
|
* Searches the list after values with content "searchStringOrEvent".
|
|
* The columns parameter defines if all values should be included in the search,
|
|
* defaults to undefined which means "all".
|
|
*/
|
|
this.search = function(searchString, columns) {
|
|
self.i = 1; // Reset paging
|
|
var matching = [],
|
|
found,
|
|
item,
|
|
text,
|
|
values,
|
|
is,
|
|
columns = (columns === undefined) ? self.items[0].values() : columns,
|
|
searchString = (searchString === undefined) ? "" : searchString,
|
|
target = searchString.target || searchString.srcElement; /* IE have srcElement */
|
|
|
|
searchString = (target === undefined) ? (""+searchString).toLowerCase() : ""+target.value.toLowerCase();
|
|
is = self.items;
|
|
// Escape regular expression characters
|
|
searchString = searchString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
|
|
templater.clear();
|
|
if (searchString === "" ) {
|
|
reset.search();
|
|
self.searched = false;
|
|
self.update();
|
|
} else {
|
|
self.searched = true;
|
|
|
|
for (var k = 0, kl = is.length; k < kl; k++) {
|
|
found = false;
|
|
item = is[k];
|
|
values = item.values();
|
|
|
|
for(var j in columns) {
|
|
if(values.hasOwnProperty(j) && columns[j] !== null) {
|
|
text = (values[j] != null) ? values[j].toString().toLowerCase() : "";
|
|
if ((searchString !== "") && (text.search(searchString) > -1)) {
|
|
found = true;
|
|
}
|
|
}
|
|
}
|
|
if (found) {
|
|
item.found = true;
|
|
matching.push(item);
|
|
} else {
|
|
item.found = false;
|
|
}
|
|
}
|
|
self.update();
|
|
}
|
|
return self.visibleItems;
|
|
};
|
|
|
|
/*
|
|
* Filters the list. If filterFunction() returns False hides the Item.
|
|
* if filterFunction == false are the filter removed
|
|
*/
|
|
this.filter = function(filterFunction) {
|
|
self.i = 1; // Reset paging
|
|
reset.filter();
|
|
if (filterFunction === undefined) {
|
|
self.filtered = false;
|
|
} else {
|
|
self.filtered = true;
|
|
var is = self.items;
|
|
for (var i = 0, il = is.length; i < il; i++) {
|
|
var item = is[i];
|
|
if (filterFunction(item)) {
|
|
item.filtered = true;
|
|
} else {
|
|
item.filtered = false;
|
|
}
|
|
}
|
|
}
|
|
self.update();
|
|
return self.visibleItems;
|
|
};
|
|
|
|
/*
|
|
* Get size of the list
|
|
*/
|
|
this.size = function() {
|
|
return self.items.length;
|
|
};
|
|
|
|
/*
|
|
* Removes all items from the list
|
|
*/
|
|
this.clear = function() {
|
|
templater.clear();
|
|
self.items = [];
|
|
};
|
|
|
|
this.on = function(event, callback) {
|
|
events[event].push(callback);
|
|
};
|
|
|
|
var trigger = function(event) {
|
|
var i = events[event].length;
|
|
while(i--) {
|
|
events[event][i]();
|
|
}
|
|
};
|
|
|
|
var reset = {
|
|
filter: function() {
|
|
var is = self.items,
|
|
il = is.length;
|
|
while (il--) {
|
|
is[il].filtered = false;
|
|
}
|
|
},
|
|
search: function() {
|
|
var is = self.items,
|
|
il = is.length;
|
|
while (il--) {
|
|
is[il].found = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
this.update = function() {
|
|
var is = self.items,
|
|
il = is.length;
|
|
|
|
self.visibleItems = [];
|
|
self.matchingItems = [];
|
|
templater.clear();
|
|
for (var i = 0; i < il; i++) {
|
|
if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
|
|
is[i].show();
|
|
self.visibleItems.push(is[i]);
|
|
self.matchingItems.push(is[i]);
|
|
} else if (is[i].matching()) {
|
|
self.matchingItems.push(is[i]);
|
|
is[i].hide();
|
|
} else {
|
|
is[i].hide();
|
|
}
|
|
}
|
|
trigger('updated');
|
|
};
|
|
|
|
Item = function(initValues, element, notCreate) {
|
|
var item = this,
|
|
values = {};
|
|
|
|
this.found = false; // Show if list.searched == true and this.found == true
|
|
this.filtered = false;// Show if list.filtered == true and this.filtered == true
|
|
|
|
var init = function(initValues, element, notCreate) {
|
|
if (element === undefined) {
|
|
if (notCreate) {
|
|
item.values(initValues, notCreate);
|
|
} else {
|
|
item.values(initValues);
|
|
}
|
|
} else {
|
|
item.elm = element;
|
|
var values = templater.get(item, initValues);
|
|
item.values(values);
|
|
}
|
|
};
|
|
this.values = function(newValues, notCreate) {
|
|
if (newValues !== undefined) {
|
|
for(var name in newValues) {
|
|
values[name] = newValues[name];
|
|
}
|
|
if (notCreate !== true) {
|
|
templater.set(item, item.values());
|
|
}
|
|
} else {
|
|
return values;
|
|
}
|
|
};
|
|
this.show = function() {
|
|
templater.show(item);
|
|
};
|
|
this.hide = function() {
|
|
templater.hide(item);
|
|
};
|
|
this.matching = function() {
|
|
return (
|
|
(self.filtered && self.searched && item.found && item.filtered) ||
|
|
(self.filtered && !self.searched && item.filtered) ||
|
|
(!self.filtered && self.searched && item.found) ||
|
|
(!self.filtered && !self.searched)
|
|
);
|
|
};
|
|
this.visible = function() {
|
|
return (item.elm.parentNode) ? true : false;
|
|
};
|
|
init(initValues, element, notCreate);
|
|
};
|
|
|
|
/* Templater with different kinds of template engines.
|
|
* All engines have these methods
|
|
* - reload(item)
|
|
* - remove(item)
|
|
*/
|
|
Templater = function(list, settings) {
|
|
if (settings.engine === undefined) {
|
|
settings.engine = "standard";
|
|
} else {
|
|
settings.engine = settings.engine.toLowerCase();
|
|
}
|
|
return new self.constructor.prototype.templateEngines[settings.engine](list, settings);
|
|
};
|
|
|
|
init.start(values, options);
|
|
};
|
|
|
|
List.prototype.templateEngines = {};
|
|
List.prototype.plugins = {};
|
|
|
|
List.prototype.templateEngines.standard = function(list, settings) {
|
|
var listSource = h.getByClass(settings.listClass, list.listContainer, true),
|
|
itemSource = getItemSource(settings.item),
|
|
templater = this;
|
|
|
|
function getItemSource(item) {
|
|
if (item === undefined) {
|
|
var nodes = listSource.childNodes,
|
|
items = [];
|
|
|
|
for (var i = 0, il = nodes.length; i < il; i++) {
|
|
// Only textnodes have a data attribute
|
|
if (nodes[i].data === undefined) {
|
|
return nodes[i];
|
|
}
|
|
}
|
|
return null;
|
|
} else if (item.indexOf("<") !== -1) { // Try create html element of list, do not work for tables!!
|
|
var div = document.createElement('div');
|
|
div.innerHTML = item;
|
|
return div.firstChild;
|
|
} else {
|
|
return document.getElementById(settings.item);
|
|
}
|
|
}
|
|
|
|
var ensure = {
|
|
created: function(item) {
|
|
if (item.elm === undefined) {
|
|
templater.create(item);
|
|
}
|
|
}
|
|
};
|
|
|
|
/* Get values from element */
|
|
this.get = function(item, valueNames) {
|
|
ensure.created(item);
|
|
var values = {};
|
|
for(var i = 0, il = valueNames.length; i < il; i++) {
|
|
var elm = h.getByClass(valueNames[i], item.elm, true);
|
|
values[valueNames[i]] = elm ? elm.innerHTML : "";
|
|
}
|
|
return values;
|
|
};
|
|
|
|
/* Sets values at element */
|
|
this.set = function(item, values) {
|
|
ensure.created(item);
|
|
for(var v in values) {
|
|
if (values.hasOwnProperty(v)) {
|
|
// TODO speed up if possible
|
|
var elm = h.getByClass(v, item.elm, true);
|
|
if (elm) {
|
|
elm.innerHTML = values[v];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
this.create = function(item) {
|
|
if (item.elm !== undefined) {
|
|
return;
|
|
}
|
|
/* If item source does not exists, use the first item in list as
|
|
source for new items */
|
|
var newItem = itemSource.cloneNode(true);
|
|
newItem.id = "";
|
|
item.elm = newItem;
|
|
templater.set(item, item.values());
|
|
};
|
|
this.remove = function(item) {
|
|
listSource.removeChild(item.elm);
|
|
};
|
|
this.show = function(item) {
|
|
ensure.created(item);
|
|
listSource.appendChild(item.elm);
|
|
};
|
|
this.hide = function(item) {
|
|
if (item.elm !== undefined && item.elm.parentNode === listSource) {
|
|
listSource.removeChild(item.elm);
|
|
}
|
|
};
|
|
this.clear = function() {
|
|
/* .innerHTML = ''; fucks up IE */
|
|
if (listSource.hasChildNodes()) {
|
|
while (listSource.childNodes.length >= 1)
|
|
{
|
|
listSource.removeChild(listSource.firstChild);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
* These helper functions are not written by List.js author Jonny (they may have been
|
|
* adjusted, thought).
|
|
*/
|
|
h = {
|
|
/*
|
|
* Cross browser getElementsByClassName, which uses native
|
|
* if it exists. Modified version of Dustin Diaz function:
|
|
* http://www.dustindiaz.com/getelementsbyclass
|
|
*/
|
|
getByClass: (function() {
|
|
if (document.getElementsByClassName) {
|
|
return function(searchClass,node,single) {
|
|
if (single) {
|
|
return node.getElementsByClassName(searchClass)[0];
|
|
} else {
|
|
return node.getElementsByClassName(searchClass);
|
|
}
|
|
};
|
|
} else {
|
|
return function(searchClass,node,single) {
|
|
var classElements = [],
|
|
tag = '*';
|
|
if (node == null) {
|
|
node = document;
|
|
}
|
|
var els = node.getElementsByTagName(tag);
|
|
var elsLen = els.length;
|
|
var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
|
|
for (var i = 0, j = 0; i < elsLen; i++) {
|
|
if ( pattern.test(els[i].className) ) {
|
|
if (single) {
|
|
return els[i];
|
|
} else {
|
|
classElements[j] = els[i];
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
return classElements;
|
|
};
|
|
}
|
|
})(),
|
|
/* (elm, 'event' callback) Source: http://net.tutsplus.com/tutorials/javascript-ajax/javascript-from-null-cross-browser-event-binding/ */
|
|
addEvent: (function( window, document ) {
|
|
if ( document.addEventListener ) {
|
|
return function( elem, type, cb ) {
|
|
if ((elem && !(elem instanceof Array) && !elem.length && !h.isNodeList(elem) && (elem.length !== 0)) || elem === window ) {
|
|
elem.addEventListener(type, cb, false );
|
|
} else if ( elem && elem[0] !== undefined ) {
|
|
var len = elem.length;
|
|
for ( var i = 0; i < len; i++ ) {
|
|
h.addEvent(elem[i], type, cb);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
else if ( document.attachEvent ) {
|
|
return function ( elem, type, cb ) {
|
|
if ((elem && !(elem instanceof Array) && !elem.length && !h.isNodeList(elem) && (elem.length !== 0)) || elem === window ) {
|
|
elem.attachEvent( 'on' + type, function() { return cb.call(elem, window.event); } );
|
|
} else if ( elem && elem[0] !== undefined ) {
|
|
var len = elem.length;
|
|
for ( var i = 0; i < len; i++ ) {
|
|
h.addEvent( elem[i], type, cb );
|
|
}
|
|
}
|
|
};
|
|
}
|
|
})(this, document),
|
|
/* (elm, attribute) Source: http://stackoverflow.com/questions/3755227/cross-browser-javascript-getattribute-method */
|
|
getAttribute: function(ele, attr) {
|
|
var result = (ele.getAttribute && ele.getAttribute(attr)) || null;
|
|
if( !result ) {
|
|
var attrs = ele.attributes;
|
|
var length = attrs.length;
|
|
for(var i = 0; i < length; i++) {
|
|
if (attr[i] !== undefined) {
|
|
if(attr[i].nodeName === attr) {
|
|
result = attr[i].nodeValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
/* http://stackoverflow.com/questions/7238177/detect-htmlcollection-nodelist-in-javascript */
|
|
isNodeList: function(nodes) {
|
|
var result = Object.prototype.toString.call(nodes);
|
|
if (typeof nodes === 'object' && /^\[object (HTMLCollection|NodeList|Object)\]$/.test(result) && (nodes.length == 0 || (typeof nodes[0] === "object" && nodes[0].nodeType > 0))) {
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
hasClass: function(ele, classN) {
|
|
var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
|
|
return (classes.search(classN) > -1);
|
|
},
|
|
addClass: function(ele, classN) {
|
|
if (!this.hasClass(ele, classN)) {
|
|
var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
|
|
classes = classes + ' ' + classN + ' ';
|
|
classes = classes.replace(/\s{2,}/g, ' ');
|
|
ele.setAttribute('class', classes);
|
|
}
|
|
},
|
|
removeClass: function(ele, classN) {
|
|
if (this.hasClass(ele, classN)) {
|
|
var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
|
|
classes = classes.replace(classN, '');
|
|
ele.setAttribute('class', classes);
|
|
}
|
|
},
|
|
/*
|
|
* The sort function. From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
|
|
*/
|
|
sorter: {
|
|
alphanum: function(a,b,asc) {
|
|
if (a === undefined || a === null) {
|
|
a = "";
|
|
}
|
|
if (b === undefined || b === null) {
|
|
b = "";
|
|
}
|
|
a = a.toString().replace(/&(lt|gt);/g, function (strMatch, p1){
|
|
return (p1 == "lt")? "<" : ">";
|
|
});
|
|
a = a.replace(/<\/?[^>]+(>|$)/g, "");
|
|
|
|
b = b.toString().replace(/&(lt|gt);/g, function (strMatch, p1){
|
|
return (p1 == "lt")? "<" : ">";
|
|
});
|
|
b = b.replace(/<\/?[^>]+(>|$)/g, "");
|
|
var aa = this.chunkify(a);
|
|
var bb = this.chunkify(b);
|
|
|
|
for (var x = 0; aa[x] && bb[x]; x++) {
|
|
if (aa[x] !== bb[x]) {
|
|
var c = Number(aa[x]), d = Number(bb[x]);
|
|
if (asc) {
|
|
if (c == aa[x] && d == bb[x]) {
|
|
return c - d;
|
|
} else {
|
|
return (aa[x] > bb[x]) ? 1 : -1;
|
|
}
|
|
} else {
|
|
if (c == aa[x] && d == bb[x]) {
|
|
return d-c;//c - d;
|
|
} else {
|
|
return (aa[x] > bb[x]) ? -1 : 1; //(aa[x] > bb[x]) ? 1 : -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return aa.length - bb.length;
|
|
},
|
|
chunkify: function(t) {
|
|
var tz = [], x = 0, y = -1, n = 0, i, j;
|
|
|
|
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
|
|
var m = (i == 45 || i == 46 || (i >=48 && i <= 57));
|
|
if (m !== n) {
|
|
tz[++y] = "";
|
|
n = m;
|
|
}
|
|
tz[y] += j;
|
|
}
|
|
return tz;
|
|
}
|
|
}
|
|
};
|
|
|
|
window.List = List;
|
|
window.ListJsHelpers = h;
|
|
})(window);
|