fuzzysearch-js
Version:
FuzzySearching in JS
1,188 lines (1,187 loc) • 98.6 kB
JavaScript
(function (modules) {
var cache = {}, require = function (id) {
var module = cache[id];
if (!module) {
module = cache[id] = {};
var exports = module.exports = {};
modules[id].call(exports, require, module, exports, window);
}
return module.exports;
};
require('0');
}({
'0': function (require, module, exports, global) {
'Use Strict';
var prime = require('1');
var onDomReady = require('2');
var $$ = require('4');
require('9');
require('3');
require('c');
require('h');
require('e');
require('i');
var zen = require('j');
var number = require('k');
var mixin = require('m');
var bound = require('n');
var FuzzySearch = require('q');
var LevenshteinFS = require('u');
var Sift3FS = require('x');
var IndexOfFS = require('z');
var WordCountFS = require('10');
var Arr = require('5');
onDomReady(function () {
new Main();
});
var Main = prime({
constructor: function () {
this.searchField = $$('#searchfield');
this.fuzzySearch = new FuzzySearch(fsData, {
'caseSensitive': false,
'termPath': ''
});
this.fuzzySearch.addModule(LevenshteinFS({
'maxDistanceTolerance': 3,
'factor': 3
}));
this.fuzzySearch.addModule(IndexOfFS({
'minTermLength': 3,
'maxIterations': 500,
'factor': 3
}));
this.fuzzySearch.addModule(WordCountFS({
'maxWordTolerance': 3,
'factor': 1
}));
$$('#maxscore').text(this.fuzzySearch.getMaximumScore());
this.loadEvents();
this.displayData();
},
loadEvents: function () {
this.searchField.on('keyup', this.bound('search'));
},
displayData: function () {
var container = $$('#data');
Arr.forEach(fsData, function (data) {
zen('li').text(data).insert(container);
});
},
displayResults: function (results, container) {
var container = container;
$$(container).empty();
Arr.forEach(results, function (result) {
zen('li').text(result.value + ' (total: ' + number.round(result.score) + ')').insert(container);
});
},
search: function () {
var term = this.searchField.value();
var levResults = this.fuzzySearch.search(term);
this.displayResults(levResults, $$('#results'));
}
});
mixin(Main, bound);
},
'1': function (require, module, exports, global) {
'use strict';
var has = function (self, key) {
return Object.hasOwnProperty.call(self, key);
};
var each = function (object, method, context) {
for (var key in object)
if (method.call(context, object[key], key, object) === false)
break;
return object;
};
if (!{ valueOf: 0 }.propertyIsEnumerable('valueOf')) {
var buggy = 'constructor,toString,valueOf,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString'.split(',');
var proto = Object.prototype;
each = function (object, method, context) {
for (var key in object)
if (method.call(context, object[key], key, object) === false)
return object;
for (var i = 0; key = buggy[i]; i++) {
var value = object[key];
if ((value !== proto[key] || has(object, key)) && method.call(context, value, key, object) === false)
break;
}
return object;
};
}
var create = Object.create || function (self) {
var constructor = function () {
};
constructor.prototype = self;
return new constructor();
};
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
var define = Object.defineProperty;
try {
var obj = { a: 1 };
getOwnPropertyDescriptor(obj, 'a');
define(obj, 'a', { value: 2 });
} catch (e) {
getOwnPropertyDescriptor = function (object, key) {
return { value: object[key] };
};
define = function (object, key, descriptor) {
object[key] = descriptor.value;
return object;
};
}
var implement = function (proto) {
each(proto, function (value, key) {
if (key !== 'constructor' && key !== 'define' && key !== 'inherits')
this.define(key, getOwnPropertyDescriptor(proto, key) || {
writable: true,
enumerable: true,
configurable: true,
value: value
});
}, this);
return this;
};
var prime = function (proto) {
var superprime = proto.inherits;
var constructor = has(proto, 'constructor') ? proto.constructor : superprime ? function () {
return superprime.apply(this, arguments);
} : function () {
};
if (superprime) {
var superproto = superprime.prototype;
var cproto = constructor.prototype = create(superproto);
constructor.parent = superproto;
cproto.constructor = constructor;
}
constructor.define = proto.define || superprime && superprime.define || function (key, descriptor) {
define(this.prototype, key, descriptor);
return this;
};
constructor.implement = implement;
return constructor.implement(proto);
};
prime.has = has;
prime.each = each;
prime.create = create;
prime.define = define;
module.exports = prime;
},
'2': function (require, module, exports, global) {
'use strict';
var $ = require('3');
var readystatechange = 'onreadystatechange' in document, shouldPoll = false, loaded = false, readys = [], checks = [], ready = null, timer = null, test = document.createElement('div'), doc = $(document), win = $(window);
var domready = function () {
if (timer)
timer = clearTimeout(timer);
if (!loaded) {
if (readystatechange)
doc.off('readystatechange', check);
doc.off('DOMContentLoaded', domready);
win.off('load', domready);
loaded = true;
for (var i = 0; ready = readys[i++];)
ready();
}
return loaded;
};
var check = function () {
for (var i = checks.length; i--;)
if (checks[i]())
return domready();
return false;
};
var poll = function () {
clearTimeout(timer);
if (!check())
timer = setTimeout(poll, 1000 / 60);
};
if (document.readyState) {
var complete = function () {
return !!/loaded|complete/.test(document.readyState);
};
checks.push(complete);
if (!complete()) {
if (readystatechange)
doc.on('readystatechange', check);
else
shouldPoll = true;
} else {
domready();
}
}
if (test.doScroll) {
var scrolls = function () {
try {
test.doScroll();
return true;
} catch (e) {
}
return false;
};
if (!scrolls()) {
checks.push(scrolls);
shouldPoll = true;
}
}
if (shouldPoll)
poll();
doc.on('DOMContentLoaded', domready);
win.on('load', domready);
module.exports = function (ready) {
loaded ? ready() : readys.push(ready);
return null;
};
},
'3': function (require, module, exports, global) {
'use strict';
var $ = require('4'), prime = require('1'), Emitter = require('8');
var html = document.documentElement;
var addEventListener = html.addEventListener ? function (node, event, handle) {
node.addEventListener(event, handle, false);
return handle;
} : function (node, event, handle) {
node.attachEvent('on' + event, handle);
return handle;
};
var removeEventListener = html.removeEventListener ? function (node, event, handle) {
node.removeEventListener(event, handle, false);
} : function (node, event, handle) {
node.detachEvent('on' + event, handle);
};
$.implement({
on: function (event, handle) {
this.forEach(function (node) {
var self = $(node);
Emitter.prototype.on.call(self, event, handle);
var domListeners = self._domListeners || (self._domListeners = {});
if (!domListeners[event])
domListeners[event] = addEventListener(node, event, function (e) {
self.emit(event, e || window.event);
});
});
return this;
},
off: function (event, handle) {
this.forEach(function (node) {
var self = $(node);
var domListeners = self._domListeners, domEvent, listeners = self._listeners, events;
if (domListeners && (domEvent = domListeners[event]) && listeners && (events = listeners[event])) {
Emitter.prototype.off.call(self, event, handle);
var empty = true, k, l;
for (k in events) {
empty = false;
break;
}
if (empty) {
removeEventListener(node, event, domEvent);
delete domListeners[event];
for (l in domListeners)
empty = false;
if (empty)
delete self._domListeners;
}
}
});
return this;
},
emit: function (event) {
var args = arguments;
this.forEach(function (node) {
Emitter.prototype.emit.apply($(node), args);
});
return this;
}
});
module.exports = $;
},
'4': function (require, module, exports, global) {
'use strict';
var prime = require('1'), array = require('5').prototype;
var uniqueIndex = 0;
var uniqueID = function (n) {
return n === global ? 'global' : n.uniqueNumber || (n.uniqueNumber = 'n:' + (uniqueIndex++).toString(36));
};
var instances = {};
var $ = prime({
constructor: function $(n, context) {
if (n == null)
return this && this.constructor === $ ? new elements() : null;
var self = n;
if (n.constructor !== elements) {
self = new elements();
var uid;
if (typeof n === 'string') {
if (!self.search)
return null;
self[self.length++] = context || document;
return self.search(n);
}
if (n.nodeType || n === global) {
self[self.length++] = n;
} else if (n.length) {
var uniques = {};
for (var i = 0, l = n.length; i < l; i++) {
var nodes = $(n[i], context);
if (nodes && nodes.length)
for (var j = 0, k = nodes.length; j < k; j++) {
var node = nodes[j];
uid = uniqueID(node);
if (!uniques[uid]) {
self[self.length++] = node;
uniques[uid] = true;
}
}
}
}
}
if (!self.length)
return null;
if (self.length === 1) {
uid = uniqueID(self[0]);
return instances[uid] || (instances[uid] = self);
}
return self;
}
});
var elements = prime({
inherits: $,
constructor: function elements() {
this.length = 0;
},
unlink: function () {
return this.map(function (node, i) {
delete instances[uniqueID(node)];
return node;
});
},
forEach: array.forEach,
map: array.map,
filter: array.filter,
every: array.every,
some: array.some
});
module.exports = $;
},
'5': function (require, module, exports, global) {
'use strict';
var array = require('6')['array'];
var names = ('pop,push,reverse,shift,sort,splice,unshift,concat,join,slice,toString,indexOf,lastIndexOf,forEach,every,some' + ',filter,map,reduce,reduceRight').split(',');
for (var methods = {}, i = 0, name, method; name = names[i++];)
if (method = Array.prototype[name])
methods[name] = method;
if (!methods.filter)
methods.filter = function (fn, context) {
var results = [];
for (var i = 0, l = this.length >>> 0; i < l; i++)
if (i in this) {
var value = this[i];
if (fn.call(context, value, i, this))
results.push(value);
}
return results;
};
if (!methods.indexOf)
methods.indexOf = function (item, from) {
for (var l = this.length >>> 0, i = from < 0 ? Math.max(0, l + from) : from || 0; i < l; i++) {
if (i in this && this[i] === item)
return i;
}
return -1;
};
if (!methods.map)
methods.map = function (fn, context) {
var length = this.length >>> 0, results = Array(length);
for (var i = 0, l = length; i < l; i++) {
if (i in this)
results[i] = fn.call(context, this[i], i, this);
}
return results;
};
if (!methods.every)
methods.every = function (fn, context) {
for (var i = 0, l = this.length >>> 0; i < l; i++) {
if (i in this && !fn.call(context, this[i], i, this))
return false;
}
return true;
};
if (!methods.some)
methods.some = function (fn, context) {
for (var i = 0, l = this.length >>> 0; i < l; i++) {
if (i in this && fn.call(context, this[i], i, this))
return true;
}
return false;
};
if (!methods.forEach)
methods.forEach = function (fn, context) {
for (var i = 0, l = this.length >>> 0; i < l; i++) {
if (i in this)
fn.call(context, this[i], i, this);
}
};
var toString = Object.prototype.toString;
array.isArray = Array.isArray || function (self) {
return toString.call(self) === '[object Array]';
};
module.exports = array.implement(methods);
},
'6': function (require, module, exports, global) {
'use strict';
var prime = require('1'), type = require('7');
var slice = Array.prototype.slice;
var ghost = prime({
constructor: function ghost(self) {
this.valueOf = function () {
return self;
};
this.toString = function () {
return self + '';
};
this.is = function (object) {
return self === object;
};
}
});
var shell = function (self) {
if (self == null || self instanceof ghost)
return self;
var g = shell[type(self)];
return g ? new g(self) : self;
};
var register = function () {
var g = prime({ inherits: ghost });
return prime({
constructor: function (self) {
return new g(self);
},
define: function (key, descriptor) {
var method = descriptor.value;
this[key] = function (self) {
return arguments.length > 1 ? method.apply(self, slice.call(arguments, 1)) : method.call(self);
};
g.prototype[key] = function () {
return shell(method.apply(this.valueOf(), arguments));
};
prime.define(this.prototype, key, descriptor);
return this;
}
});
};
for (var types = 'string,number,array,object,date,function,regexp'.split(','), i = types.length; i--;)
shell[types[i]] = register();
module.exports = shell;
},
'7': function (require, module, exports, global) {
'use strict';
var toString = Object.prototype.toString, types = /number|object|array|string|function|date|regexp|boolean/;
var type = function (object) {
if (object == null)
return 'null';
var string = toString.call(object).slice(8, -1).toLowerCase();
if (string === 'number' && isNaN(object))
return 'null';
if (types.test(string))
return string;
return 'object';
};
module.exports = type;
},
'8': function (require, module, exports, global) {
'use strict';
var prime = require('1'), slice = Array.prototype.slice;
var EID = 0;
module.exports = prime({
on: function (event, fn) {
var listeners = this._listeners || (this._listeners = {}), events = listeners[event] || (listeners[event] = {});
for (var k in events)
if (events[k] === fn)
return this;
events[(EID++).toString(36)] = fn;
return this;
},
off: function (event, fn) {
var listeners = this._listeners, events, key, length = 0;
if (listeners && (events = listeners[event])) {
for (var k in events) {
length++;
if (key == null && events[k] === fn)
key = k;
if (key && length > 1)
break;
}
if (key) {
delete events[key];
if (length === 1) {
delete listeners[event];
for (var l in listeners)
return this;
delete this._listeners;
}
}
}
return this;
},
emit: function (event) {
var listeners = this._listeners, events;
if (listeners && (events = listeners[event])) {
var args = arguments.length > 1 ? slice.call(arguments, 1) : [];
for (var k in events)
events[k].apply(this, args);
}
return this;
}
});
},
'9': function (require, module, exports, global) {
'use strict';
var $ = require('4'), string = require('a'), array = require('5');
$.implement({
setAttribute: function (name, value) {
this.forEach(function (node) {
node.setAttribute(name, value);
});
return this;
},
getAttribute: function (name) {
var attr = this[0].getAttributeNode(name);
return attr && attr.specified ? attr.value : null;
},
hasAttribute: function (name) {
var node = this[0];
if (node.hasAttribute)
return node.hasAttribute(name);
var attr = node.getAttributeNode(name);
return !!(attr && attr.specified);
},
removeAttribute: function (name) {
this.forEach(function (node) {
var attr = node.getAttributeNode(name);
if (attr)
node.removeAttributeNode(attr);
});
return this;
}
});
var accessors = {};
array.forEach('type,value,name,href,title,id'.split(','), function (name) {
accessors[name] = function (value) {
if (value !== undefined) {
this.forEach(function (node) {
node[name] = value;
});
return this;
}
return this[0][name];
};
});
array.forEach('checked,disabled,selected'.split(','), function (name) {
accessors[name] = function (value) {
if (value !== undefined) {
this.forEach(function (node) {
node[name] = !!value;
});
return this;
}
return !!this[0][name];
};
});
var classes = function (className) {
var classNames = string.clean(className).split(' '), uniques = {};
return array.filter(classNames, function (className) {
if (className !== '' && !uniques[className])
return uniques[className] = className;
}).sort();
};
accessors.className = function (className) {
if (className !== undefined) {
this.forEach(function (node) {
node.className = classes(className).join(' ');
});
return this;
}
return classes(this[0].className).join(' ');
};
$.implement({
attribute: function (name, value) {
var accessor = accessors[name];
if (accessor)
return accessor.call(this, value);
if (value != null)
return this.setAttribute(name, value);
if (value === null)
return this.removeAttribute(name);
if (value === undefined)
return this.getAttribute(name);
}
});
$.implement(accessors);
$.implement({
check: function () {
return this.checked(true);
},
uncheck: function () {
return this.checked(false);
},
disable: function () {
return this.disabled(true);
},
enable: function () {
return this.disabled(false);
},
select: function () {
return this.selected(true);
},
deselect: function () {
return this.selected(false);
}
});
$.implement({
classNames: function () {
return classes(this[0].className);
},
hasClass: function (className) {
return array.indexOf(this.classNames(), className) > -1;
},
addClass: function (className) {
this.forEach(function (node) {
var nodeClassName = node.className;
var classNames = classes(nodeClassName + ' ' + className).join(' ');
if (nodeClassName != classNames)
node.className = classNames;
});
return this;
},
removeClass: function (className) {
this.forEach(function (node) {
var classNames = classes(node.className);
array.forEach(classes(className), function (className) {
var index = array.indexOf(classNames, className);
if (index > -1)
classNames.splice(index, 1);
});
node.className = classNames.join(' ');
});
return this;
}
});
$.prototype.toString = function () {
var tag = this.tag(), id = this.id(), classes = this.classNames();
var str = tag;
if (id)
str += '#' + id;
if (classes.length)
str += '.' + classes.join('.');
return str;
};
var textProperty = document.createElement('div').textContent == null ? 'innerText' : 'textContent';
$.implement({
tag: function () {
return this[0].tagName.toLowerCase();
},
html: function (html) {
if (html != null) {
this.forEach(function (node) {
node.innerHTML = html;
});
return this;
}
return this[0].innerHTML;
},
text: function (text) {
if (text != undefined) {
this.forEach(function (node) {
node[textProperty] = text;
});
return this;
}
return this[0][textProperty];
}
});
module.exports = $;
},
'a': function (require, module, exports, global) {
'use strict';
var string = require('b');
string.implement({
clean: function () {
return string.trim((this + '').replace(/\s+/g, ' '));
},
camelize: function () {
return (this + '').replace(/-\D/g, function (match) {
return match.charAt(1).toUpperCase();
});
},
hyphenate: function () {
return (this + '').replace(/[A-Z]/g, function (match) {
return '-' + match.toLowerCase();
});
},
capitalize: function () {
return (this + '').replace(/\b[a-z]/g, function (match) {
return match.toUpperCase();
});
},
escape: function () {
return (this + '').replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
},
number: function () {
return parseFloat(this);
}
});
if (typeof JSON !== 'undefined')
string.implement({
decode: function () {
return JSON.parse(this);
}
});
module.exports = string;
},
'b': function (require, module, exports, global) {
'use strict';
var string = require('6')['string'];
var names = ('charAt,charCodeAt,concat,contains,endsWith,indexOf,lastIndexOf,localeCompare,match,replace,search,slice,split' + ',startsWith,substr,substring,toLocaleLowerCase,toLocaleUpperCase,toLowerCase,toString,toUpperCase,trim,valueOf').split(',');
for (var methods = {}, i = 0, name, method; name = names[i++];)
if (method = String.prototype[name])
methods[name] = method;
if (!methods.trim)
methods.trim = function () {
return (this + '').replace(/^\s+|\s+$/g, '');
};
module.exports = string.implement(methods);
},
'c': function (require, module, exports, global) {
'use strict';
var $ = require('3'), Map = require('d');
require('e');
$.implement({
delegate: function (event, selector, handle) {
this.forEach(function (node) {
var self = $(node);
var delegation = self._delegation || (self._delegation = {}), events = delegation[event] || (delegation[event] = {}), map = events[selector] || (events[selector] = new Map());
var action = function (e) {
var target = $(e.target), match = target.matches(selector) ? target : target.parent(selector);
if (match)
handle.call(self, e, match);
};
map.set(handle, action);
self.on(event, action);
});
return this;
},
undelegate: function (event, selector, handle) {
this.forEach(function (node) {
var self = $(node), delegation, events, map;
if (!(delegation = self._delegation) || !(events = delegation[event]) || !(map = events[selector]))
return;
var action = map.get(handle);
if (action) {
self.off(event, action);
map.remove(handle);
if (!map.count())
delete events[selector];
var e1 = true, e2 = true, x;
for (x in events) {
e1 = false;
break;
}
if (e1)
delete delegation[event];
for (x in delegation) {
e2 = false;
break;
}
if (!e2)
delete self._delegation;
}
});
return this;
}
});
module.exports = $;
},
'd': function (require, module, exports, global) {
'use strict';
var prime = require('1'), array = require('5');
var Map = prime({
constructor: function () {
if (!this || this.constructor !== Map)
return new Map();
this.length = 0;
this._values = [];
this._keys = [];
},
set: function (key, value) {
var index = array.indexOf(this._keys, key);
if (index === -1) {
this._keys.push(key);
this._values.push(value);
this.length++;
} else {
this._values[index] = value;
}
return this;
},
get: function (key) {
var index = array.indexOf(this._keys, key);
return index === -1 ? null : this._values[index];
},
count: function () {
return this.length;
},
each: function (method, context) {
for (var i = 0, l = this.length; i < l; i++) {
if (method.call(context, this._values[i], this._keys[i], this) === false)
break;
}
return this;
},
backwards: function (method, context) {
for (var i = this.length - 1; i >= 0; i--) {
if (method.call(context, this._values[i], this._keys[i], this) === false)
break;
}
return this;
},
map: function (method, context) {
var results = new Map();
this.each(function (value, key) {
results.set(key, method.call(context, value, key, this));
}, this);
return results;
},
filter: function (method, context) {
var results = new Map();
this.each(function (value, key) {
if (method.call(context, value, key, this))
results.set(key, value);
}, this);
return results;
},
every: function (method, context) {
var every = true;
this.each(function (value, key) {
if (!method.call(context, value, key, this))
return every = false;
}, this);
return every;
},
some: function (method, context) {
var some = false;
this.each(function (value, key) {
if (method.call(context, value, key, this))
return !(some = true);
}, this);
return some;
},
index: function (value) {
var index = array.indexOf(this._values, value);
return index > -1 ? this._keys[index] : null;
},
remove: function (key) {
var index = array.indexOf(this._keys, key);
if (index !== -1) {
this._keys.splice(index, 1);
this.length--;
return this._values.splice(index, 1)[0];
}
return null;
},
keys: function () {
return this._keys.slice();
},
values: function () {
return this._values.slice();
}
});
module.exports = Map;
},
'e': function (require, module, exports, global) {
'use strict';
var $ = require('4'), array = require('5'), slick = require('f');
var walk = function (combinator, method) {
return function (expression) {
var parts = slick.parse(expression || '*');
expression = array.map(parts, function (part) {
return combinator + ' ' + part;
}).join(', ');
return this[method](expression);
};
};
$.implement({
search: function (expression) {
if (this.length === 1)
return $(slick.search(expression, this[0], new $()));
var buffer = [];
for (var i = 0, node; node = this[i]; i++)
buffer.push.apply(buffer, slick.search(expression, node));
return $(buffer).sort();
},
find: function (expression) {
if (this.length === 1)
return $(slick.find(expression, this[0]));
var buffer = [];
for (var i = 0, node; node = this[i]; i++)
buffer.push(slick.find(expression, node));
return $(buffer);
},
sort: function () {
return slick.sort(this);
},
matches: function (expression) {
return slick.matches(this[0], expression);
},
nextSiblings: walk('~', 'search'),
nextSibling: walk('+', 'find'),
previousSiblings: walk('!~', 'search'),
previousSibling: walk('!+', 'find'),
children: walk('>', 'search'),
firstChild: walk('^', 'find'),
lastChild: walk('!^', 'find'),
parent: function (expression) {
for (var i = 0, node; node = this[i]; i++)
while (node = node.parentNode) {
if (!expression || slick.matches(node, expression))
return $(node);
}
return null;
},
parents: function (expression) {
var buffer = [];
for (var i = 0, node; node = this[i]; i++)
while (node = node.parentNode) {
if (!expression || slick.matches(node, expression))
buffer.push(node);
}
return $(buffer);
}
});
module.exports = $;
},
'f': function (require, module, exports, global) {
'use strict';
var parse = require('g');
var uniqueIndex = 0;
var uniqueID = function (node) {
return node.uniqueNumber || (node.uniqueNumber = 's:' + uniqueIndex++);
};
var uniqueIDXML = function (node) {
var uid = node.getAttribute('uniqueNumber');
if (!uid) {
uid = 's:' + uniqueIndex++;
node.setAttribute('uniqueNumber', uid);
}
return uid;
};
var isArray = Array.isArray || function (object) {
return Object.prototype.toString.call(object) === '[object Array]';
};
var HAS = {
GET_ELEMENT_BY_ID: function (test, id) {
test.innerHTML = '<a id="' + id + '"></a>';
return !!this.getElementById(id);
},
QUERY_SELECTOR: function (test) {
test.innerHTML = '_<style>:nth-child(2){}</style>';
test.innerHTML = '<a class="MiX"></a>';
return test.querySelectorAll('.MiX').length === 1;
},
EXPANDOS: function (test, id) {
test._custom_property_ = id;
return test._custom_property_ === id;
},
MATCHES_SELECTOR: function (test) {
test.innerHTML = '<a class="MiX"></a>';
var matches = test.matchesSelector || test.mozMatchesSelector || test.webkitMatchesSelector;
if (matches)
try {
matches.call(test, ':slick');
} catch (e) {
return matches.call(test, '.MiX') ? matches : false;
}
return false;
},
GET_ELEMENTS_BY_CLASS_NAME: function (test) {
test.innerHTML = '<a class="f"></a><a class="b"></a>';
if (test.getElementsByClassName('b').length !== 1)
return false;
test.firstChild.className = 'b';
if (test.getElementsByClassName('b').length !== 2)
return false;
test.innerHTML = '<a class="a"></a><a class="f b a"></a>';
if (test.getElementsByClassName('a').length !== 2)
return false;
return true;
},
GET_ATTRIBUTE: function (test) {
var shout = 'fus ro dah';
test.innerHTML = '<a class="' + shout + '"></a>';
return test.firstChild.getAttribute('class') === shout;
}
};
var Finder = function Finder(document) {
this.document = document;
var root = this.root = document.documentElement;
this.tested = {};
this.uniqueID = this.has('EXPANDOS') ? uniqueID : uniqueIDXML;
this.getAttribute = this.has('GET_ATTRIBUTE') ? function (node, name) {
return node.getAttribute(name);
} : function (node, name) {
var node = node.getAttributeNode(name);
return node && node.specified ? node.value : null;
};
this.hasAttribute = root.hasAttribute ? function (node, attribute) {
return node.hasAttribute(attribute);
} : function (node, attribute) {
node = node.getAttributeNode(attribute);
return !!(node && node.specified);
};
this.contains = document.contains && root.contains ? function (context, node) {
return context.contains(node);
} : root.compareDocumentPosition ? function (context, node) {
return context === node || !!(context.compareDocumentPosition(node) & 16);
} : function (context, node) {
do {
if (node === context)
return true;
} while (node = node.parentNode);
return false;
};
this.sorter = root.compareDocumentPosition ? function (a, b) {
if (!a.compareDocumentPosition || !b.compareDocumentPosition)
return 0;
return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
} : 'sourceIndex' in root ? function (a, b) {
if (!a.sourceIndex || !b.sourceIndex)
return 0;
return a.sourceIndex - b.sourceIndex;
} : document.createRange ? function (a, b) {
if (!a.ownerDocument || !b.ownerDocument)
return 0;
var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
aRange.setStart(a, 0);
aRange.setEnd(a, 0);
bRange.setStart(b, 0);
bRange.setEnd(b, 0);
return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
} : null;
this.failed = {};
var nativeMatches = this.has('MATCHES_SELECTOR');
if (nativeMatches)
this.matchesSelector = function (node, expression) {
if (this.failed[expression])
return true;
try {
return nativeMatches.call(node, expression);
} catch (e) {
if (slick.debug)
console.warn('matchesSelector failed on ' + expression);
return this.failed[expression] = true;
}
};
if (this.has('QUERY_SELECTOR')) {
this.querySelectorAll = function (node, expression) {
if (this.failed[expression])
return true;
var result, _id, _expression, _slick_id, _combinator;
if (node !== this.document) {
_combinator = expression[0].combinator;
_id = node.getAttribute('id');
_expression = expression;
if (!_id) {
_slick_id = true;
_id = '__slick__';
node.setAttribute('id', _id);
}
expression = '#' + _id + ' ' + _expression;
if (_combinator.indexOf('~') > -1 || _combinator.indexOf('+') > -1) {
node = node.parentNode;
if (!node)
result = true;
}
}
if (!result)
try {
result = node.querySelectorAll(expression);
} catch (e) {
if (slick.debug)
console.warn('querySelectorAll failed on ' + (_expression || expression));
result = this.failed[_expression || expression] = true;
}
if (_slick_id)
node.removeAttribute('id');
return result;
};
}
};
Finder.prototype.has = function (FEATURE) {
var tested = this.tested, testedFEATURE = tested[FEATURE];
if (testedFEATURE != null)
return testedFEATURE;
var root = this.root, document = this.document, testNode = document.createElement('div');
testNode.setAttribute('style', 'display: none;');
root.appendChild(testNode);
var TEST = HAS[FEATURE], result = false;
if (TEST)
try {
result = TEST.call(document, testNode, 's:' + uniqueIndex++);
} catch (e) {
}
if (slick.debug && !result)
console.warn('document has no ' + FEATURE);
root.removeChild(testNode);
return tested[FEATURE] = result;
};
var combinators = {
' ': function (node, part, push) {
var item, items;
var noId = !part.id, noTag = !part.tag, noClass = !part.classes;
if (part.id && node.getElementById && this.has('GET_ELEMENT_BY_ID')) {
item = node.getElementById(part.id);
if (item && item.getAttribute('id') === part.id) {
items = [item];
noId = true;
if (part.tag === '*')
noTag = true;
}
}
if (!items) {
if (part.classes && node.getElementsByClassName && this.has('GET_ELEMENTS_BY_CLASS_NAME')) {
items = node.getElementsByClassName(part.classList);
noClass = true;
if (part.tag === '*')
noTag = true;
} else {
items = node.getElementsByTagName(part.tag);
if (part.tag !== '*')
noTag = true;
}
if (!items || !items.length)
return false;
}
for (var i = 0; item = items[i++];)
if (noTag && noId && noClass && !part.attributes && !part.pseudos || this.match(item, part, noTag, noId, noClass))
push(item);
return true;
},
'>': function (node, part, push) {
if (node = node.firstChild)
do {
if (node.nodeType == 1 && this.match(node, part))
push(node);
} while (node = node.nextSibling);
},
'+': function (node, part, push) {
while (node = node.nextSibling)
if (node.nodeType == 1) {
if (this.match(node, part))
push(node);
break;
}
},
'^': function (node, part, push) {
node = node.firstChild;
if (node) {
if (node.nodeType === 1) {
if (this.match(node, part))
push(node);