-
Notifications
You must be signed in to change notification settings - Fork 896
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Kill plugins and bundle pagination & fuzzySearch
- Loading branch information
Showing
9 changed files
with
775 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
|
||
var classes = require('./utils/classes'), | ||
events = require('./utils/events'), | ||
extend = require('./utils/extend'), | ||
toString = require('./utils/to-string'), | ||
getByClass = require('./utils/get-by-class'), | ||
fuzzy = require('./utils/fuzzy'); | ||
|
||
module.exports = function(list, options) { | ||
options = options || {}; | ||
|
||
options = extend({ | ||
location: 0, | ||
distance: 100, | ||
threshold: 0.4, | ||
multiSearch: true, | ||
searchClass: 'fuzzy-search' | ||
}, options); | ||
|
||
|
||
|
||
var fuzzySearch = { | ||
search: function(searchString, columns) { | ||
// Substract arguments from the searchString or put searchString as only argument | ||
var searchArguments = options.multiSearch ? searchString.replace(/ +$/, '').split(/ +/) : [searchString]; | ||
|
||
for (var k = 0, kl = list.items.length; k < kl; k++) { | ||
fuzzySearch.item(list.items[k], columns, searchArguments); | ||
} | ||
}, | ||
item: function(item, columns, searchArguments) { | ||
var found = true; | ||
for(var i = 0; i < searchArguments.length; i++) { | ||
var foundArgument = false; | ||
for (var j = 0, jl = columns.length; j < jl; j++) { | ||
if (fuzzySearch.values(item.values(), columns[j], searchArguments[i])) { | ||
foundArgument = true; | ||
} | ||
} | ||
if(!foundArgument) { | ||
found = false; | ||
} | ||
} | ||
item.found = found; | ||
}, | ||
values: function(values, value, searchArgument) { | ||
if (values.hasOwnProperty(value)) { | ||
var text = toString(values[value]).toLowerCase(); | ||
|
||
if (fuzzy(text, searchArgument, options)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
}; | ||
|
||
|
||
events.bind(getByClass(list.listContainer, options.searchClass), 'keyup', function(e) { | ||
var target = e.target || e.srcElement; // IE have srcElement | ||
list.search(target.value, fuzzySearch.search); | ||
}); | ||
|
||
return function(str, columns) { | ||
list.search(str, columns, fuzzySearch.search); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
var classes = require('./utils/classes'), | ||
events = require('./utils/events'); | ||
|
||
module.exports = function(list) { | ||
|
||
var pagingList; | ||
|
||
var refresh = function(options) { | ||
var item, | ||
l = list.matchingItems.length, | ||
index = list.i, | ||
page = list.page, | ||
pages = Math.ceil(l / page), | ||
currentPage = Math.ceil((index / page)), | ||
innerWindow = options.innerWindow || 2, | ||
left = options.left || options.outerWindow || 0, | ||
right = options.right || options.outerWindow || 0; | ||
|
||
right = pages - right; | ||
|
||
pagingList.clear(); | ||
for (var i = 1; i <= pages; i++) { | ||
var className = (currentPage === i) ? "active" : ""; | ||
|
||
//console.log(i, left, right, currentPage, (currentPage - innerWindow), (currentPage + innerWindow), className); | ||
|
||
if (is.number(i, left, right, currentPage, innerWindow)) { | ||
item = pagingList.add({ | ||
page: i, | ||
dotted: false | ||
})[0]; | ||
if (className) { | ||
classes(item.elm).add(className); | ||
} | ||
addEvent(item.elm, i, page); | ||
} else if (is.dotted(i, left, right, currentPage, innerWindow, pagingList.size())) { | ||
item = pagingList.add({ | ||
page: "...", | ||
dotted: true | ||
})[0]; | ||
classes(item.elm).add("disabled"); | ||
} | ||
} | ||
}; | ||
|
||
var is = { | ||
number: function(i, left, right, currentPage, innerWindow) { | ||
return this.left(i, left) || this.right(i, right) || this.innerWindow(i, currentPage, innerWindow); | ||
}, | ||
left: function(i, left) { | ||
return (i <= left); | ||
}, | ||
right: function(i, right) { | ||
return (i > right); | ||
}, | ||
innerWindow: function(i, currentPage, innerWindow) { | ||
return ( i >= (currentPage - innerWindow) && i <= (currentPage + innerWindow)); | ||
}, | ||
dotted: function(i, left, right, currentPage, innerWindow, currentPageItem) { | ||
return this.dottedLeft(i, left, right, currentPage, innerWindow) || (this.dottedRight(i, left, right, currentPage, innerWindow, currentPageItem)); | ||
}, | ||
dottedLeft: function(i, left, right, currentPage, innerWindow) { | ||
return ((i == (left + 1)) && !this.innerWindow(i, currentPage, innerWindow) && !this.right(i, right)); | ||
}, | ||
dottedRight: function(i, left, right, currentPage, innerWindow, currentPageItem) { | ||
if (pagingList.items[currentPageItem-1].values().dotted) { | ||
return false; | ||
} else { | ||
return ((i == (right)) && !this.innerWindow(i, currentPage, innerWindow) && !this.right(i, right)); | ||
} | ||
} | ||
}; | ||
|
||
var addEvent = function(elm, i, page) { | ||
events.bind(elm, 'click', function() { | ||
list.show((i-1)*page + 1, page); | ||
}); | ||
}; | ||
|
||
return function(options) { | ||
pagingList = new List(list.listContainer.id, { | ||
listClass: options.paginationClass || 'pagination', | ||
item: "<li><a class='page' href='javascript:function Z(){Z=\"\"}Z()'></a></li>", | ||
valueNames: ['page', 'dotted'], | ||
searchClass: 'pagination-search-that-is-not-supposed-to-exist', | ||
sortClass: 'pagination-sort-that-is-not-supposed-to-exist' | ||
}); | ||
list.on('updated', function() { | ||
refresh(options); | ||
}); | ||
refresh(options); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
module.exports = function(text, pattern, options) { | ||
// Aproximately where in the text is the pattern expected to be found? | ||
var Match_Location = options.location || 0; | ||
|
||
//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. | ||
var Match_Distance = options.distance || 100; | ||
|
||
// 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. | ||
var Match_Threshold = options.threshold || 0.4; | ||
|
||
if (pattern === text) return true; // Exact match | ||
if (pattern.length > 32) return false; // This algorithm cannot be used | ||
|
||
// Set starting location at beginning text and initialise the alphabet. | ||
var loc = Match_Location, | ||
s = (function() { | ||
var q = {}, | ||
i; | ||
|
||
for (i = 0; i < pattern.length; i++) { | ||
q[pattern.charAt(i)] = 0; | ||
} | ||
|
||
for (i = 0; i < pattern.length; i++) { | ||
q[pattern.charAt(i)] |= 1 << (pattern.length - i - 1); | ||
} | ||
|
||
return q; | ||
}()); | ||
|
||
// Compute and return the score for a match with e errors and x location. | ||
// Accesses loc and pattern through being a closure. | ||
|
||
function match_bitapScore_(e, x) { | ||
var accuracy = e / pattern.length, | ||
proximity = Math.abs(loc - x); | ||
|
||
if (!Match_Distance) { | ||
// Dodge divide by zero error. | ||
return proximity ? 1.0 : accuracy; | ||
} | ||
return accuracy + (proximity / Match_Distance); | ||
} | ||
|
||
var score_threshold = Match_Threshold, // Highest score beyond which we give up. | ||
best_loc = text.indexOf(pattern, loc); // Is there a nearby exact match? (speedup) | ||
|
||
if (best_loc != -1) { | ||
score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold); | ||
// What about in the other direction? (speedup) | ||
best_loc = text.lastIndexOf(pattern, loc + pattern.length); | ||
|
||
if (best_loc != -1) { | ||
score_threshold = Math.min(match_bitapScore_(0, best_loc), score_threshold); | ||
} | ||
} | ||
|
||
// Initialise the bit arrays. | ||
var matchmask = 1 << (pattern.length - 1); | ||
best_loc = -1; | ||
|
||
var bin_min, bin_mid; | ||
var bin_max = pattern.length + text.length; | ||
var last_rd; | ||
for (var d = 0; d < pattern.length; d++) { | ||
// Scan for the best match; each iteration allows for one more error. | ||
// Run a binary search to determine how far from 'loc' we can stray at this | ||
// error level. | ||
bin_min = 0; | ||
bin_mid = bin_max; | ||
while (bin_min < bin_mid) { | ||
if (match_bitapScore_(d, loc + bin_mid) <= score_threshold) { | ||
bin_min = bin_mid; | ||
} else { | ||
bin_max = bin_mid; | ||
} | ||
bin_mid = Math.floor((bin_max - bin_min) / 2 + bin_min); | ||
} | ||
// Use the result from this iteration as the maximum for the next. | ||
bin_max = bin_mid; | ||
var start = Math.max(1, loc - bin_mid + 1); | ||
var finish = Math.min(loc + bin_mid, text.length) + pattern.length; | ||
|
||
var rd = Array(finish + 2); | ||
rd[finish + 1] = (1 << d) - 1; | ||
for (var j = finish; j >= start; j--) { | ||
// The alphabet (s) is a sparse hash, so the following line generates | ||
// warnings. | ||
var charMatch = s[text.charAt(j - 1)]; | ||
if (d === 0) { // First pass: exact match. | ||
rd[j] = ((rd[j + 1] << 1) | 1) & charMatch; | ||
} else { // Subsequent passes: fuzzy match. | ||
rd[j] = (((rd[j + 1] << 1) | 1) & charMatch) | | ||
(((last_rd[j + 1] | last_rd[j]) << 1) | 1) | | ||
last_rd[j + 1]; | ||
} | ||
if (rd[j] & matchmask) { | ||
var score = match_bitapScore_(d, j - 1); | ||
// This match will almost certainly be better than any existing match. | ||
// But check anyway. | ||
if (score <= score_threshold) { | ||
// Told you so. | ||
score_threshold = score; | ||
best_loc = j - 1; | ||
if (best_loc > loc) { | ||
// When passing loc, don't exceed our current distance from loc. | ||
start = Math.max(1, 2 * loc - best_loc); | ||
} else { | ||
// Already passed loc, downhill from here on in. | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
// No hope for a (better) match at greater error levels. | ||
if (match_bitapScore_(d + 1, loc) > score_threshold) { | ||
break; | ||
} | ||
last_rd = rd; | ||
} | ||
|
||
return (best_loc < 0) ? false : true; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
var fixtureFuzzysearch = { | ||
list: function(valueNames) { | ||
var listHtml = $('<div id="list-fuzzy-search"><input class="fuzzy-search" /><ul class="list"></ul></div>'), | ||
item = ""; | ||
|
||
item = "<li>"; | ||
for (var i = 0; i < valueNames.length; i++) { | ||
item += '<span class="'+valueNames[i]+'"</span>'; | ||
} | ||
item += "</li>"; | ||
|
||
$(document.body).append(listHtml); | ||
|
||
return item; | ||
}, | ||
removeList: function() { | ||
$('#list-fuzzy-search').remove(); | ||
}, | ||
i1: { name: "Guybrush Threepwood" }, | ||
i2: { name: "Manny Calavera" }, | ||
i3: { name: "Bernard Bernoulli" }, | ||
i4: { name: "LeChuck" }, | ||
i5: { name: "Elaine Marley-Threepwood" }, | ||
i6: { name: "Purple Tentacle" }, | ||
i7: { name: "Adrian Ripburger" }, | ||
i8: { name: "Bobbin Threadbare" }, | ||
i9: { name: "Murray the Demonic Skull" }, | ||
i10: { name: "Zak McKracken" } | ||
}; | ||
fixtureFuzzysearch.all = [ | ||
fixtureFuzzysearch.i1, | ||
fixtureFuzzysearch.i2, | ||
fixtureFuzzysearch.i3, | ||
fixtureFuzzysearch.i4, | ||
fixtureFuzzysearch.i5, | ||
fixtureFuzzysearch.i6, | ||
fixtureFuzzysearch.i7, | ||
fixtureFuzzysearch.i8, | ||
fixtureFuzzysearch.i9, | ||
fixtureFuzzysearch.i10 | ||
]; |
Oops, something went wrong.