Move list.js extensions to plugins
This commit is contained in:
parent
26e207aeb1
commit
3a948e9b73
8 changed files with 102 additions and 848 deletions
2
Gemfile
2
Gemfile
|
@ -19,7 +19,7 @@ end
|
||||||
gem 'jquery-rails'
|
gem 'jquery-rails'
|
||||||
gem 'select2-rails'
|
gem 'select2-rails'
|
||||||
gem 'bootstrap-datepicker-rails'
|
gem 'bootstrap-datepicker-rails'
|
||||||
|
gem 'rails-assets-listjs', '0.2.0.beta.4' # remember to maintain list.*.js plugins and template engines on update
|
||||||
|
|
||||||
gem 'mysql2'
|
gem 'mysql2'
|
||||||
gem 'prawn'
|
gem 'prawn'
|
||||||
|
|
|
@ -192,6 +192,8 @@ GEM
|
||||||
activesupport (= 3.2.13)
|
activesupport (= 3.2.13)
|
||||||
bundler (~> 1.0)
|
bundler (~> 1.0)
|
||||||
railties (= 3.2.13)
|
railties (= 3.2.13)
|
||||||
|
rails-assets-listjs (0.2.0.beta.4)
|
||||||
|
railties (>= 3.1)
|
||||||
rails-settings-cached (0.2.4)
|
rails-settings-cached (0.2.4)
|
||||||
rails (>= 3.0.0)
|
rails (>= 3.0.0)
|
||||||
railties (3.2.13)
|
railties (3.2.13)
|
||||||
|
@ -332,6 +334,7 @@ DEPENDENCIES
|
||||||
prawn
|
prawn
|
||||||
quiet_assets
|
quiet_assets
|
||||||
rails (~> 3.2.9)
|
rails (~> 3.2.9)
|
||||||
|
rails-assets-listjs (= 0.2.0.beta.4)
|
||||||
rails-settings-cached (= 0.2.4)
|
rails-settings-cached (= 0.2.4)
|
||||||
resque
|
resque
|
||||||
rspec-core
|
rspec-core
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
//= require jquery.observe_field
|
//= require jquery.observe_field
|
||||||
//= require list
|
//= require list
|
||||||
//= require list.unlist
|
//= require list.unlist
|
||||||
//= require list.customized
|
//= require list.delay
|
||||||
|
//= require list.reset
|
||||||
//= require rails.validations
|
//= require rails.validations
|
||||||
//= require_self
|
//= require_self
|
||||||
//= require ordering
|
//= require ordering
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
(function(window, undefined) {
|
|
||||||
|
|
||||||
var CustomizedList = function(id, options, values) {
|
|
||||||
var self = this;
|
|
||||||
var h = window.ListJsHelpers;
|
|
||||||
|
|
||||||
this.searchTimeout = undefined;
|
|
||||||
|
|
||||||
var init = {
|
|
||||||
start: function(id, options, values) {
|
|
||||||
this.defaults(options);
|
|
||||||
this.list(id, options, values);
|
|
||||||
this.callbacks(options);
|
|
||||||
this.onload(options);
|
|
||||||
},
|
|
||||||
defaults: function(options) {
|
|
||||||
options.delayedSearchClass = options.delayedSearchClass || 'delayed-search';
|
|
||||||
options.delayedSearchTime = options.delayedSearchTime || 500;
|
|
||||||
options.highlightClass = options.highlightClass || 'btn-primary';
|
|
||||||
options.resetSearchClass = options.resetSearchClass || 'reset-search';
|
|
||||||
},
|
|
||||||
list: function(id, options, values) {
|
|
||||||
self.list = new window.List(id, options, values);
|
|
||||||
},
|
|
||||||
callbacks: function(options) {
|
|
||||||
var resetSearchButton = h.getByClass(options.resetSearchClass, self.list.listContainer);
|
|
||||||
$(resetSearchButton).click(self.resetSearch);
|
|
||||||
self.list.on('updated', self.highlightResetButton);
|
|
||||||
|
|
||||||
var delayedSearchInput = h.getByClass(options.delayedSearchClass, self.list.listContainer);
|
|
||||||
$(delayedSearchInput).keyup(self.searchDelayStart);
|
|
||||||
},
|
|
||||||
onload: function(options) {
|
|
||||||
var initialSearchTerm = $('.' + options.delayedSearchClass + ', .' + options.searchClass, self.list.listContainer).val();
|
|
||||||
if('' != initialSearchTerm) {
|
|
||||||
self.list.search(initialSearchTerm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.searchDelayStart = function(searchString, columns) {
|
|
||||||
// TODO: if keycode corresponds to 'ENTER' ? skip delay
|
|
||||||
clearTimeout(self.searchTimeout);
|
|
||||||
self.searchTimeout = window.setTimeout(function() {self.searchDelayEnd(searchString, columns)}, options.delayedSearchTime);
|
|
||||||
|
|
||||||
var resetSearchButton = h.getByClass(options.resetSearchClass, self.list.listContainer);
|
|
||||||
$(resetSearchButton).removeClass(options.highlightClass);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.searchDelayEnd = function(searchString, columns) {
|
|
||||||
self.list.search(searchString, columns);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.highlightResetButton = function() {
|
|
||||||
var resetSearchButton = h.getByClass(options.resetSearchClass, self.list.listContainer);
|
|
||||||
$(resetSearchButton).toggleClass(options.highlightClass, self.list.searched);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.resetSearch = function() {
|
|
||||||
$('.' + options.delayedSearchClass + ', .' + options.searchClass, self.list.listContainer).val('');
|
|
||||||
self.list.search('');
|
|
||||||
};
|
|
||||||
|
|
||||||
init.start(id, options, values);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.CustomizedList = CustomizedList;
|
|
||||||
|
|
||||||
})(window);
|
|
50
app/assets/javascripts/list.delay.js
Normal file
50
app/assets/javascripts/list.delay.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// for use with listjs 0.2.0
|
||||||
|
// https://github.com/javve/list.js
|
||||||
|
|
||||||
|
(function(window, undefined) {
|
||||||
|
|
||||||
|
window.List.prototype.plugins.delay = function(locals, options) {
|
||||||
|
var list = this;
|
||||||
|
|
||||||
|
this.searchTimeout = undefined;
|
||||||
|
|
||||||
|
var init = {
|
||||||
|
start: function(options) {
|
||||||
|
this.defaults(options);
|
||||||
|
this.callbacks(options);
|
||||||
|
this.onload(options);
|
||||||
|
},
|
||||||
|
defaults: function(options) {
|
||||||
|
options.delayedSearchClass = options.delayedSearchClass || 'delayed-search';
|
||||||
|
options.delayedSearchTime = options.delayedSearchTime || 500;
|
||||||
|
},
|
||||||
|
callbacks: function(options) {
|
||||||
|
$('.' + options.delayedSearchClass, list.listContainer).keyup(list.searchDelayStart);
|
||||||
|
},
|
||||||
|
onload: function(options) {
|
||||||
|
var initialSearchTerm = $('.' + options.delayedSearchClass, list.listContainer).val();
|
||||||
|
if('' != initialSearchTerm) {
|
||||||
|
list.search(initialSearchTerm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.searchDelayStart = function(searchString, columns) {
|
||||||
|
// TODO: if keycode corresponds to 'ENTER' ? skip delay
|
||||||
|
clearTimeout(list.searchTimeout);
|
||||||
|
list.searchTimeout = window.setTimeout(
|
||||||
|
function() {list.searchDelayEnd(searchString, columns)},
|
||||||
|
options.delayedSearchTime
|
||||||
|
);
|
||||||
|
|
||||||
|
$(list.listContainer).trigger('updateComing');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.searchDelayEnd = function(searchString, columns) {
|
||||||
|
list.search(searchString, columns);
|
||||||
|
};
|
||||||
|
|
||||||
|
init.start(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window);
|
42
app/assets/javascripts/list.reset.js
Normal file
42
app/assets/javascripts/list.reset.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// for use with listjs 0.2.0
|
||||||
|
// https://github.com/javve/list.js
|
||||||
|
|
||||||
|
(function(window, undefined) {
|
||||||
|
|
||||||
|
window.List.prototype.plugins.reset = function(locals, options) {
|
||||||
|
var list = this;
|
||||||
|
|
||||||
|
var init = {
|
||||||
|
start: function(options) {
|
||||||
|
this.defaults(options);
|
||||||
|
this.callbacks(options);
|
||||||
|
},
|
||||||
|
defaults: function(options) {
|
||||||
|
options.highlightClass = options.highlightClass || 'btn-primary';
|
||||||
|
options.resetSearchClass = options.resetSearchClass || 'reset-search';
|
||||||
|
options.resettableClass = options.resettableClass || 'resettable';
|
||||||
|
},
|
||||||
|
callbacks: function(options) {
|
||||||
|
$('.' + options.resetSearchClass, list.listContainer).click(list.resetSearch);
|
||||||
|
list.on('updated', list.highlightResetButton);
|
||||||
|
|
||||||
|
$(list.listContainer).on('updateComing', function() {
|
||||||
|
list.highlightResetButton(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.highlightResetButton = function(highlightEnabled) {
|
||||||
|
highlightEnabled = (undefined === highlightEnabled) ? (list.searched) : (highlightEnabled);
|
||||||
|
$('.' + options.resetSearchClass, list.listContainer).toggleClass(options.highlightClass, highlightEnabled);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.resetSearch = function() {
|
||||||
|
$('.' + options.resettableClass, list.listContainer).val('');
|
||||||
|
list.search('');
|
||||||
|
};
|
||||||
|
|
||||||
|
init.start(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window);
|
|
@ -8,7 +8,9 @@
|
||||||
setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]});
|
setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]});
|
||||||
setStockit(#{@order.stockit?});
|
setStockit(#{@order.stockit?});
|
||||||
// create List for search-feature (using list.js, http://listjs.com)
|
// create List for search-feature (using list.js, http://listjs.com)
|
||||||
new CustomizedList(document.body, { valueNames: ['name'], engine: 'unlist' });
|
var listjsResetPlugin = ['reset', {highlightClass: 'btn-primary'}];
|
||||||
|
var listjsDelayPlugin = ['delay', {delayedSearchTime: 500}];
|
||||||
|
new List(document.body, { valueNames: ['name'], engine: 'unlist', plugins: [listjsResetPlugin, listjsDelayPlugin] });
|
||||||
});
|
});
|
||||||
|
|
||||||
- title t('.title'), false
|
- title t('.title'), false
|
||||||
|
@ -45,7 +47,7 @@
|
||||||
.well.clear
|
.well.clear
|
||||||
.form-search
|
.form-search
|
||||||
.input-append
|
.input-append
|
||||||
= text_field_tag :article, params[:article], placeholder: t('.search_article'), class: 'search-query delayed-search'
|
= text_field_tag :article, params[:article], placeholder: t('.search_article'), class: 'search-query delayed-search resettable'
|
||||||
%button.add-on.btn.reset-search{:type => :button, :title => t('.reset_article_search')}
|
%button.add-on.btn.reset-search{:type => :button, :title => t('.reset_article_search')}
|
||||||
%i.icon.icon-remove
|
%i.icon.icon-remove
|
||||||
|
|
||||||
|
|
775
vendor/assets/javascripts/list.js
vendored
775
vendor/assets/javascripts/list.js
vendored
|
@ -1,775 +0,0 @@
|
||||||
/*
|
|
||||||
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);
|
|
Loading…
Reference in a new issue