diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index c8c36147d..b100c9f73 100755 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -3,10 +3,13 @@ ### Version 2.3.0 - Feb 19, 2018 **Major Enhancements** +- **Search** - Category search can now work with local search by adding a `category` property to any result and specifying `type: 'category'` +- **Search** - Category results now has `exact` matching - **Modal** - Modal has been rewritten to use `flexbox`. No need to call `refresh()` to recalculate vertical centering. - **Modal** - Modals now have a setting `centered` which can be used to disable vertical centering. This can be useful for modals with content that changes dynamically to prevent content from jumping in position. **Enhancements** +- **Search** - Category results will now responsively adjust `title` row if titles are long instead of forcing a title width - **Dimmer** - Dimmers now have centered content with a single wrapping `content` element. - **Popup** - Popup will now align the center of the arrow (not the edge of the popup) when it would be reasonable (up to 2x arrow's offset from edge). [See this explanation](http://oi66.tinypic.com/2zr2ckk.jpg) - **Popup** - Popup can now position elements correctly even when they have a different offset context than their activating element. Like in [this example](https://jsfiddle.net/g853mc03/) diff --git a/src/definitions/modules/search.js b/src/definitions/modules/search.js index 88a71929d..c06ab1b49 100644 --- a/src/definitions/modules/search.js +++ b/src/definitions/modules/search.js @@ -70,6 +70,7 @@ $.fn.search = function(parameters) { initialize: function() { module.verbose('Initializing module'); + module.get.settings(); module.determine.searchFields(); module.bind.events(); module.set.type(); @@ -402,6 +403,12 @@ $.fn.search = function(parameters) { }, get: { + settings: function() { + if($.isPlainObject(parameters) && parameters.searchFullText) { + settings.fullTextSearch = parameters.searchFullText; + module.error(settings.error.oldSearchSyntax, element); + } + }, inputEvent: function() { var prompt = $prompt[0], @@ -545,8 +552,14 @@ $.fn.search = function(parameters) { ; module.set.loading(); module.save.results(results); - module.debug('Returned local search results', results); - + module.debug('Returned full local search results', results); + if(settings.maxResults > 0) { + module.debug('Using specified max results', results); + results = results.slice(0, settings.maxResults); + } + if(settings.type == 'category') { + results = module.create.categoryResults(results); + } searchHTML = module.generateResults({ results: results }); @@ -574,6 +587,7 @@ $.fn.search = function(parameters) { object: function(searchTerm, source, searchFields) { var results = [], + exactResults = [], fuzzyResults = [], searchExp = searchTerm.toString().replace(regExp.escape, '\\$&'), matchRegExp = new RegExp(regExp.beginsWith + searchExp, 'i'), @@ -605,7 +619,6 @@ $.fn.search = function(parameters) { module.error(error.source); return []; } - // iterate through search fields looking for matches $.each(searchFields, function(index, field) { $.each(source, function(label, content) { @@ -617,17 +630,30 @@ $.fn.search = function(parameters) { // content starts with value (first in results) addResult(results, content); } - else if(settings.searchFullText && module.fuzzySearch(searchTerm, content[field]) ) { + else if(settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, content[field]) ) { + // content fuzzy matches (last in results) + addResult(exactResults, content); + } + else if(settings.fullTextSearch == true && module.fuzzySearch(searchTerm, content[field]) ) { // content fuzzy matches (last in results) addResult(fuzzyResults, content); } } }); }); - return $.merge(results, fuzzyResults); + $.merge(exactResults, fuzzyResults) + $.merge(results, exactResults); + return results; } }, - + exactSearch: function (query, term) { + query = query.toLowerCase(); + term = term.toLowerCase(); + if(term.indexOf(query) > -1) { + return true; + } + return false; + }, fuzzySearch: function(query, term) { var termLength = term.length, @@ -739,6 +765,27 @@ $.fn.search = function(parameters) { }, create: { + categoryResults: function(results) { + var + categoryResults = {} + ; + $.each(results, function(index, result) { + if(!result.category) { + return; + } + if(categoryResults[result.category] === undefined) { + module.verbose('Creating new category of results', result.category); + categoryResults[result.category] = { + name : result.category, + results : [result] + } + } + else { + categoryResults[result.category].results.push(result); + } + }); + return categoryResults; + }, id: function(resultIndex, categoryIndex) { var resultID = (resultIndex + 1), // not zero indexed @@ -776,7 +823,10 @@ $.fn.search = function(parameters) { $selectedResult = (categoryIndex !== undefined) ? $results .children().eq(categoryIndex) - .children(selector.result).eq(resultIndex) + .children(selector.results) + .first() + .children(selector.result) + .eq(resultIndex) : $results .children(selector.result).eq(resultIndex) ; @@ -1197,8 +1247,8 @@ $.fn.search.settings = { // field to display in standard results template displayField : '', - // whether to include fuzzy results in local search - searchFullText : true, + // search anywhere in value (set to 'exact' to require exact matches + fullTextSearch : 'exact', // whether to add events to prompt automatically automatic : true, @@ -1209,7 +1259,7 @@ $.fn.search.settings = { // delay before searching searchDelay : 200, - // maximum results returned from local + // maximum results returned from search maxResults : 7, // whether to store lookups in local cache @@ -1245,14 +1295,15 @@ $.fn.search.settings = { }, error : { - source : 'Cannot search. No source used, and Semantic API module was not included', - noResults : 'Your search returned no results', - logging : 'Error in debug logging, exiting.', - noEndpoint : 'No search endpoint was specified', - noTemplate : 'A valid template name was not specified.', - serverError : 'There was an issue querying the server.', - maxResults : 'Results must be an array to use maxResults setting', - method : 'The method you called is not defined.' + source : 'Cannot search. No source used, and Semantic API module was not included', + noResults : 'Your search returned no results', + logging : 'Error in debug logging, exiting.', + noEndpoint : 'No search endpoint was specified', + noTemplate : 'A valid template name was not specified.', + oldSearchSyntax : 'searchFullText setting has been renamed fullTextSearch for consistency, please adjust your settings.', + serverError : 'There was an issue querying the server.', + maxResults : 'Results must be an array to use maxResults setting', + method : 'The method you called is not defined.' }, metadata: { @@ -1354,6 +1405,7 @@ $.fn.search.settings = { } // each item inside category + html += '