From 3a948e9b7396738981dd37efbb5bbe6371636952 Mon Sep 17 00:00:00 2001 From: Julius Date: Fri, 4 Oct 2013 18:28:45 +0200 Subject: [PATCH] Move list.js extensions to plugins --- Gemfile | 2 +- Gemfile.lock | 3 + app/assets/javascripts/application.js | 3 +- app/assets/javascripts/list.customized.js | 69 -- app/assets/javascripts/list.delay.js | 50 ++ app/assets/javascripts/list.reset.js | 42 ++ app/views/group_orders/_form.html.haml | 6 +- vendor/assets/javascripts/list.js | 775 ---------------------- 8 files changed, 102 insertions(+), 848 deletions(-) delete mode 100644 app/assets/javascripts/list.customized.js create mode 100644 app/assets/javascripts/list.delay.js create mode 100644 app/assets/javascripts/list.reset.js delete mode 100644 vendor/assets/javascripts/list.js diff --git a/Gemfile b/Gemfile index e80314ed..f2dbd228 100644 --- a/Gemfile +++ b/Gemfile @@ -19,7 +19,7 @@ end gem 'jquery-rails' gem 'select2-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 'prawn' diff --git a/Gemfile.lock b/Gemfile.lock index c816b8c4..61e2fc6c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -192,6 +192,8 @@ GEM activesupport (= 3.2.13) bundler (~> 1.0) railties (= 3.2.13) + rails-assets-listjs (0.2.0.beta.4) + railties (>= 3.1) rails-settings-cached (0.2.4) rails (>= 3.0.0) railties (3.2.13) @@ -332,6 +334,7 @@ DEPENDENCIES prawn quiet_assets rails (~> 3.2.9) + rails-assets-listjs (= 0.2.0.beta.4) rails-settings-cached (= 0.2.4) resque rspec-core diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index c684cf31..b8dc87e8 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,7 +10,8 @@ //= require jquery.observe_field //= require list //= require list.unlist -//= require list.customized +//= require list.delay +//= require list.reset //= require rails.validations //= require_self //= require ordering diff --git a/app/assets/javascripts/list.customized.js b/app/assets/javascripts/list.customized.js deleted file mode 100644 index da79cbe1..00000000 --- a/app/assets/javascripts/list.customized.js +++ /dev/null @@ -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); diff --git a/app/assets/javascripts/list.delay.js b/app/assets/javascripts/list.delay.js new file mode 100644 index 00000000..72ac425c --- /dev/null +++ b/app/assets/javascripts/list.delay.js @@ -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); diff --git a/app/assets/javascripts/list.reset.js b/app/assets/javascripts/list.reset.js new file mode 100644 index 00000000..9482f32c --- /dev/null +++ b/app/assets/javascripts/list.reset.js @@ -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); diff --git a/app/views/group_orders/_form.html.haml b/app/views/group_orders/_form.html.haml index fbb4da00..3c6048c0 100644 --- a/app/views/group_orders/_form.html.haml +++ b/app/views/group_orders/_form.html.haml @@ -8,7 +8,9 @@ setToleranceBehaviour(#{FoodsoftConfig[:tolerance_is_costly]}); setStockit(#{@order.stockit?}); // 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 @@ -45,7 +47,7 @@ .well.clear .form-search .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')} %i.icon.icon-remove diff --git a/vendor/assets/javascripts/list.js b/vendor/assets/javascripts/list.js deleted file mode 100644 index 44ce6879..00000000 --- a/vendor/assets/javascripts/list.js +++ /dev/null @@ -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);