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 += '
'; $.each(category.results, function(index, result) { if(result[fields.url]) { html += ''; @@ -1383,6 +1435,7 @@ $.fn.search.settings = { ; html += ''; }); + html += '
'; html += '' + '' ; diff --git a/src/definitions/modules/search.less b/src/definitions/modules/search.less index 4d28567d9..5a41e87bb 100755 --- a/src/definitions/modules/search.less +++ b/src/definitions/modules/search.less @@ -315,11 +315,16 @@ width: @categoryResultsWidth; } +.ui.category.search .results.animating, +.ui.category.search .results.visible { + display: table; +} + /* Category */ .ui.category.search > .results .category { + display: table-row; background: @categoryBackground; box-shadow: @categoryBoxShadow; - border-bottom: @categoryDivider; transition: @categoryTransition; } @@ -336,30 +341,32 @@ border-radius: 0em 0em @resultsBorderRadius 0em; } -/* Category Result */ -.ui.category.search > .results .category .result { - background: @categoryResultBackground; - margin-left: @categoryNameWidth; - border-left: @categoryResultLeftBorder; - border-bottom: @categoryResultDivider; - transition: @categoryResultTransition; - padding: @categoryResultPadding; -} -.ui.category.search > .results .category:last-child .result:last-child { - border-bottom: @categoryResultLastDivider; -} - /* Category Result Name */ .ui.category.search > .results .category > .name { + display: table-cell; + text-overflow: ellipsis; width: @categoryNameWidth; + white-space: @categoryNameWhitespace; background: @categoryNameBackground; font-family: @categoryNameFont; font-size: @categoryNameFontSize; - float: @categoryNameFontSize; - float: @categoryNameFloat; padding: @categoryNamePadding; font-weight: @categoryNameFontWeight; color: @categoryNameColor; + border-bottom: @categoryDivider; +} + +/* Category Result */ +.ui.category.search > .results .category .results { + display: table-cell; + background: @categoryResultBackground; + border-left: @categoryResultLeftBorder; + border-bottom: @categoryDivider; +} +.ui.category.search > .results .category .result { + border-bottom: @categoryResultDivider; + transition: @categoryResultTransition; + padding: @categoryResultPadding; } /******************************* diff --git a/src/themes/default/modules/search.variables b/src/themes/default/modules/search.variables index c84249fb3..890cb11bf 100644 --- a/src/themes/default/modules/search.variables +++ b/src/themes/default/modules/search.variables @@ -152,7 +152,7 @@ @categoryNameBackground: transparent; @categoryNameFont: @pageFont; @categoryNameFontSize: 1em; -@categoryNameFloat: left; +@categoryNameWhitespace: nowrap; @categoryNamePadding: 0.4em 1em; @categoryNameFontWeight: bold; @categoryNameColor: @lightTextColor;