Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding in site wide search, crappy but it works!
- Loading branch information
Showing
4 changed files
with
270 additions
and
8 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
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,182 @@ | ||
var JSONSearch = function(options) { | ||
|
||
this.default_options = { | ||
fields: {}, | ||
ranks: {}, | ||
limit: null, | ||
offset: 0, | ||
case_sensitive: false | ||
}; | ||
|
||
this.patterns = { | ||
infix: '.*$token.*', | ||
prefix: '^$token.*', | ||
exact: '^$token$', | ||
word: '\\b$token\\b', | ||
word_prefix: '\\b$token.*' | ||
}; | ||
|
||
this.query_string = ''; | ||
this.query_function = "1&&function(object) { var hits = 0, ranks_array = []; #{query_string} if (hits > 0) { return [(ranks_array.sort()[ranks_array.length - 1] || 0), hits, object]; } }"; | ||
|
||
this.initialize(options); | ||
}; | ||
|
||
JSONSearch.InstanceMethods = { | ||
initialize: function(options) { | ||
this.options = {}; | ||
for(var property in this.default_options) { | ||
this.options[property] = this.default_options[property] | ||
}; | ||
for(var property in options) { | ||
this.options[property] = options[property]; | ||
} | ||
this.setAttributes(options); | ||
this.buildMatcherTemplates(); | ||
this.buildQueryString(); | ||
}, | ||
|
||
setAttributes: function() { | ||
var args = ['fields', 'limit', 'offset', 'case_sensitive']; | ||
for(var i = 0; i < args.length; i++) { | ||
this[args[i]] = this.options[args[i]]; | ||
}; | ||
this.ranks = this.getRanks(); | ||
this.fields_ordered_by_rank = this.fieldsOrderedByRank(); | ||
}, | ||
|
||
buildMatcherTemplates: function() { | ||
for(var property in this.patterns) { | ||
this[property + '_matcher'] = 'if(/' + this.patterns[property] + '/#{regex_options}.test(object["#{name}"])){hits++;ranks_array.push(ranks["#{name}"]);}'; | ||
}; | ||
}, | ||
|
||
getRanks: function(object) { | ||
var ranks = {}; | ||
for(var property in this.fields) { | ||
ranks[property] = (this.options.ranks && this.options.ranks[property] || 0); | ||
}; | ||
return ranks; | ||
}, | ||
|
||
// TODO if ranks are all 0 might just use the format order if supplied | ||
fieldsOrderedByRank: function() { | ||
var fields_ordered_by_rank = []; | ||
for(var property in this.ranks){ | ||
fields_ordered_by_rank.push([this.ranks['property'], property]); | ||
}; | ||
fields_ordered_by_rank = fields_ordered_by_rank.sort().reverse(); | ||
for(var i = 0; i < fields_ordered_by_rank.length; i++) { | ||
fields_ordered_by_rank[i] = fields_ordered_by_rank[i][1]; | ||
} | ||
return fields_ordered_by_rank; | ||
}, | ||
|
||
buildQueryString: function() { | ||
var query_string_array = [], field; | ||
for(var i = 0; i < this.fields_ordered_by_rank.length; i++) { | ||
field = this.fields_ordered_by_rank[i]; | ||
query_string_array.push(this.buildMatcher(field, this.fields[field])); | ||
} | ||
this.query_string = query_string_array.join(''); | ||
}, | ||
|
||
buildMatcher: function(name, pattern) { | ||
return this.subMatcher(this[pattern + '_matcher'], { name: name, regex_options: this.getRegexOptions() }); | ||
}, | ||
|
||
subMatcher: function(matcher, object) { | ||
var subbed_matcher = matcher; | ||
for(var property in object) { | ||
subbed_matcher = subbed_matcher.replace('#{' + property + '}', object[property], 'g') | ||
} | ||
return subbed_matcher; | ||
}, | ||
|
||
subQueryString: function(token) { | ||
return this.query_string.replace(/\$token/g, this.regexEscape(token)); | ||
}, | ||
|
||
subQueryFunction: function(object) { | ||
var subbed_query_function; | ||
for(var property in object) { | ||
subbed_query_function = this.query_function.replace('#{' + property + '}', object[property], 'g') | ||
} | ||
return subbed_query_function; | ||
}, | ||
|
||
//TODO add an options object to pass limit/offset. | ||
getResults: function(token, object) { | ||
object = this.evalJSON(object); | ||
if (!(object instanceof Array)) { | ||
object = [object]; | ||
} | ||
var results, subbed_query_string = this.subQueryString(token); | ||
results = this.getFilteredResults(subbed_query_string, object); | ||
results = this.sortResults(results); | ||
results = this.limitResults(results); | ||
return this.cleanResults(results); | ||
}, | ||
|
||
getFilteredResults: function(query_string, array) { | ||
var results = [], ranks = this.ranks, result, len = (array.length), query_string = (query_string || ''); | ||
var query_function = eval(this.subQueryFunction({ query_string: query_string })); | ||
|
||
for(var i = 0; i < len; ++i) { | ||
if(result = query_function(array[i])) { | ||
results.push(result); | ||
} | ||
} | ||
return results; | ||
}, | ||
|
||
sortResults: function(results) { | ||
return results.sort().reverse(); | ||
}, | ||
|
||
limitResults: function(results) { | ||
if (this.limit) { | ||
return results.slice(this.offset, (this.limit + this.offset)); | ||
} else if (this.offset > 0) { | ||
return results.slice(this.offset, (results.length)); | ||
} else { | ||
return results; | ||
} | ||
}, | ||
|
||
cleanResults: function(results) { | ||
var clean_results = []; len = (results.length); | ||
for(var i = 0; i < len; ++i) { | ||
clean_results.push(results[i][2]); | ||
} | ||
return clean_results; | ||
}, | ||
|
||
evalJSON: function(json) { | ||
if (typeof json == 'string') { | ||
try { | ||
json = eval('(' + json + ')'); | ||
} catch(e) { | ||
throw new SyntaxError('Badly formed JSON string'); | ||
} | ||
} | ||
return json; | ||
}, | ||
|
||
getRegex: function(token, pattern) { | ||
return new RegExp(this.patterns[pattern].replace(/\$token/, this.regexEscape(token)), this.getRegexOptions()); | ||
}, | ||
|
||
getRegexOptions: function() { | ||
return (this.case_sensitive && '' || 'i'); | ||
}, | ||
|
||
regexEscape: function(string) { | ||
return String(string).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); | ||
} | ||
} | ||
|
||
for(var property in JSONSearch.InstanceMethods) { | ||
JSONSearch.prototype[property] = JSONSearch.InstanceMethods[property] | ||
} | ||
delete JSONSearch.InstanceMethods; |
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