rails-assets-listjs 0.2.0.beta.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails-assets-listjs.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Thomas Klemm
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Rails::Assets::Listjs
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rails-assets-listjs'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rails-assets-listjs
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,10 @@
1
+ require "rails-assets-listjs/version"
2
+
3
+ module Rails
4
+ module Assets
5
+ module Listjs
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module Rails
2
+ module Assets
3
+ module Listjs
4
+ VERSION = "0.2.0.beta.4"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rails-assets-listjs/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "rails-assets-listjs"
8
+ gem.version = Rails::Assets::Listjs::VERSION
9
+ gem.authors = ["Thomas Klemm"]
10
+ gem.email = ["github@tklemm.eu"]
11
+ gem.description = %q{List.js - packaged by RailsAssets for the Rails Asset Pipeline}
12
+ gem.summary = %q{List.js - packaged by RailsAssets for the Rails Asset Pipeline}
13
+ gem.homepage = "http://www.railsassets.com"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_dependency "railties", ">= 3.1"
19
+ end
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Locate the best instance of 'pattern' in 'text' using the Bitap algorithm.
3
+ *
4
+ * This method is a based on: Diff Match and Patch
5
+ * http://code.google.com/p/google-diff-match-patch/
6
+ * Author: fraser@google.com (Neil Fraser)
7
+ * Modifications by: l.vanegeraat@gmail.com (Luuk van Egeraat)
8
+ * Plugin by: jonny.stromberg@gmail.com (Jonny Strömberg / @javve)
9
+ *
10
+ * Licensed under the Apache License
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ */
14
+
15
+ List.prototype.plugins.fuzzySearch = function(locals, options) {
16
+ var self = this;
17
+ var searchFunction = function(text, pattern, options) {
18
+ // Aproximately where in the text is the pattern expected to be found?
19
+ var Match_Location = options.location || 0;
20
+
21
+ //Determines how close the match must be to the fuzzy location (specified above). An exact letter match which is 'distance' characters away from the fuzzy location would score as a complete mismatch. A distance of '0' requires the match be at the exact location specified, a threshold of '1000' would require a perfect match to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.
22
+ var Match_Distance = options.distance || 100;
23
+
24
+ // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match (of both letters and location), a threshold of '1.0' would match anything.
25
+ var Match_Threshold = options.threshold || 0.4;
26
+
27
+ if (pattern === text) return true; // Exact match
28
+ if (pattern.length > 32) return false; // This algorithm cannot be used
29
+
30
+ // Set starting location at beginning text and initialise the alphabet.
31
+ var loc = Match_Location,
32
+ s = (function() {
33
+ var q = {};
34
+
35
+ for (var i = 0; i < pattern.length; i++) {
36
+ q[pattern.charAt(i)] = 0;
37
+ }
38
+
39
+ for (var i = 0; i < pattern.length; i++) {
40
+ q[pattern.charAt(i)] |= 1 << (pattern.length - i - 1);
41
+ }
42
+
43
+ return q;
44
+ }());
45
+
46
+ // Compute and return the score for a match with e errors and x location.
47
+ // Accesses loc and pattern through being a closure.
48
+
49
+ function match_bitapScore_(e, x) {
50
+ var accuracy = e / pattern.length,
51
+ proximity = Math.abs(loc - x);
52
+
53
+ if (!Match_Distance) {
54
+ // Dodge divide by zero error.
55
+ return proximity ? 1.0 : accuracy;
56
+ }
57
+ return accuracy + (proximity / Match_Distance);
58
+ }
59
+
60
+ var score_threshold = Match_Threshold, // Highest score beyond which we give up.
61
+ best_loc = text.indexOf(pattern, loc); // Is there a nearby exact match? (speedup)
62
+
63
+ if (best_loc != -1) {
64
+ score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold);
65
+ // What about in the other direction? (speedup)
66
+ best_loc = text.lastIndexOf(pattern, loc + pattern.length);
67
+
68
+ if (best_loc != -1) {
69
+ score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold);
70
+ }
71
+ }
72
+
73
+ // Initialise the bit arrays.
74
+ var matchmask = 1 << (pattern.length - 1);
75
+ best_loc = -1;
76
+
77
+ var bin_min, bin_mid;
78
+ var bin_max = pattern.length + text.length;
79
+ var last_rd;
80
+ for (var d = 0; d < pattern.length; d++) {
81
+ // Scan for the best match; each iteration allows for one more error.
82
+ // Run a binary search to determine how far from 'loc' we can stray at this
83
+ // error level.
84
+ bin_min = 0;
85
+ bin_mid = bin_max;
86
+ while (bin_min < bin_mid) {
87
+ if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) {
88
+ bin_min = bin_mid;
89
+ } else {
90
+ bin_max = bin_mid;
91
+ }
92
+ bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min);
93
+ }
94
+ // Use the result from this iteration as the maximum for the next.
95
+ bin_max = bin_mid;
96
+ var start = Math.max(1, loc - bin_mid + 1);
97
+ var finish = Math.min(loc + bin_mid, text.length) + pattern.length;
98
+
99
+ var rd = Array(finish + 2);
100
+ rd[finish + 1] = (1 << d) - 1;
101
+ for (var j = finish; j >= start; j--) {
102
+ // The alphabet (s) is a sparse hash, so the following line generates
103
+ // warnings.
104
+ var charMatch = s[text.charAt(j - 1)];
105
+ if (d === 0) { // First pass: exact match.
106
+ rd[j] = ((rd[j + 1] << 1) | 1) & charMatch;
107
+ } else { // Subsequent passes: fuzzy match.
108
+ rd[j] = (((rd[j + 1] << 1) | 1) & charMatch) |
109
+ (((last_rd[j + 1] | last_rd[j]) << 1) | 1) |
110
+ last_rd[j + 1];
111
+ }
112
+ if (rd[j] & matchmask) {
113
+ var score = match_bitapScore_(d, j - 1);
114
+ // This match will almost certainly be better than any existing match.
115
+ // But check anyway.
116
+ if (score <= score_threshold) {
117
+ // Told you so.
118
+ score_threshold = score;
119
+ best_loc = j - 1;
120
+ if (best_loc > loc) {
121
+ // When passing loc, don't exceed our current distance from loc.
122
+ start = Math.max(1, 2 * loc - best_loc);
123
+ } else {
124
+ // Already passed loc, downhill from here on in.
125
+ break;
126
+ }
127
+ }
128
+ }
129
+ }
130
+ // No hope for a (better) match at greater error levels.
131
+ if (match_bitapScore_(d + 1, loc) > score_threshold) {
132
+ break;
133
+ }
134
+ last_rd = rd;
135
+ }
136
+ return (best_loc < 0) ? false : true;
137
+ };
138
+
139
+
140
+ return (function() {
141
+ var func = function(searchString, columns) {
142
+ self.i = 1; // Reset paging
143
+ var searchArguments,
144
+ foundArgument,
145
+ matching = [],
146
+ found,
147
+ item,
148
+ text,
149
+ values,
150
+ is,
151
+ multiSearch = (typeof options.multiSearch !== 'boolean') ? true : options.multiSearch,
152
+ columns = (columns === undefined) ? self.items[0].values() : columns,
153
+ searchString = (searchString === undefined) ? "" : searchString,
154
+ target = searchString.target || searchString.srcElement; /* IE have srcElement */
155
+
156
+ searchString = (target === undefined) ? (""+searchString).toLowerCase() : ""+target.value.toLowerCase();
157
+ is = self.items;
158
+
159
+ // Substract arguments from the searchString or put searchString as only argument
160
+ searchArguments = multiSearch ? searchString.replace(/ +$/, '').split(/ +/) : [searchString];
161
+
162
+ locals.templater.clear();
163
+ if (searchString === "") {
164
+ locals.reset.search();
165
+ self.searched = false;
166
+ self.update();
167
+ } else {
168
+ self.searched = true;
169
+
170
+ for (var k = 0, kl = is.length; k < kl; k++) {
171
+ found = true;
172
+ item = is[k];
173
+ values = item.values();
174
+
175
+ for(var i = 0; i < searchArguments.length; i++) {
176
+ foundArgument = false;
177
+
178
+ for(var j in columns) {
179
+ if(values.hasOwnProperty(j) && columns[j] !== null) {
180
+ text = (values[j] != null) ? values[j].toString().toLowerCase() : "";
181
+ if (searchFunction(text, searchArguments[i], options)) {
182
+ foundArgument = true;
183
+ }
184
+ }
185
+ }
186
+ if(!foundArgument) found = false;
187
+ }
188
+ if (found) {
189
+ item.found = true;
190
+ matching.push(item);
191
+ } else {
192
+ item.found = false;
193
+ }
194
+ }
195
+ self.update();
196
+ }
197
+ return self.visibleItems;
198
+ },
199
+ timeout;
200
+
201
+ return function() {
202
+ var context = this, args = arguments;
203
+ var later = function() {
204
+ timeout = null;
205
+ func.apply(context, args);
206
+ };
207
+ clearTimeout(timeout);
208
+ timeout = setTimeout(later, 100);
209
+ };
210
+ }());
211
+ };
@@ -0,0 +1,775 @@
1
+ /*
2
+ ListJS Beta 0.2.0
3
+ By Jonny Strömberg (www.jonnystromberg.com, www.listjs.com)
4
+
5
+ OBS. The API is not frozen. It MAY change!
6
+
7
+ License (MIT)
8
+
9
+ Copyright (c) 2011 Jonny Strömberg http://jonnystromberg.com
10
+
11
+ Permission is hereby granted, free of charge, to any person
12
+ obtaining a copy of this software and associated documentation
13
+ files (the "Software"), to deal in the Software without restriction,
14
+ including without limitation the rights to use, copy, modify, merge,
15
+ publish, distribute, sublicense, and/or sell copies of the Software,
16
+ and to permit persons to whom the Software is furnished to do so,
17
+ subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be
20
+ included in all copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29
+ OTHER DEALINGS IN THE SOFTWARE.
30
+ */
31
+ (function( window, undefined ) {
32
+ "use strict";
33
+ var document = window.document,
34
+ h;
35
+
36
+ var List = function(id, options, values) {
37
+ var self = this,
38
+ templater,
39
+ init,
40
+ initialItems,
41
+ Item,
42
+ Templater,
43
+ sortButtons,
44
+ events = {
45
+ 'updated': []
46
+ };
47
+ this.listContainer = (typeof(id) == 'string') ? document.getElementById(id) : id;
48
+ // Check if the container exists. If not return instead of breaking the javascript
49
+ if (!this.listContainer)
50
+ return;
51
+
52
+ this.items = [];
53
+ this.visibleItems = []; // These are the items currently visible
54
+ this.matchingItems = []; // These are the items currently matching filters and search, regadlessof visible count
55
+ this.searched = false;
56
+ this.filtered = false;
57
+
58
+ this.list = null;
59
+ this.templateEngines = {};
60
+
61
+ this.page = options.page || 200;
62
+ this.i = options.i || 1;
63
+
64
+ init = {
65
+ start: function(values, options) {
66
+ options.plugins = options.plugins || {};
67
+ this.classes(options);
68
+ templater = new Templater(self, options);
69
+ this.callbacks(options);
70
+ this.items.start(values, options);
71
+ self.update();
72
+ this.plugins(options.plugins);
73
+ },
74
+ classes: function(options) {
75
+ options.listClass = options.listClass || 'list';
76
+ options.searchClass = options.searchClass || 'search';
77
+ options.sortClass = options.sortClass || 'sort';
78
+ },
79
+ callbacks: function(options) {
80
+ self.list = h.getByClass(options.listClass, self.listContainer, true);
81
+ h.addEvent(h.getByClass(options.searchClass, self.listContainer), 'keyup', self.search);
82
+ sortButtons = h.getByClass(options.sortClass, self.listContainer);
83
+ h.addEvent(sortButtons, 'click', self.sort);
84
+ },
85
+ items: {
86
+ start: function(values, options) {
87
+ if (options.valueNames) {
88
+ var itemsToIndex = this.get(),
89
+ valueNames = options.valueNames;
90
+ if (options.indexAsync) {
91
+ this.indexAsync(itemsToIndex, valueNames);
92
+ } else {
93
+ this.index(itemsToIndex, valueNames);
94
+ }
95
+ }
96
+ if (values !== undefined) {
97
+ self.add(values);
98
+ }
99
+ },
100
+ get: function() {
101
+ // return h.getByClass('item', self.list);
102
+ var nodes = self.list.childNodes,
103
+ items = [];
104
+ for (var i = 0, il = nodes.length; i < il; i++) {
105
+ // Only textnodes have a data attribute
106
+ if (nodes[i].data === undefined) {
107
+ items.push(nodes[i]);
108
+ }
109
+ }
110
+ return items;
111
+ },
112
+ index: function(itemElements, valueNames) {
113
+ for (var i = 0, il = itemElements.length; i < il; i++) {
114
+ self.items.push(new Item(valueNames, itemElements[i]));
115
+ }
116
+ },
117
+ indexAsync: function(itemElements, valueNames) {
118
+ var itemsToIndex = itemElements.splice(0, 100); // TODO: If < 100 items, what happens in IE etc?
119
+ this.index(itemsToIndex, valueNames);
120
+ if (itemElements.length > 0) {
121
+ setTimeout(function() {
122
+ init.items.indexAsync(itemElements, valueNames);
123
+ },
124
+ 10);
125
+ } else {
126
+ self.update();
127
+ // TODO: Add indexed callback
128
+ }
129
+ }
130
+ },
131
+ plugins: function(plugins) {
132
+ var locals = {
133
+ templater: templater,
134
+ init: init,
135
+ initialItems: initialItems,
136
+ Item: Item,
137
+ Templater: Templater,
138
+ sortButtons: sortButtons,
139
+ events: events,
140
+ reset: reset
141
+ };
142
+ for (var i = 0; i < plugins.length; i++) {
143
+ plugins[i][1] = plugins[i][1] || {};
144
+ var pluginName = plugins[i][1].name || plugins[i][0];
145
+ self[pluginName] = self.plugins[plugins[i][0]].call(self, locals, plugins[i][1]);
146
+ }
147
+ }
148
+ };
149
+
150
+
151
+ /*
152
+ * Add object to list
153
+ */
154
+ this.add = function(values, callback) {
155
+ if (callback) {
156
+ addAsync(values, callback);
157
+ }
158
+ var added = [],
159
+ notCreate = false;
160
+ if (values[0] === undefined){
161
+ values = [values];
162
+ }
163
+ for (var i = 0, il = values.length; i < il; i++) {
164
+ var item = null;
165
+ if (values[i] instanceof Item) {
166
+ item = values[i];
167
+ item.reload();
168
+ } else {
169
+ notCreate = (self.items.length > self.page) ? true : false;
170
+ item = new Item(values[i], undefined, notCreate);
171
+ }
172
+ self.items.push(item);
173
+ added.push(item);
174
+ }
175
+ self.update();
176
+ return added;
177
+ };
178
+
179
+ /*
180
+ * Adds items asynchronous to the list, good for adding huge amount of
181
+ * data. Defaults to add 100 items a time
182
+ */
183
+ var addAsync = function(values, callback, items) {
184
+ var valuesToAdd = values.splice(0, 100);
185
+ items = items || [];
186
+ items = items.concat(self.add(valuesToAdd));
187
+ if (values.length > 0) {
188
+ setTimeout(function() {
189
+ addAsync(values, callback, items);
190
+ }, 10);
191
+ } else {
192
+ self.update();
193
+ callback(items);
194
+ }
195
+ };
196
+
197
+ this.show = function(i, page) {
198
+ this.i = i;
199
+ this.page = page;
200
+ self.update();
201
+ };
202
+
203
+ /* Removes object from list.
204
+ * Loops through the list and removes objects where
205
+ * property "valuename" === value
206
+ */
207
+ this.remove = function(valueName, value, options) {
208
+ var found = 0;
209
+ for (var i = 0, il = self.items.length; i < il; i++) {
210
+ if (self.items[i].values()[valueName] == value) {
211
+ templater.remove(self.items[i], options);
212
+ self.items.splice(i,1);
213
+ il--;
214
+ found++;
215
+ }
216
+ }
217
+ self.update();
218
+ return found;
219
+ };
220
+
221
+ /* Gets the objects in the list which
222
+ * property "valueName" === value
223
+ */
224
+ this.get = function(valueName, value) {
225
+ var matchedItems = [];
226
+ for (var i = 0, il = self.items.length; i < il; i++) {
227
+ var item = self.items[i];
228
+ if (item.values()[valueName] == value) {
229
+ matchedItems.push(item);
230
+ }
231
+ }
232
+ if (matchedItems.length == 0) {
233
+ return null;
234
+ } else if (matchedItems.length == 1) {
235
+ return matchedItems[0];
236
+ } else {
237
+ return matchedItems;
238
+ }
239
+ };
240
+
241
+ /* Sorts the list.
242
+ * @valueOrEvent Either a JavaScript event object or a valueName
243
+ * @sortFunction (optional) Define if natural sorting does not fullfill your needs
244
+ */
245
+ this.sort = function(valueName, options) {
246
+ var length = self.items.length,
247
+ value = null,
248
+ target = valueName.target || valueName.srcElement, /* IE have srcElement */
249
+ sorting = '',
250
+ isAsc = false,
251
+ asc = 'asc',
252
+ desc = 'desc',
253
+ options = options || {};
254
+
255
+ if (target === undefined) {
256
+ value = valueName;
257
+ isAsc = options.asc || false;
258
+ } else {
259
+ value = h.getAttribute(target, 'data-sort');
260
+ isAsc = h.hasClass(target, asc) ? false : true;
261
+ }
262
+ for (var i = 0, il = sortButtons.length; i < il; i++) {
263
+ h.removeClass(sortButtons[i], asc);
264
+ h.removeClass(sortButtons[i], desc);
265
+ }
266
+ if (isAsc) {
267
+ if (target !== undefined) {
268
+ h.addClass(target, asc);
269
+ }
270
+ isAsc = true;
271
+ } else {
272
+ if (target !== undefined) {
273
+ h.addClass(target, desc);
274
+ }
275
+ isAsc = false;
276
+ }
277
+
278
+ if (options.sortFunction) {
279
+ options.sortFunction = options.sortFunction;
280
+ } else {
281
+ options.sortFunction = function(a, b) {
282
+ return h.sorter.alphanum(a.values()[value].toLowerCase(), b.values()[value].toLowerCase(), isAsc);
283
+ };
284
+ }
285
+ self.items.sort(options.sortFunction);
286
+ self.update();
287
+ };
288
+
289
+ /*
290
+ * Searches the list after values with content "searchStringOrEvent".
291
+ * The columns parameter defines if all values should be included in the search,
292
+ * defaults to undefined which means "all".
293
+ */
294
+ this.search = function(searchString, columns) {
295
+ self.i = 1; // Reset paging
296
+ var matching = [],
297
+ found,
298
+ item,
299
+ text,
300
+ values,
301
+ is,
302
+ columns = (columns === undefined) ? self.items[0].values() : columns,
303
+ searchString = (searchString === undefined) ? "" : searchString,
304
+ target = searchString.target || searchString.srcElement; /* IE have srcElement */
305
+
306
+ searchString = (target === undefined) ? (""+searchString).toLowerCase() : ""+target.value.toLowerCase();
307
+ is = self.items;
308
+ // Escape regular expression characters
309
+ searchString = searchString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
310
+
311
+ templater.clear();
312
+ if (searchString === "" ) {
313
+ reset.search();
314
+ self.searched = false;
315
+ self.update();
316
+ } else {
317
+ self.searched = true;
318
+
319
+ for (var k = 0, kl = is.length; k < kl; k++) {
320
+ found = false;
321
+ item = is[k];
322
+ values = item.values();
323
+
324
+ for(var j in columns) {
325
+ if(values.hasOwnProperty(j) && columns[j] !== null) {
326
+ text = (values[j] != null) ? values[j].toString().toLowerCase() : "";
327
+ if ((searchString !== "") && (text.search(searchString) > -1)) {
328
+ found = true;
329
+ }
330
+ }
331
+ }
332
+ if (found) {
333
+ item.found = true;
334
+ matching.push(item);
335
+ } else {
336
+ item.found = false;
337
+ }
338
+ }
339
+ self.update();
340
+ }
341
+ return self.visibleItems;
342
+ };
343
+
344
+ /*
345
+ * Filters the list. If filterFunction() returns False hides the Item.
346
+ * if filterFunction == false are the filter removed
347
+ */
348
+ this.filter = function(filterFunction) {
349
+ self.i = 1; // Reset paging
350
+ reset.filter();
351
+ if (filterFunction === undefined) {
352
+ self.filtered = false;
353
+ } else {
354
+ self.filtered = true;
355
+ var is = self.items;
356
+ for (var i = 0, il = is.length; i < il; i++) {
357
+ var item = is[i];
358
+ if (filterFunction(item)) {
359
+ item.filtered = true;
360
+ } else {
361
+ item.filtered = false;
362
+ }
363
+ }
364
+ }
365
+ self.update();
366
+ return self.visibleItems;
367
+ };
368
+
369
+ /*
370
+ * Get size of the list
371
+ */
372
+ this.size = function() {
373
+ return self.items.length;
374
+ };
375
+
376
+ /*
377
+ * Removes all items from the list
378
+ */
379
+ this.clear = function() {
380
+ templater.clear();
381
+ self.items = [];
382
+ };
383
+
384
+ this.on = function(event, callback) {
385
+ events[event].push(callback);
386
+ };
387
+
388
+ var trigger = function(event) {
389
+ var i = events[event].length;
390
+ while(i--) {
391
+ events[event][i]();
392
+ }
393
+ };
394
+
395
+ var reset = {
396
+ filter: function() {
397
+ var is = self.items,
398
+ il = is.length;
399
+ while (il--) {
400
+ is[il].filtered = false;
401
+ }
402
+ },
403
+ search: function() {
404
+ var is = self.items,
405
+ il = is.length;
406
+ while (il--) {
407
+ is[il].found = false;
408
+ }
409
+ }
410
+ };
411
+
412
+
413
+ this.update = function() {
414
+ var is = self.items,
415
+ il = is.length;
416
+
417
+ self.visibleItems = [];
418
+ self.matchingItems = [];
419
+ templater.clear();
420
+ for (var i = 0; i < il; i++) {
421
+ if (is[i].matching() && ((self.matchingItems.length+1) >= self.i && self.visibleItems.length < self.page)) {
422
+ is[i].show();
423
+ self.visibleItems.push(is[i]);
424
+ self.matchingItems.push(is[i]);
425
+ } else if (is[i].matching()) {
426
+ self.matchingItems.push(is[i]);
427
+ is[i].hide();
428
+ } else {
429
+ is[i].hide();
430
+ }
431
+ }
432
+ trigger('updated');
433
+ };
434
+
435
+ Item = function(initValues, element, notCreate) {
436
+ var item = this,
437
+ values = {};
438
+
439
+ this.found = false; // Show if list.searched == true and this.found == true
440
+ this.filtered = false;// Show if list.filtered == true and this.filtered == true
441
+
442
+ var init = function(initValues, element, notCreate) {
443
+ if (element === undefined) {
444
+ if (notCreate) {
445
+ item.values(initValues, notCreate);
446
+ } else {
447
+ item.values(initValues);
448
+ }
449
+ } else {
450
+ item.elm = element;
451
+ var values = templater.get(item, initValues);
452
+ item.values(values);
453
+ }
454
+ };
455
+ this.values = function(newValues, notCreate) {
456
+ if (newValues !== undefined) {
457
+ for(var name in newValues) {
458
+ values[name] = newValues[name];
459
+ }
460
+ if (notCreate !== true) {
461
+ templater.set(item, item.values());
462
+ }
463
+ } else {
464
+ return values;
465
+ }
466
+ };
467
+ this.show = function() {
468
+ templater.show(item);
469
+ };
470
+ this.hide = function() {
471
+ templater.hide(item);
472
+ };
473
+ this.matching = function() {
474
+ return (
475
+ (self.filtered && self.searched && item.found && item.filtered) ||
476
+ (self.filtered && !self.searched && item.filtered) ||
477
+ (!self.filtered && self.searched && item.found) ||
478
+ (!self.filtered && !self.searched)
479
+ );
480
+ };
481
+ this.visible = function() {
482
+ return (item.elm.parentNode) ? true : false;
483
+ };
484
+ init(initValues, element, notCreate);
485
+ };
486
+
487
+ /* Templater with different kinds of template engines.
488
+ * All engines have these methods
489
+ * - reload(item)
490
+ * - remove(item)
491
+ */
492
+ Templater = function(list, settings) {
493
+ if (settings.engine === undefined) {
494
+ settings.engine = "standard";
495
+ } else {
496
+ settings.engine = settings.engine.toLowerCase();
497
+ }
498
+ return new self.constructor.prototype.templateEngines[settings.engine](list, settings);
499
+ };
500
+
501
+ init.start(values, options);
502
+ };
503
+
504
+ List.prototype.templateEngines = {};
505
+ List.prototype.plugins = {};
506
+
507
+ List.prototype.templateEngines.standard = function(list, settings) {
508
+ var listSource = h.getByClass(settings.listClass, list.listContainer, true),
509
+ itemSource = getItemSource(settings.item),
510
+ templater = this;
511
+
512
+ function getItemSource(item) {
513
+ if (item === undefined) {
514
+ var nodes = listSource.childNodes,
515
+ items = [];
516
+
517
+ for (var i = 0, il = nodes.length; i < il; i++) {
518
+ // Only textnodes have a data attribute
519
+ if (nodes[i].data === undefined) {
520
+ return nodes[i];
521
+ }
522
+ }
523
+ return null;
524
+ } else if (item.indexOf("<") !== -1) { // Try create html element of list, do not work for tables!!
525
+ var div = document.createElement('div');
526
+ div.innerHTML = item;
527
+ return div.firstChild;
528
+ } else {
529
+ return document.getElementById(settings.item);
530
+ }
531
+ }
532
+
533
+ var ensure = {
534
+ created: function(item) {
535
+ if (item.elm === undefined) {
536
+ templater.create(item);
537
+ }
538
+ }
539
+ };
540
+
541
+ /* Get values from element */
542
+ this.get = function(item, valueNames) {
543
+ ensure.created(item);
544
+ var values = {};
545
+ for(var i = 0, il = valueNames.length; i < il; i++) {
546
+ var elm = h.getByClass(valueNames[i], item.elm, true);
547
+ values[valueNames[i]] = elm ? elm.innerHTML : "";
548
+ }
549
+ return values;
550
+ };
551
+
552
+ /* Sets values at element */
553
+ this.set = function(item, values) {
554
+ ensure.created(item);
555
+ for(var v in values) {
556
+ if (values.hasOwnProperty(v)) {
557
+ // TODO speed up if possible
558
+ var elm = h.getByClass(v, item.elm, true);
559
+ if (elm) {
560
+ elm.innerHTML = values[v];
561
+ }
562
+ }
563
+ }
564
+ };
565
+
566
+ this.create = function(item) {
567
+ if (item.elm !== undefined) {
568
+ return;
569
+ }
570
+ /* If item source does not exists, use the first item in list as
571
+ source for new items */
572
+ var newItem = itemSource.cloneNode(true);
573
+ newItem.id = "";
574
+ item.elm = newItem;
575
+ templater.set(item, item.values());
576
+ };
577
+ this.remove = function(item) {
578
+ listSource.removeChild(item.elm);
579
+ };
580
+ this.show = function(item) {
581
+ ensure.created(item);
582
+ listSource.appendChild(item.elm);
583
+ };
584
+ this.hide = function(item) {
585
+ if (item.elm !== undefined && item.elm.parentNode === listSource) {
586
+ listSource.removeChild(item.elm);
587
+ }
588
+ };
589
+ this.clear = function() {
590
+ /* .innerHTML = ''; fucks up IE */
591
+ if (listSource.hasChildNodes()) {
592
+ while (listSource.childNodes.length >= 1)
593
+ {
594
+ listSource.removeChild(listSource.firstChild);
595
+ }
596
+ }
597
+ };
598
+ };
599
+
600
+
601
+ /*
602
+ * These helper functions are not written by List.js author Jonny (they may have been
603
+ * adjusted, thought).
604
+ */
605
+ h = {
606
+ /*
607
+ * Cross browser getElementsByClassName, which uses native
608
+ * if it exists. Modified version of Dustin Diaz function:
609
+ * http://www.dustindiaz.com/getelementsbyclass
610
+ */
611
+ getByClass: (function() {
612
+ if (document.getElementsByClassName) {
613
+ return function(searchClass,node,single) {
614
+ if (single) {
615
+ return node.getElementsByClassName(searchClass)[0];
616
+ } else {
617
+ return node.getElementsByClassName(searchClass);
618
+ }
619
+ };
620
+ } else {
621
+ return function(searchClass,node,single) {
622
+ var classElements = [],
623
+ tag = '*';
624
+ if (node == null) {
625
+ node = document;
626
+ }
627
+ var els = node.getElementsByTagName(tag);
628
+ var elsLen = els.length;
629
+ var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
630
+ for (var i = 0, j = 0; i < elsLen; i++) {
631
+ if ( pattern.test(els[i].className) ) {
632
+ if (single) {
633
+ return els[i];
634
+ } else {
635
+ classElements[j] = els[i];
636
+ j++;
637
+ }
638
+ }
639
+ }
640
+ return classElements;
641
+ };
642
+ }
643
+ })(),
644
+ /* (elm, 'event' callback) Source: http://net.tutsplus.com/tutorials/javascript-ajax/javascript-from-null-cross-browser-event-binding/ */
645
+ addEvent: (function( window, document ) {
646
+ if ( document.addEventListener ) {
647
+ return function( elem, type, cb ) {
648
+ if ((elem && !(elem instanceof Array) && !elem.length && !h.isNodeList(elem) && (elem.length !== 0)) || elem === window ) {
649
+ elem.addEventListener(type, cb, false );
650
+ } else if ( elem && elem[0] !== undefined ) {
651
+ var len = elem.length;
652
+ for ( var i = 0; i < len; i++ ) {
653
+ h.addEvent(elem[i], type, cb);
654
+ }
655
+ }
656
+ };
657
+ }
658
+ else if ( document.attachEvent ) {
659
+ return function ( elem, type, cb ) {
660
+ if ((elem && !(elem instanceof Array) && !elem.length && !h.isNodeList(elem) && (elem.length !== 0)) || elem === window ) {
661
+ elem.attachEvent( 'on' + type, function() { return cb.call(elem, window.event); } );
662
+ } else if ( elem && elem[0] !== undefined ) {
663
+ var len = elem.length;
664
+ for ( var i = 0; i < len; i++ ) {
665
+ h.addEvent( elem[i], type, cb );
666
+ }
667
+ }
668
+ };
669
+ }
670
+ })(this, document),
671
+ /* (elm, attribute) Source: http://stackoverflow.com/questions/3755227/cross-browser-javascript-getattribute-method */
672
+ getAttribute: function(ele, attr) {
673
+ var result = (ele.getAttribute && ele.getAttribute(attr)) || null;
674
+ if( !result ) {
675
+ var attrs = ele.attributes;
676
+ var length = attrs.length;
677
+ for(var i = 0; i < length; i++) {
678
+ if (attr[i] !== undefined) {
679
+ if(attr[i].nodeName === attr) {
680
+ result = attr[i].nodeValue;
681
+ }
682
+ }
683
+ }
684
+ }
685
+ return result;
686
+ },
687
+ /* http://stackoverflow.com/questions/7238177/detect-htmlcollection-nodelist-in-javascript */
688
+ isNodeList: function(nodes) {
689
+ var result = Object.prototype.toString.call(nodes);
690
+ if (typeof nodes === 'object' && /^\[object (HTMLCollection|NodeList|Object)\]$/.test(result) && (nodes.length == 0 || (typeof nodes[0] === "object" && nodes[0].nodeType > 0))) {
691
+ return true;
692
+ }
693
+ return false;
694
+ },
695
+ hasClass: function(ele, classN) {
696
+ var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
697
+ return (classes.search(classN) > -1);
698
+ },
699
+ addClass: function(ele, classN) {
700
+ if (!this.hasClass(ele, classN)) {
701
+ var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
702
+ classes = classes + ' ' + classN + ' ';
703
+ classes = classes.replace(/\s{2,}/g, ' ');
704
+ ele.setAttribute('class', classes);
705
+ }
706
+ },
707
+ removeClass: function(ele, classN) {
708
+ if (this.hasClass(ele, classN)) {
709
+ var classes = this.getAttribute(ele, 'class') || this.getAttribute(ele, 'className') || "";
710
+ classes = classes.replace(classN, '');
711
+ ele.setAttribute('class', classes);
712
+ }
713
+ },
714
+ /*
715
+ * The sort function. From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
716
+ */
717
+ sorter: {
718
+ alphanum: function(a,b,asc) {
719
+ if (a === undefined || a === null) {
720
+ a = "";
721
+ }
722
+ if (b === undefined || b === null) {
723
+ b = "";
724
+ }
725
+ a = a.toString().replace(/&(lt|gt);/g, function (strMatch, p1){
726
+ return (p1 == "lt")? "<" : ">";
727
+ });
728
+ a = a.replace(/<\/?[^>]+(>|$)/g, "");
729
+
730
+ b = b.toString().replace(/&(lt|gt);/g, function (strMatch, p1){
731
+ return (p1 == "lt")? "<" : ">";
732
+ });
733
+ b = b.replace(/<\/?[^>]+(>|$)/g, "");
734
+ var aa = this.chunkify(a);
735
+ var bb = this.chunkify(b);
736
+
737
+ for (var x = 0; aa[x] && bb[x]; x++) {
738
+ if (aa[x] !== bb[x]) {
739
+ var c = Number(aa[x]), d = Number(bb[x]);
740
+ if (asc) {
741
+ if (c == aa[x] && d == bb[x]) {
742
+ return c - d;
743
+ } else {
744
+ return (aa[x] > bb[x]) ? 1 : -1;
745
+ }
746
+ } else {
747
+ if (c == aa[x] && d == bb[x]) {
748
+ return d-c;//c - d;
749
+ } else {
750
+ return (aa[x] > bb[x]) ? -1 : 1; //(aa[x] > bb[x]) ? 1 : -1;
751
+ }
752
+ }
753
+ }
754
+ }
755
+ return aa.length - bb.length;
756
+ },
757
+ chunkify: function(t) {
758
+ var tz = [], x = 0, y = -1, n = 0, i, j;
759
+
760
+ while (i = (j = t.charAt(x++)).charCodeAt(0)) {
761
+ var m = (i == 45 || i == 46 || (i >=48 && i <= 57));
762
+ if (m !== n) {
763
+ tz[++y] = "";
764
+ n = m;
765
+ }
766
+ tz[y] += j;
767
+ }
768
+ return tz;
769
+ }
770
+ }
771
+ };
772
+
773
+ window.List = List;
774
+ window.ListJsHelpers = h;
775
+ })(window);
@@ -0,0 +1 @@
1
+ (function(a,b){"use strict";var c=a.document,d;var e=function(a,e,f){var g=this,i,j,k,l,m,n,o={updated:[]};this.listContainer=typeof a=="string"?c.getElementById(a):a;if(!this.listContainer)return;this.items=[];this.visibleItems=[];this.matchingItems=[];this.searched=false;this.filtered=false;this.list=null;this.templateEngines={};this.page=e.page||200;this.i=e.i||1;j={start:function(a,b){b.plugins=b.plugins||{};this.classes(b);i=new m(g,b);this.callbacks(b);this.items.start(a,b);g.update();this.plugins(b.plugins)},classes:function(a){a.listClass=a.listClass||"list";a.searchClass=a.searchClass||"search";a.sortClass=a.sortClass||"sort"},callbacks:function(a){g.list=d.getByClass(a.listClass,g.listContainer,true);d.addEvent(d.getByClass(a.searchClass,g.listContainer),"keyup",g.search);n=d.getByClass(a.sortClass,g.listContainer);d.addEvent(n,"click",g.sort)},items:{start:function(a,c){if(c.valueNames){var d=this.get(),e=c.valueNames;if(c.indexAsync){this.indexAsync(d,e)}else{this.index(d,e)}}if(a!==b){g.add(a)}},get:function(){var a=g.list.childNodes,c=[];for(var d=0,e=a.length;d<e;d++){if(a[d].data===b){c.push(a[d])}}return c},index:function(a,b){for(var c=0,d=a.length;c<d;c++){g.items.push(new l(b,a[c]))}},indexAsync:function(a,b){var c=a.splice(0,100);this.index(c,b);if(a.length>0){setTimeout(function(){j.items.indexAsync(a,b)},10)}else{g.update()}}},plugins:function(a){var b={templater:i,init:j,initialItems:k,Item:l,Templater:m,sortButtons:n,events:o,reset:r};for(var c=0;c<a.length;c++){a[c][1]=a[c][1]||{};var d=a[c][1].name||a[c][0];g[d]=g.plugins[a[c][0]].call(g,b,a[c][1])}}};this.add=function(a,c){if(c){p(a,c)}var d=[],e=false;if(a[0]===b){a=[a]}for(var f=0,h=a.length;f<h;f++){var i=null;if(a[f]instanceof l){i=a[f];i.reload()}else{e=g.items.length>g.page?true:false;i=new l(a[f],b,e)}g.items.push(i);d.push(i)}g.update();return d};var p=function(a,b,c){var d=a.splice(0,100);c=c||[];c=c.concat(g.add(d));if(a.length>0){setTimeout(function(){p(a,b,c)},10)}else{g.update();b(c)}};this.show=function(a,b){this.i=a;this.page=b;g.update()};this.remove=function(a,b,c){var d=0;for(var e=0,f=g.items.length;e<f;e++){if(g.items[e].values()[a]==b){i.remove(g.items[e],c);g.items.splice(e,1);f--;d++}}g.update();return d};this.get=function(a,b){var c=[];for(var d=0,e=g.items.length;d<e;d++){var f=g.items[d];if(f.values()[a]==b){c.push(f)}}if(c.length==0){return null}else if(c.length==1){return c[0]}else{return c}};this.sort=function(a,c){var e=g.items.length,f=null,i=a.target||a.srcElement,j="",k=false,l="asc",m="desc",c=c||{};if(i===b){f=a;k=c.asc||false}else{f=d.getAttribute(i,"data-sort");k=d.hasClass(i,l)?false:true}for(var o=0,p=n.length;o<p;o++){d.removeClass(n[o],l);d.removeClass(n[o],m)}if(k){if(i!==b){d.addClass(i,l)}k=true}else{if(i!==b){d.addClass(i,m)}k=false}if(c.sortFunction){c.sortFunction=c.sortFunction}else{c.sortFunction=function(a,b){return d.sorter.alphanum(a.values()[f].toLowerCase(),b.values()[f].toLowerCase(),k)}}g.items.sort(c.sortFunction);g.update()};this.search=function(a,c){g.i=1;var d=[],e,f,h,j,k,c=c===b?g.items[0].values():c,a=a===b?"":a,l=a.target||a.srcElement;a=l===b?(""+a).toLowerCase():""+l.value.toLowerCase();k=g.items;a=a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&");i.clear();if(a===""){r.search();g.searched=false;g.update()}else{g.searched=true;for(var m=0,n=k.length;m<n;m++){e=false;f=k[m];j=f.values();for(var o in c){if(j.hasOwnProperty(o)&&c[o]!==null){h=j[o]!=null?j[o].toString().toLowerCase():"";if(a!==""&&h.search(a)>-1){e=true}}}if(e){f.found=true;d.push(f)}else{f.found=false}}g.update()}return g.visibleItems};this.filter=function(a){g.i=1;r.filter();if(a===b){g.filtered=false}else{g.filtered=true;var c=g.items;for(var d=0,e=c.length;d<e;d++){var f=c[d];if(a(f)){f.filtered=true}else{f.filtered=false}}}g.update();return g.visibleItems};this.size=function(){return g.items.length};this.clear=function(){i.clear();g.items=[]};this.on=function(a,b){o[a].push(b)};var q=function(a){var b=o[a].length;while(b--){o[a][b]()}};var r={filter:function(){var a=g.items,b=a.length;while(b--){a[b].filtered=false}},search:function(){var a=g.items,b=a.length;while(b--){a[b].found=false}}};this.update=function(){var a=g.items,b=a.length;g.visibleItems=[];g.matchingItems=[];i.clear();for(var c=0;c<b;c++){if(a[c].matching()&&g.matchingItems.length+1>=g.i&&g.visibleItems.length<g.page){a[c].show();g.visibleItems.push(a[c]);g.matchingItems.push(a[c])}else if(a[c].matching()){g.matchingItems.push(a[c]);a[c].hide()}else{a[c].hide()}}q("updated")};l=function(a,c,d){var e=this,f={};this.found=false;this.filtered=false;var h=function(a,c,d){if(c===b){if(d){e.values(a,d)}else{e.values(a)}}else{e.elm=c;var f=i.get(e,a);e.values(f)}};this.values=function(a,c){if(a!==b){for(var d in a){f[d]=a[d]}if(c!==true){i.set(e,e.values())}}else{return f}};this.show=function(){i.show(e)};this.hide=function(){i.hide(e)};this.matching=function(){return g.filtered&&g.searched&&e.found&&e.filtered||g.filtered&&!g.searched&&e.filtered||!g.filtered&&g.searched&&e.found||!g.filtered&&!g.searched};this.visible=function(){return e.elm.parentNode?true:false};h(a,c,d)};m=function(a,c){if(c.engine===b){c.engine="standard"}else{c.engine=c.engine.toLowerCase()}return new g.constructor.prototype.templateEngines[c.engine](a,c)};j.start(f,e)};e.prototype.templateEngines={};e.prototype.plugins={};e.prototype.templateEngines.standard=function(a,e){function j(a){if(a===b){var d=f.childNodes,g=[];for(var h=0,i=d.length;h<i;h++){if(d[h].data===b){return d[h]}}return null}else if(a.indexOf("<")!==-1){var j=c.createElement("div");j.innerHTML=a;return j.firstChild}else{return c.getElementById(e.item)}}var f=d.getByClass(e.listClass,a.listContainer,true),g=j(e.item),i=this;var k={created:function(a){if(a.elm===b){i.create(a)}}};this.get=function(a,b){k.created(a);var c={};for(var e=0,f=b.length;e<f;e++){var g=d.getByClass(b[e],a.elm,true);c[b[e]]=g?g.innerHTML:""}return c};this.set=function(a,b){k.created(a);for(var c in b){if(b.hasOwnProperty(c)){var e=d.getByClass(c,a.elm,true);if(e){e.innerHTML=b[c]}}}};this.create=function(a){if(a.elm!==b){return}var c=g.cloneNode(true);c.id="";a.elm=c;i.set(a,a.values())};this.remove=function(a){f.removeChild(a.elm)};this.show=function(a){k.created(a);f.appendChild(a.elm)};this.hide=function(a){if(a.elm!==b&&a.elm.parentNode===f){f.removeChild(a.elm)}};this.clear=function(){if(f.hasChildNodes()){while(f.childNodes.length>=1){f.removeChild(f.firstChild)}}}};d={getByClass:function(){if(c.getElementsByClassName){return function(a,b,c){if(c){return b.getElementsByClassName(a)[0]}else{return b.getElementsByClassName(a)}}}else{return function(a,b,d){var e=[],f="*";if(b==null){b=c}var g=b.getElementsByTagName(f);var h=g.length;var i=new RegExp("(^|\\s)"+a+"(\\s|$)");for(var j=0,k=0;j<h;j++){if(i.test(g[j].className)){if(d){return g[j]}else{e[k]=g[j];k++}}}return e}}}(),addEvent:function(a,c){if(c.addEventListener){return function(c,e,f){if(c&&!(c instanceof Array)&&!c.length&&!d.isNodeList(c)&&c.length!==0||c===a){c.addEventListener(e,f,false)}else if(c&&c[0]!==b){var g=c.length;for(var i=0;i<g;i++){d.addEvent(c[i],e,f)}}}}else if(c.attachEvent){return function(c,e,f){if(c&&!(c instanceof Array)&&!c.length&&!d.isNodeList(c)&&c.length!==0||c===a){c.attachEvent("on"+e,function(){return f.call(c,a.event)})}else if(c&&c[0]!==b){var g=c.length;for(var i=0;i<g;i++){d.addEvent(c[i],e,f)}}}}}(this,c),getAttribute:function(a,c){var d=a.getAttribute&&a.getAttribute(c)||null;if(!d){var e=a.attributes;var f=e.length;for(var g=0;g<f;g++){if(c[g]!==b){if(c[g].nodeName===c){d=c[g].nodeValue}}}}return d},isNodeList:function(a){var b=Object.prototype.toString.call(a);if(typeof a==="object"&&/^\[object (HTMLCollection|NodeList|Object)\]$/.test(b)&&(a.length==0||typeof a[0]==="object"&&a[0].nodeType>0)){return true}return false},hasClass:function(a,b){var c=this.getAttribute(a,"class")||this.getAttribute(a,"className")||"";return c.search(b)>-1},addClass:function(a,b){if(!this.hasClass(a,b)){var c=this.getAttribute(a,"class")||this.getAttribute(a,"className")||"";c=c+" "+b+" ";c=c.replace(/\s{2,}/g," ");a.setAttribute("class",c)}},removeClass:function(a,b){if(this.hasClass(a,b)){var c=this.getAttribute(a,"class")||this.getAttribute(a,"className")||"";c=c.replace(b,"");a.setAttribute("class",c)}},sorter:{alphanum:function(a,c,d){if(a===b||a===null){a=""}if(c===b||c===null){c=""}a=a.toString().replace(/&(lt|gt);/g,function(a,b){return b=="lt"?"<":">"});a=a.replace(/<\/?[^>]+(>|$)/g,"");c=c.toString().replace(/&(lt|gt);/g,function(a,b){return b=="lt"?"<":">"});c=c.replace(/<\/?[^>]+(>|$)/g,"");var e=this.chunkify(a);var f=this.chunkify(c);for(var g=0;e[g]&&f[g];g++){if(e[g]!==f[g]){var h=Number(e[g]),i=Number(f[g]);if(d){if(h==e[g]&&i==f[g]){return h-i}else{return e[g]>f[g]?1:-1}}else{if(h==e[g]&&i==f[g]){return i-h}else{return e[g]>f[g]?-1:1}}}}return e.length-f.length},chunkify:function(a){var b=[],c=0,d=-1,e=0,f,g;while(f=(g=a.charAt(c++)).charCodeAt(0)){var h=f==45||f==46||f>=48&&f<=57;if(h!==e){b[++d]="";e=h}b[d]+=g}return b}}};a.List=e;a.ListJsHelpers=d})(window)
@@ -0,0 +1,86 @@
1
+ List.prototype.plugins.paging = function(locals, options) {
2
+ var list = this;
3
+ var pagingList;
4
+ var init = function() {
5
+ options = options || {};
6
+ pagingList = new List(list.listContainer.id, {
7
+ listClass: options.pagingClass || 'paging',
8
+ item: "<li><div class='page'></div></li>", // Have to contain something, can't set valueName at root element
9
+ valueNames: ['page', 'dotted'],
10
+ searchClass: 'nosearchclass',
11
+ sortClass: 'nosortclass'
12
+ });
13
+ list.on('updated', refresh);
14
+ refresh();
15
+ };
16
+
17
+ var refresh = function() {
18
+ var l = list.matchingItems.length,
19
+ index = list.i,
20
+ page = list.page,
21
+ pages = Math.ceil(l / page),
22
+ currentPage = Math.ceil((index / page)),
23
+ innerWindow = options.innerWindow || 2,
24
+ left = options.left || options.outerWindow || 0,
25
+ right = options.right || options.outerWindow || 0,
26
+ right = pages - right;
27
+
28
+ pagingList.clear();
29
+ for (var i = 1; i <= pages; i++) {
30
+ var className = (currentPage === i) ? "active" : "";
31
+
32
+ //console.log(i, left, right, currentPage, (currentPage - innerWindow), (currentPage + innerWindow));
33
+
34
+ if (is.number(i, left, right, currentPage, innerWindow)) {
35
+ var item = pagingList.add({
36
+ page: "<a class='"+className+"' href='javascript:function Z(){Z=\"\"}Z()'>"+(i)+"</a>",
37
+ dotted: false
38
+ })[0];
39
+ addEvent(item.elm, i, page);
40
+ } else if (is.dotted(i, left, right, currentPage, innerWindow, pagingList.size())) {
41
+ pagingList.add({
42
+ page: "...",
43
+ dotted: true
44
+ });
45
+ }
46
+ }
47
+ };
48
+
49
+ var is = {
50
+ number: function(i, left, right, currentPage, innerWindow) {
51
+ return this.left(i, left) || this.right(i, right) || this.innerWindow(i, currentPage, innerWindow);
52
+ },
53
+ left: function(i, left) {
54
+ return (i <= left);
55
+ },
56
+ right: function(i, right) {
57
+ return (i > right);
58
+ },
59
+ innerWindow: function(i, currentPage, innerWindow) {
60
+ return ( i >= (currentPage - innerWindow) && i <= (currentPage + innerWindow));
61
+ },
62
+ dotted: function(i, left, right, currentPage, innerWindow, currentPageItem) {
63
+ return this.dottedLeft(i, left, right, currentPage, innerWindow)
64
+ || (this.dottedRight(i, left, right, currentPage, innerWindow, currentPageItem));
65
+ },
66
+ dottedLeft: function(i, left, right, currentPage, innerWindow) {
67
+ return ((i == (left + 1)) && !this.innerWindow(i, currentPage, innerWindow) && !this.right(i, right))
68
+ },
69
+ dottedRight: function(i, left, right, currentPage, innerWindow, currentPageItem) {
70
+ if (pagingList.items[currentPageItem-1].values().dotted) {
71
+ return false
72
+ } else {
73
+ return ((i == (right)) && !this.innerWindow(i, currentPage, innerWindow) && !this.right(i, right))
74
+ }
75
+ }
76
+ };
77
+
78
+ var addEvent = function(elm, i, page) {
79
+ ListJsHelpers.addEvent(elm, 'click', function() {
80
+ list.show((i-1)*page + 1, page);
81
+ });
82
+ };
83
+
84
+ init();
85
+ return this;
86
+ };
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-assets-listjs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0.beta.4
5
+ prerelease: 6
6
+ platform: ruby
7
+ authors:
8
+ - Thomas Klemm
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-01 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: railties
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.1'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ description: List.js - packaged by RailsAssets for the Rails Asset Pipeline
31
+ email:
32
+ - github@tklemm.eu
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - .gitignore
38
+ - Gemfile
39
+ - LICENSE.txt
40
+ - README.md
41
+ - Rakefile
42
+ - lib/rails-assets-listjs.rb
43
+ - lib/rails-assets-listjs/version.rb
44
+ - rails-assets-listjs.gemspec
45
+ - vendor/assets/javascripts/list.fuzzySearch.js
46
+ - vendor/assets/javascripts/list.js
47
+ - vendor/assets/javascripts/list.min.js
48
+ - vendor/assets/javascripts/list.paging.js
49
+ homepage: http://www.railsassets.com
50
+ licenses: []
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>'
65
+ - !ruby/object:Gem::Version
66
+ version: 1.3.1
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.23
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: List.js - packaged by RailsAssets for the Rails Asset Pipeline
73
+ test_files: []
74
+ has_rdoc: