fomantic-ui-sass 2.8.8.1 → 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/app/assets/fonts/semantic-ui/Lato-Bold.woff +0 -0
  4. data/app/assets/fonts/semantic-ui/Lato-Bold.woff2 +0 -0
  5. data/app/assets/fonts/semantic-ui/Lato-BoldItalic.woff +0 -0
  6. data/app/assets/fonts/semantic-ui/Lato-BoldItalic.woff2 +0 -0
  7. data/app/assets/fonts/semantic-ui/Lato-Italic.woff +0 -0
  8. data/app/assets/fonts/semantic-ui/Lato-Italic.woff2 +0 -0
  9. data/app/assets/fonts/semantic-ui/Lato-Regular.woff +0 -0
  10. data/app/assets/fonts/semantic-ui/Lato-Regular.woff2 +0 -0
  11. data/app/assets/fonts/semantic-ui/LatoLatin-Bold.woff +0 -0
  12. data/app/assets/fonts/semantic-ui/LatoLatin-Bold.woff2 +0 -0
  13. data/app/assets/fonts/semantic-ui/LatoLatin-BoldItalic.woff +0 -0
  14. data/app/assets/fonts/semantic-ui/LatoLatin-BoldItalic.woff2 +0 -0
  15. data/app/assets/fonts/semantic-ui/LatoLatin-Italic.woff +0 -0
  16. data/app/assets/fonts/semantic-ui/LatoLatin-Italic.woff2 +0 -0
  17. data/app/assets/fonts/semantic-ui/LatoLatin-Regular.woff +0 -0
  18. data/app/assets/fonts/semantic-ui/LatoLatin-Regular.woff2 +0 -0
  19. data/app/assets/fonts/semantic-ui/brand-icons.eot +0 -0
  20. data/app/assets/fonts/semantic-ui/brand-icons.svg +41 -6
  21. data/app/assets/fonts/semantic-ui/brand-icons.ttf +0 -0
  22. data/app/assets/fonts/semantic-ui/brand-icons.woff +0 -0
  23. data/app/assets/fonts/semantic-ui/brand-icons.woff2 +0 -0
  24. data/app/assets/fonts/semantic-ui/icons.eot +0 -0
  25. data/app/assets/fonts/semantic-ui/icons.svg +245 -7
  26. data/app/assets/fonts/semantic-ui/icons.ttf +0 -0
  27. data/app/assets/fonts/semantic-ui/icons.woff +0 -0
  28. data/app/assets/fonts/semantic-ui/icons.woff2 +0 -0
  29. data/app/assets/fonts/semantic-ui/outline-icons.eot +0 -0
  30. data/app/assets/fonts/semantic-ui/outline-icons.svg +2 -2
  31. data/app/assets/fonts/semantic-ui/outline-icons.ttf +0 -0
  32. data/app/assets/fonts/semantic-ui/outline-icons.woff +0 -0
  33. data/app/assets/fonts/semantic-ui/outline-icons.woff2 +0 -0
  34. data/app/assets/javascripts/semantic-ui/accordion.js +569 -590
  35. data/app/assets/javascripts/semantic-ui/api.js +1153 -1116
  36. data/app/assets/javascripts/semantic-ui/calendar.js +1941 -1698
  37. data/app/assets/javascripts/semantic-ui/checkbox.js +862 -854
  38. data/app/assets/javascripts/semantic-ui/dimmer.js +697 -713
  39. data/app/assets/javascripts/semantic-ui/dropdown.js +4196 -4192
  40. data/app/assets/javascripts/semantic-ui/embed.js +646 -672
  41. data/app/assets/javascripts/semantic-ui/flyout.js +1579 -0
  42. data/app/assets/javascripts/semantic-ui/form.js +2024 -2000
  43. data/app/assets/javascripts/semantic-ui/modal.js +1546 -1384
  44. data/app/assets/javascripts/semantic-ui/nag.js +521 -527
  45. data/app/assets/javascripts/semantic-ui/popup.js +1457 -1463
  46. data/app/assets/javascripts/semantic-ui/progress.js +970 -995
  47. data/app/assets/javascripts/semantic-ui/rating.js +508 -520
  48. data/app/assets/javascripts/semantic-ui/search.js +1521 -1508
  49. data/app/assets/javascripts/semantic-ui/shape.js +784 -811
  50. data/app/assets/javascripts/semantic-ui/sidebar.js +1061 -1002
  51. data/app/assets/javascripts/semantic-ui/site.js +437 -477
  52. data/app/assets/javascripts/semantic-ui/slider.js +1311 -1297
  53. data/app/assets/javascripts/semantic-ui/state.js +639 -658
  54. data/app/assets/javascripts/semantic-ui/sticky.js +848 -891
  55. data/app/assets/javascripts/semantic-ui/tab.js +895 -941
  56. data/app/assets/javascripts/semantic-ui/toast.js +911 -851
  57. data/app/assets/javascripts/semantic-ui/transition.js +1049 -1073
  58. data/app/assets/javascripts/semantic-ui/visibility.js +1214 -1246
  59. data/app/assets/stylesheets/semantic-ui/collections/_breadcrumb.scss +7 -7
  60. data/app/assets/stylesheets/semantic-ui/collections/_form.scss +389 -407
  61. data/app/assets/stylesheets/semantic-ui/collections/_grid.scss +203 -345
  62. data/app/assets/stylesheets/semantic-ui/collections/_menu.scss +372 -501
  63. data/app/assets/stylesheets/semantic-ui/collections/_message.scss +154 -226
  64. data/app/assets/stylesheets/semantic-ui/collections/_table.scss +2065 -880
  65. data/app/assets/stylesheets/semantic-ui/elements/_button.scss +867 -1232
  66. data/app/assets/stylesheets/semantic-ui/elements/_container.scss +101 -6
  67. data/app/assets/stylesheets/semantic-ui/elements/_divider.scss +75 -93
  68. data/app/assets/stylesheets/semantic-ui/elements/_emoji.scss +11148 -9190
  69. data/app/assets/stylesheets/semantic-ui/elements/_flag.scss +1037 -929
  70. data/app/assets/stylesheets/semantic-ui/elements/_header.scss +124 -146
  71. data/app/assets/stylesheets/semantic-ui/elements/_icon.scss +2728 -2759
  72. data/app/assets/stylesheets/semantic-ui/elements/_image.scss +41 -65
  73. data/app/assets/stylesheets/semantic-ui/elements/_input.scss +982 -163
  74. data/app/assets/stylesheets/semantic-ui/elements/_label.scss +432 -479
  75. data/app/assets/stylesheets/semantic-ui/elements/_list.scss +80 -101
  76. data/app/assets/stylesheets/semantic-ui/elements/_loader.scss +452 -540
  77. data/app/assets/stylesheets/semantic-ui/elements/_placeholder.scss +56 -76
  78. data/app/assets/stylesheets/semantic-ui/elements/_rail.scss +17 -22
  79. data/app/assets/stylesheets/semantic-ui/elements/_reveal.scss +46 -85
  80. data/app/assets/stylesheets/semantic-ui/elements/_segment.scss +263 -255
  81. data/app/assets/stylesheets/semantic-ui/elements/_step.scss +106 -179
  82. data/app/assets/stylesheets/semantic-ui/elements/_text.scss +33 -33
  83. data/app/assets/stylesheets/semantic-ui/globals/_reset.scss +14 -18
  84. data/app/assets/stylesheets/semantic-ui/globals/_site.scss +132 -48
  85. data/app/assets/stylesheets/semantic-ui/modules/_accordion.scss +196 -74
  86. data/app/assets/stylesheets/semantic-ui/modules/_calendar.scss +43 -29
  87. data/app/assets/stylesheets/semantic-ui/modules/_checkbox.scss +210 -280
  88. data/app/assets/stylesheets/semantic-ui/modules/_dimmer.scss +78 -182
  89. data/app/assets/stylesheets/semantic-ui/modules/_dropdown.scss +339 -423
  90. data/app/assets/stylesheets/semantic-ui/modules/_embed.scss +24 -35
  91. data/app/assets/stylesheets/semantic-ui/modules/_flyout.scss +546 -0
  92. data/app/assets/stylesheets/semantic-ui/modules/_modal.scss +150 -153
  93. data/app/assets/stylesheets/semantic-ui/modules/_nag.scss +55 -65
  94. data/app/assets/stylesheets/semantic-ui/modules/_popup.scss +530 -310
  95. data/app/assets/stylesheets/semantic-ui/modules/_progress.scss +108 -213
  96. data/app/assets/stylesheets/semantic-ui/modules/_rating.scss +88 -168
  97. data/app/assets/stylesheets/semantic-ui/modules/_search.scss +73 -102
  98. data/app/assets/stylesheets/semantic-ui/modules/_shape.scss +16 -32
  99. data/app/assets/stylesheets/semantic-ui/modules/_sidebar.scss +126 -215
  100. data/app/assets/stylesheets/semantic-ui/modules/_slider.scss +110 -138
  101. data/app/assets/stylesheets/semantic-ui/modules/_sticky.scss +3 -7
  102. data/app/assets/stylesheets/semantic-ui/modules/_tab.scss +16 -20
  103. data/app/assets/stylesheets/semantic-ui/modules/_toast.scss +111 -141
  104. data/app/assets/stylesheets/semantic-ui/modules/_transition.scss +371 -1282
  105. data/app/assets/stylesheets/semantic-ui/views/_ad.scss +39 -50
  106. data/app/assets/stylesheets/semantic-ui/views/_card.scss +949 -458
  107. data/app/assets/stylesheets/semantic-ui/views/_comment.scss +44 -62
  108. data/app/assets/stylesheets/semantic-ui/views/_feed.scss +50 -72
  109. data/app/assets/stylesheets/semantic-ui/views/_item.scss +89 -136
  110. data/app/assets/stylesheets/semantic-ui/views/_statistic.scss +78 -119
  111. data/lib/fomantic/ui/sass/version.rb +2 -2
  112. data/tasks/converter.rb +1 -1
  113. metadata +21 -3
@@ -1,1567 +1,1580 @@
1
1
  /*!
2
2
  * # Fomantic-UI - Search
3
- * http://github.com/fomantic/Fomantic-UI/
3
+ * https://github.com/fomantic/Fomantic-UI/
4
4
  *
5
5
  *
6
6
  * Released under the MIT license
7
- * http://opensource.org/licenses/MIT
7
+ * https://opensource.org/licenses/MIT
8
8
  *
9
9
  */
10
10
 
11
- ;(function ($, window, document, undefined) {
12
-
13
- 'use strict';
14
-
15
- $.isFunction = $.isFunction || function(obj) {
16
- return typeof obj === "function" && typeof obj.nodeType !== "number";
17
- };
18
-
19
- window = (typeof window != 'undefined' && window.Math == Math)
20
- ? window
21
- : (typeof self != 'undefined' && self.Math == Math)
22
- ? self
23
- : Function('return this')()
24
- ;
25
-
26
- $.fn.search = function(parameters) {
27
- var
28
- $allModules = $(this),
29
- moduleSelector = $allModules.selector || '',
30
-
31
- time = new Date().getTime(),
32
- performance = [],
33
-
34
- query = arguments[0],
35
- methodInvoked = (typeof query == 'string'),
36
- queryArguments = [].slice.call(arguments, 1),
37
- returnedValue
38
- ;
39
- $(this)
40
- .each(function() {
41
- var
42
- settings = ( $.isPlainObject(parameters) )
43
- ? $.extend(true, {}, $.fn.search.settings, parameters)
44
- : $.extend({}, $.fn.search.settings),
45
-
46
- className = settings.className,
47
- metadata = settings.metadata,
48
- regExp = settings.regExp,
49
- fields = settings.fields,
50
- selector = settings.selector,
51
- error = settings.error,
52
- namespace = settings.namespace,
53
-
54
- eventNamespace = '.' + namespace,
55
- moduleNamespace = namespace + '-module',
56
-
57
- $module = $(this),
58
- $prompt = $module.find(selector.prompt),
59
- $searchButton = $module.find(selector.searchButton),
60
- $results = $module.find(selector.results),
61
- $result = $module.find(selector.result),
62
- $category = $module.find(selector.category),
63
-
64
- element = this,
65
- instance = $module.data(moduleNamespace),
66
-
67
- disabledBubbled = false,
68
- resultsDismissed = false,
69
-
70
- module
71
- ;
72
-
73
- module = {
74
-
75
- initialize: function() {
76
- module.verbose('Initializing module');
77
- module.get.settings();
78
- module.determine.searchFields();
79
- module.bind.events();
80
- module.set.type();
81
- module.create.results();
82
- module.instantiate();
83
- },
84
- instantiate: function() {
85
- module.verbose('Storing instance of module', module);
86
- instance = module;
87
- $module
88
- .data(moduleNamespace, module)
89
- ;
90
- },
91
- destroy: function() {
92
- module.verbose('Destroying instance');
93
- $module
94
- .off(eventNamespace)
95
- .removeData(moduleNamespace)
96
- ;
97
- },
11
+ (function ($, window, document) {
12
+ 'use strict';
98
13
 
99
- refresh: function() {
100
- module.debug('Refreshing selector cache');
101
- $prompt = $module.find(selector.prompt);
102
- $searchButton = $module.find(selector.searchButton);
103
- $category = $module.find(selector.category);
104
- $results = $module.find(selector.results);
105
- $result = $module.find(selector.result);
106
- },
14
+ function isFunction(obj) {
15
+ return typeof obj === 'function' && typeof obj.nodeType !== 'number';
16
+ }
107
17
 
108
- refreshResults: function() {
109
- $results = $module.find(selector.results);
110
- $result = $module.find(selector.result);
111
- },
18
+ window = window !== undefined && window.Math === Math
19
+ ? window
20
+ : globalThis;
112
21
 
113
- bind: {
114
- events: function() {
115
- module.verbose('Binding events to search');
116
- if(settings.automatic) {
117
- $module
118
- .on(module.get.inputEvent() + eventNamespace, selector.prompt, module.event.input)
119
- ;
120
- $prompt
121
- .attr('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
122
- ;
123
- }
124
- $module
125
- // prompt
126
- .on('focus' + eventNamespace, selector.prompt, module.event.focus)
127
- .on('blur' + eventNamespace, selector.prompt, module.event.blur)
128
- .on('keydown' + eventNamespace, selector.prompt, module.handleKeyboard)
129
- // search button
130
- .on('click' + eventNamespace, selector.searchButton, module.query)
131
- // results
132
- .on('mousedown' + eventNamespace, selector.results, module.event.result.mousedown)
133
- .on('mouseup' + eventNamespace, selector.results, module.event.result.mouseup)
134
- .on('click' + eventNamespace, selector.result, module.event.result.click)
135
- ;
136
- }
137
- },
22
+ $.fn.search = function (parameters) {
23
+ var
24
+ $allModules = $(this),
25
+ moduleSelector = $allModules.selector || '',
138
26
 
139
- determine: {
140
- searchFields: function() {
141
- // this makes sure $.extend does not add specified search fields to default fields
142
- // this is the only setting which should not extend defaults
143
- if(parameters && parameters.searchFields !== undefined) {
144
- settings.searchFields = parameters.searchFields;
145
- }
146
- }
147
- },
27
+ time = Date.now(),
28
+ performance = [],
148
29
 
149
- event: {
150
- input: function() {
151
- if(settings.searchDelay) {
152
- clearTimeout(module.timer);
153
- module.timer = setTimeout(function() {
154
- if(module.is.focused()) {
155
- module.query();
156
- }
157
- }, settings.searchDelay);
158
- }
159
- else {
160
- module.query();
161
- }
162
- },
163
- focus: function() {
164
- module.set.focus();
165
- if(settings.searchOnFocus && module.has.minimumCharacters() ) {
166
- module.query(function() {
167
- if(module.can.show() ) {
168
- module.showResults();
169
- }
170
- });
171
- }
172
- },
173
- blur: function(event) {
30
+ query = arguments[0],
31
+ methodInvoked = typeof query === 'string',
32
+ queryArguments = [].slice.call(arguments, 1),
33
+ returnedValue
34
+ ;
35
+ $allModules.each(function () {
174
36
  var
175
- pageLostFocus = (document.activeElement === this),
176
- callback = function() {
177
- module.cancel.query();
178
- module.remove.focus();
179
- module.timer = setTimeout(module.hideResults, settings.hideDelay);
180
- }
37
+ settings = $.isPlainObject(parameters)
38
+ ? $.extend(true, {}, $.fn.search.settings, parameters)
39
+ : $.extend({}, $.fn.search.settings),
40
+
41
+ className = settings.className,
42
+ metadata = settings.metadata,
43
+ regExp = settings.regExp,
44
+ fields = settings.fields,
45
+ selector = settings.selector,
46
+ error = settings.error,
47
+ namespace = settings.namespace,
48
+
49
+ eventNamespace = '.' + namespace,
50
+ moduleNamespace = namespace + '-module',
51
+
52
+ $module = $(this),
53
+ $prompt = $module.find(selector.prompt),
54
+ $searchButton = $module.find(selector.searchButton),
55
+ $results = $module.find(selector.results),
56
+ $result = $module.find(selector.result),
57
+ $category = $module.find(selector.category),
58
+
59
+ element = this,
60
+ instance = $module.data(moduleNamespace),
61
+
62
+ disabledBubbled = false,
63
+ resultsDismissed = false,
64
+
65
+ module
181
66
  ;
182
- if(pageLostFocus) {
183
- return;
184
- }
185
- resultsDismissed = false;
186
- if(module.resultsClicked) {
187
- module.debug('Determining if user action caused search to close');
188
- $module
189
- .one('click.close' + eventNamespace, selector.results, function(event) {
190
- if(module.is.inMessage(event) || disabledBubbled) {
191
- $prompt.focus();
192
- return;
193
- }
194
- disabledBubbled = false;
195
- if( !module.is.animating() && !module.is.hidden()) {
196
- callback();
197
- }
198
- })
199
- ;
200
- }
201
- else {
202
- module.debug('Input blurred without user action, closing results');
203
- callback();
204
- }
205
- },
206
- result: {
207
- mousedown: function() {
208
- module.resultsClicked = true;
209
- },
210
- mouseup: function() {
211
- module.resultsClicked = false;
212
- },
213
- click: function(event) {
214
- module.debug('Search result selected');
215
- var
216
- $result = $(this),
217
- $title = $result.find(selector.title).eq(0),
218
- $link = $result.is('a[href]')
219
- ? $result
220
- : $result.find('a[href]').eq(0),
221
- href = $link.attr('href') || false,
222
- target = $link.attr('target') || false,
223
- // title is used for result lookup
224
- value = ($title.length > 0)
225
- ? $title.text()
226
- : false,
227
- results = module.get.results(),
228
- result = $result.data(metadata.result) || module.get.result(value, results)
229
- ;
230
- var oldValue = module.get.value();
231
- if( $.isFunction(settings.onSelect) ) {
232
- if(settings.onSelect.call(element, result, results) === false) {
233
- module.debug('Custom onSelect callback cancelled default select action');
234
- disabledBubbled = true;
235
- return;
236
- }
237
- }
238
- module.hideResults();
239
- if(value && module.get.value() === oldValue) {
240
- module.set.value(value);
241
- }
242
- if(href) {
243
- event.preventDefault();
244
- module.verbose('Opening search link found in result', $link);
245
- if(target == '_blank' || event.ctrlKey) {
246
- window.open(href);
247
- }
248
- else {
249
- window.location.href = (href);
250
- }
251
- }
252
- }
253
- }
254
- },
255
- ensureVisible: function($el) {
256
- var elTop, elBottom, resultsScrollTop, resultsHeight;
257
- if($el.length === 0) {
258
- return;
259
- }
260
- elTop = $el.position().top;
261
- elBottom = elTop + $el.outerHeight(true);
262
-
263
- resultsScrollTop = $results.scrollTop();
264
- resultsHeight = $results.height();
265
-
266
- if (elTop < 0) {
267
- $results.scrollTop(resultsScrollTop + elTop);
268
- }
269
-
270
- else if (resultsHeight < elBottom) {
271
- $results.scrollTop(resultsScrollTop + (elBottom - resultsHeight));
272
- }
273
- },
274
- handleKeyboard: function(event) {
275
- var
276
- // force selector refresh
277
- $result = $module.find(selector.result),
278
- $category = $module.find(selector.category),
279
- $activeResult = $result.filter('.' + className.active),
280
- currentIndex = $result.index( $activeResult ),
281
- resultSize = $result.length,
282
- hasActiveResult = $activeResult.length > 0,
283
-
284
- keyCode = event.which,
285
- keys = {
286
- backspace : 8,
287
- enter : 13,
288
- escape : 27,
289
- upArrow : 38,
290
- downArrow : 40
291
- },
292
- newIndex
293
- ;
294
- // search shortcuts
295
- if(keyCode == keys.escape) {
296
- module.verbose('Escape key pressed, blurring search field');
297
- module.hideResults();
298
- resultsDismissed = true;
299
- }
300
- if( module.is.visible() ) {
301
- if(keyCode == keys.enter) {
302
- module.verbose('Enter key pressed, selecting active result');
303
- if( $result.filter('.' + className.active).length > 0 ) {
304
- module.event.result.click.call($result.filter('.' + className.active), event);
305
- event.preventDefault();
306
- return false;
307
- }
308
- }
309
- else if(keyCode == keys.upArrow && hasActiveResult) {
310
- module.verbose('Up key pressed, changing active result');
311
- newIndex = (currentIndex - 1 < 0)
312
- ? currentIndex
313
- : currentIndex - 1
314
- ;
315
- $category
316
- .removeClass(className.active)
317
- ;
318
- $result
319
- .removeClass(className.active)
320
- .eq(newIndex)
321
- .addClass(className.active)
322
- .closest($category)
323
- .addClass(className.active)
324
- ;
325
- module.ensureVisible($result.eq(newIndex));
326
- event.preventDefault();
327
- }
328
- else if(keyCode == keys.downArrow) {
329
- module.verbose('Down key pressed, changing active result');
330
- newIndex = (currentIndex + 1 >= resultSize)
331
- ? currentIndex
332
- : currentIndex + 1
333
- ;
334
- $category
335
- .removeClass(className.active)
336
- ;
337
- $result
338
- .removeClass(className.active)
339
- .eq(newIndex)
340
- .addClass(className.active)
341
- .closest($category)
342
- .addClass(className.active)
343
- ;
344
- module.ensureVisible($result.eq(newIndex));
345
- event.preventDefault();
346
- }
347
- }
348
- else {
349
- // query shortcuts
350
- if(keyCode == keys.enter) {
351
- module.verbose('Enter key pressed, executing query');
352
- module.query();
353
- module.set.buttonPressed();
354
- $prompt.one('keyup', module.remove.buttonFocus);
355
- }
356
- }
357
- },
358
67
 
359
- setup: {
360
- api: function(searchTerm, callback) {
361
- var
362
- apiSettings = {
363
- debug : settings.debug,
364
- on : false,
365
- cache : settings.cache,
366
- action : 'search',
367
- urlData : {
368
- query : searchTerm
68
+ module = {
69
+
70
+ initialize: function () {
71
+ module.verbose('Initializing module');
72
+ module.get.settings();
73
+ module.determine.searchFields();
74
+ module.bind.events();
75
+ module.set.type();
76
+ module.create.results();
77
+ module.instantiate();
369
78
  },
370
- onSuccess : function(response) {
371
- module.parse.response.call(element, response, searchTerm);
372
- callback();
79
+ instantiate: function () {
80
+ module.verbose('Storing instance of module', module);
81
+ instance = module;
82
+ $module
83
+ .data(moduleNamespace, module)
84
+ ;
373
85
  },
374
- onFailure : function() {
375
- module.displayMessage(error.serverError);
376
- callback();
86
+ destroy: function () {
87
+ module.verbose('Destroying instance');
88
+ $module
89
+ .off(eventNamespace)
90
+ .removeData(moduleNamespace)
91
+ ;
377
92
  },
378
- onAbort : function(response) {
93
+
94
+ refresh: function () {
95
+ module.debug('Refreshing selector cache');
96
+ $prompt = $module.find(selector.prompt);
97
+ $searchButton = $module.find(selector.searchButton);
98
+ $category = $module.find(selector.category);
99
+ $results = $module.find(selector.results);
100
+ $result = $module.find(selector.result);
379
101
  },
380
- onError : module.error
381
- }
382
- ;
383
- $.extend(true, apiSettings, settings.apiSettings);
384
- module.verbose('Setting up API request', apiSettings);
385
- $module.api(apiSettings);
386
- }
387
- },
388
102
 
389
- can: {
390
- useAPI: function() {
391
- return $.fn.api !== undefined;
392
- },
393
- show: function() {
394
- return module.is.focused() && !module.is.visible() && !module.is.empty();
395
- },
396
- transition: function() {
397
- return settings.transition && $.fn.transition !== undefined && $module.transition('is supported');
398
- }
399
- },
103
+ refreshResults: function () {
104
+ $results = $module.find(selector.results);
105
+ $result = $module.find(selector.result);
106
+ },
400
107
 
401
- is: {
402
- animating: function() {
403
- return $results.hasClass(className.animating);
404
- },
405
- chrome: function() {
406
- return !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
407
- },
408
- hidden: function() {
409
- return $results.hasClass(className.hidden);
410
- },
411
- inMessage: function(event) {
412
- if(!event.target) {
413
- return;
414
- }
415
- var
416
- $target = $(event.target),
417
- isInDOM = $.contains(document.documentElement, event.target)
418
- ;
419
- return (isInDOM && $target.closest(selector.message).length > 0);
420
- },
421
- empty: function() {
422
- return ($results.html() === '');
423
- },
424
- visible: function() {
425
- return ($results.filter(':visible').length > 0);
426
- },
427
- focused: function() {
428
- return ($prompt.filter(':focus').length > 0);
429
- }
430
- },
108
+ bind: {
109
+ events: function () {
110
+ module.verbose('Binding events to search');
111
+ if (settings.automatic) {
112
+ $module
113
+ .on(module.get.inputEvent() + eventNamespace, selector.prompt, module.event.input)
114
+ ;
115
+ $prompt
116
+ .attr('autocomplete', module.is.chrome() ? 'fomantic-search' : 'off')
117
+ ;
118
+ }
119
+ $module
120
+ // prompt
121
+ .on('focus' + eventNamespace, selector.prompt, module.event.focus)
122
+ .on('blur' + eventNamespace, selector.prompt, module.event.blur)
123
+ .on('keydown' + eventNamespace, selector.prompt, module.handleKeyboard)
124
+ // search button
125
+ .on('click' + eventNamespace, selector.searchButton, module.query)
126
+ // results
127
+ .on('mousedown' + eventNamespace, selector.results, module.event.result.mousedown)
128
+ .on('mouseup' + eventNamespace, selector.results, module.event.result.mouseup)
129
+ .on('click' + eventNamespace, selector.result, module.event.result.click)
130
+ ;
131
+ },
132
+ },
431
133
 
432
- get: {
433
- settings: function() {
434
- if($.isPlainObject(parameters) && parameters.searchFullText) {
435
- settings.fullTextSearch = parameters.searchFullText;
436
- module.error(settings.error.oldSearchSyntax, element);
437
- }
438
- if (settings.ignoreDiacritics && !String.prototype.normalize) {
439
- settings.ignoreDiacritics = false;
440
- module.error(error.noNormalize, element);
441
- }
442
- },
443
- inputEvent: function() {
444
- var
445
- prompt = $prompt[0],
446
- inputEvent = (prompt !== undefined && prompt.oninput !== undefined)
447
- ? 'input'
448
- : (prompt !== undefined && prompt.onpropertychange !== undefined)
449
- ? 'propertychange'
450
- : 'keyup'
451
- ;
452
- return inputEvent;
453
- },
454
- value: function() {
455
- return $prompt.val();
456
- },
457
- results: function() {
458
- var
459
- results = $module.data(metadata.results)
460
- ;
461
- return results;
462
- },
463
- result: function(value, results) {
464
- var
465
- result = false
466
- ;
467
- value = (value !== undefined)
468
- ? value
469
- : module.get.value()
470
- ;
471
- results = (results !== undefined)
472
- ? results
473
- : module.get.results()
474
- ;
475
- if(settings.type === 'category') {
476
- module.debug('Finding result that matches', value);
477
- $.each(results, function(index, category) {
478
- if(Array.isArray(category.results)) {
479
- result = module.search.object(value, category.results)[0];
480
- // don't continue searching if a result is found
481
- if(result) {
482
- return false;
483
- }
484
- }
485
- });
486
- }
487
- else {
488
- module.debug('Finding result in results object', value);
489
- result = module.search.object(value, results)[0];
490
- }
491
- return result || false;
492
- },
493
- },
134
+ determine: {
135
+ searchFields: function () {
136
+ // this makes sure $.extend does not add specified search fields to default fields
137
+ // this is the only setting which should not extend defaults
138
+ if (parameters && parameters.searchFields !== undefined) {
139
+ settings.searchFields = parameters.searchFields;
140
+ }
141
+ },
142
+ },
494
143
 
495
- select: {
496
- firstResult: function() {
497
- module.verbose('Selecting first result');
498
- $result.first().addClass(className.active);
499
- }
500
- },
144
+ event: {
145
+ input: function () {
146
+ if (settings.searchDelay) {
147
+ clearTimeout(module.timer);
148
+ module.timer = setTimeout(function () {
149
+ if (module.is.focused()) {
150
+ module.query();
151
+ }
152
+ }, settings.searchDelay);
153
+ } else {
154
+ module.query();
155
+ }
156
+ },
157
+ focus: function () {
158
+ module.set.focus();
159
+ if (settings.searchOnFocus && module.has.minimumCharacters()) {
160
+ module.query(function () {
161
+ if (module.can.show()) {
162
+ module.showResults();
163
+ }
164
+ });
165
+ }
166
+ },
167
+ blur: function (event) {
168
+ var
169
+ pageLostFocus = document.activeElement === this,
170
+ callback = function () {
171
+ module.cancel.query();
172
+ module.remove.focus();
173
+ module.timer = setTimeout(module.hideResults, settings.hideDelay);
174
+ }
175
+ ;
176
+ if (pageLostFocus) {
177
+ return;
178
+ }
179
+ resultsDismissed = false;
180
+ if (module.resultsClicked) {
181
+ module.debug('Determining if user action caused search to close');
182
+ $module
183
+ .one('click.close' + eventNamespace, selector.results, function (event) {
184
+ if (module.is.inMessage(event) || disabledBubbled) {
185
+ $prompt.trigger('focus');
186
+
187
+ return;
188
+ }
189
+ disabledBubbled = false;
190
+ if (!module.is.animating() && !module.is.hidden()) {
191
+ callback();
192
+ }
193
+ })
194
+ ;
195
+ } else {
196
+ module.debug('Input blurred without user action, closing results');
197
+ callback();
198
+ }
199
+ },
200
+ result: {
201
+ mousedown: function () {
202
+ module.resultsClicked = true;
203
+ },
204
+ mouseup: function () {
205
+ module.resultsClicked = false;
206
+ },
207
+ click: function (event) {
208
+ module.debug('Search result selected');
209
+ var
210
+ $result = $(this),
211
+ $title = $result.find(selector.title).eq(0),
212
+ $link = $result.is('a[href]')
213
+ ? $result
214
+ : $result.find('a[href]').eq(0),
215
+ href = $link.attr('href') || false,
216
+ target = $link.attr('target') || false,
217
+ // title is used for result lookup
218
+ value = $title.length > 0
219
+ ? $title.text()
220
+ : false,
221
+ results = module.get.results(),
222
+ result = $result.data(metadata.result) || module.get.result(value, results)
223
+ ;
224
+ var oldValue = module.get.value();
225
+ if (isFunction(settings.onSelect)) {
226
+ if (settings.onSelect.call(element, result, results) === false) {
227
+ module.debug('Custom onSelect callback cancelled default select action');
228
+ disabledBubbled = true;
229
+
230
+ return;
231
+ }
232
+ }
233
+ module.hideResults();
234
+ if (value && module.get.value() === oldValue) {
235
+ module.set.value(value);
236
+ }
237
+ if (href) {
238
+ event.preventDefault();
239
+ module.verbose('Opening search link found in result', $link);
240
+ if (target === '_blank' || event.ctrlKey) {
241
+ window.open(href);
242
+ } else {
243
+ window.location.href = href;
244
+ }
245
+ }
246
+ },
247
+ },
248
+ },
249
+ ensureVisible: function ($el) {
250
+ var
251
+ elTop,
252
+ elBottom,
253
+ resultsScrollTop,
254
+ resultsHeight
255
+ ;
256
+ if ($el.length === 0) {
257
+ return;
258
+ }
259
+ elTop = $el.position().top;
260
+ elBottom = elTop + $el.outerHeight(true);
501
261
 
502
- set: {
503
- focus: function() {
504
- $module.addClass(className.focus);
505
- },
506
- loading: function() {
507
- $module.addClass(className.loading);
508
- },
509
- value: function(value) {
510
- module.verbose('Setting search input value', value);
511
- $prompt
512
- .val(value)
513
- ;
514
- },
515
- type: function(type) {
516
- type = type || settings.type;
517
- if(settings.type == 'category') {
518
- $module.addClass(settings.type);
519
- }
520
- },
521
- buttonPressed: function() {
522
- $searchButton.addClass(className.pressed);
523
- }
524
- },
262
+ resultsScrollTop = $results.scrollTop();
263
+ resultsHeight = $results.height();
525
264
 
526
- remove: {
527
- loading: function() {
528
- $module.removeClass(className.loading);
529
- },
530
- focus: function() {
531
- $module.removeClass(className.focus);
532
- },
533
- buttonPressed: function() {
534
- $searchButton.removeClass(className.pressed);
535
- },
536
- diacritics: function(text) {
537
- return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036f]/g, '') : text;
538
- }
539
- },
265
+ if (elTop < 0) {
266
+ $results.scrollTop(resultsScrollTop + elTop);
267
+ } else if (resultsHeight < elBottom) {
268
+ $results.scrollTop(resultsScrollTop + (elBottom - resultsHeight));
269
+ }
270
+ },
271
+ handleKeyboard: function (event) {
272
+ var
273
+ // force selector refresh
274
+ $result = $module.find(selector.result),
275
+ $category = $module.find(selector.category),
276
+ $activeResult = $result.filter('.' + className.active),
277
+ currentIndex = $result.index($activeResult),
278
+ resultSize = $result.length,
279
+ hasActiveResult = $activeResult.length > 0,
280
+
281
+ keyCode = event.which,
282
+ keys = {
283
+ backspace: 8,
284
+ enter: 13,
285
+ escape: 27,
286
+ upArrow: 38,
287
+ downArrow: 40,
288
+ },
289
+ newIndex
290
+ ;
291
+ // search shortcuts
292
+ if (keyCode === keys.escape) {
293
+ if (!module.is.visible()) {
294
+ module.verbose('Escape key pressed, blurring search field');
295
+ $prompt.trigger('blur');
296
+ } else {
297
+ module.hideResults();
298
+ }
299
+ event.stopPropagation();
300
+ resultsDismissed = true;
301
+ }
302
+ if (module.is.visible()) {
303
+ if (keyCode === keys.enter) {
304
+ module.verbose('Enter key pressed, selecting active result');
305
+ if ($result.filter('.' + className.active).length > 0) {
306
+ module.event.result.click.call($result.filter('.' + className.active), event);
307
+ event.preventDefault();
308
+
309
+ return false;
310
+ }
311
+ } else if (keyCode === keys.upArrow && hasActiveResult) {
312
+ module.verbose('Up key pressed, changing active result');
313
+ newIndex = currentIndex - 1 < 0
314
+ ? currentIndex
315
+ : currentIndex - 1;
316
+ $category
317
+ .removeClass(className.active)
318
+ ;
319
+ $result
320
+ .removeClass(className.active)
321
+ .eq(newIndex)
322
+ .addClass(className.active)
323
+ .closest($category)
324
+ .addClass(className.active)
325
+ ;
326
+ module.ensureVisible($result.eq(newIndex));
327
+ event.preventDefault();
328
+ } else if (keyCode === keys.downArrow) {
329
+ module.verbose('Down key pressed, changing active result');
330
+ newIndex = currentIndex + 1 >= resultSize
331
+ ? currentIndex
332
+ : currentIndex + 1;
333
+ $category
334
+ .removeClass(className.active)
335
+ ;
336
+ $result
337
+ .removeClass(className.active)
338
+ .eq(newIndex)
339
+ .addClass(className.active)
340
+ .closest($category)
341
+ .addClass(className.active)
342
+ ;
343
+ module.ensureVisible($result.eq(newIndex));
344
+ event.preventDefault();
345
+ }
346
+ } else {
347
+ // query shortcuts
348
+ if (keyCode === keys.enter) {
349
+ module.verbose('Enter key pressed, executing query');
350
+ module.query();
351
+ module.set.buttonPressed();
352
+ $prompt.one('keyup', module.remove.buttonFocus);
353
+ }
354
+ }
355
+ },
540
356
 
541
- query: function(callback) {
542
- callback = $.isFunction(callback)
543
- ? callback
544
- : function(){}
545
- ;
546
- var
547
- searchTerm = module.get.value(),
548
- cache = module.read.cache(searchTerm)
549
- ;
550
- callback = callback || function() {};
551
- if( module.has.minimumCharacters() ) {
552
- if(cache) {
553
- module.debug('Reading result from cache', searchTerm);
554
- module.save.results(cache.results);
555
- module.addResults(cache.html);
556
- module.inject.id(cache.results);
557
- callback();
558
- }
559
- else {
560
- module.debug('Querying for', searchTerm);
561
- if($.isPlainObject(settings.source) || Array.isArray(settings.source)) {
562
- module.search.local(searchTerm);
563
- callback();
564
- }
565
- else if( module.can.useAPI() ) {
566
- module.search.remote(searchTerm, callback);
567
- }
568
- else {
569
- module.error(error.source);
570
- callback();
571
- }
572
- }
573
- settings.onSearchQuery.call(element, searchTerm);
574
- }
575
- else {
576
- module.hideResults();
577
- }
578
- },
357
+ setup: {
358
+ api: function (searchTerm, callback) {
359
+ var
360
+ apiSettings = {
361
+ debug: settings.debug,
362
+ on: false,
363
+ cache: settings.cache,
364
+ action: 'search',
365
+ urlData: {
366
+ query: searchTerm,
367
+ },
368
+ },
369
+ apiCallbacks = {
370
+ onSuccess: function (response, $module, xhr) {
371
+ module.parse.response.call(element, response, searchTerm);
372
+ callback();
373
+ if (settings.apiSettings && typeof settings.apiSettings.onSuccess === 'function') {
374
+ settings.apiSettings.onSuccess.call(this, response, $module, xhr);
375
+ }
376
+ },
377
+ onFailure: function (response, $module, xhr) {
378
+ module.displayMessage(error.serverError);
379
+ callback();
380
+ if (settings.apiSettings && typeof settings.apiSettings.onFailure === 'function') {
381
+ settings.apiSettings.onFailure.call(this, response, $module, xhr);
382
+ }
383
+ },
384
+ onAbort: function (status, $module, xhr) {
385
+ if (settings.apiSettings && typeof settings.apiSettings.onAbort === 'function') {
386
+ settings.apiSettings.onAbort.call(this, status, $module, xhr);
387
+ }
388
+ },
389
+ onError: function (errorMessage, $module, xhr) {
390
+ module.error();
391
+ if (settings.apiSettings && typeof settings.apiSettings.onError === 'function') {
392
+ settings.apiSettings.onError.call(this, errorMessage, $module, xhr);
393
+ }
394
+ },
395
+ }
396
+ ;
397
+ $.extend(true, apiSettings, settings.apiSettings, apiCallbacks);
398
+ module.verbose('Setting up API request', apiSettings);
399
+ $module.api(apiSettings);
400
+ },
401
+ },
579
402
 
580
- search: {
581
- local: function(searchTerm) {
582
- var
583
- results = module.search.object(searchTerm, settings.source),
584
- searchHTML
585
- ;
586
- module.set.loading();
587
- module.save.results(results);
588
- module.debug('Returned full local search results', results);
589
- if(settings.maxResults > 0) {
590
- module.debug('Using specified max results', results);
591
- results = results.slice(0, settings.maxResults);
592
- }
593
- if(settings.type == 'category') {
594
- results = module.create.categoryResults(results);
595
- }
596
- searchHTML = module.generateResults({
597
- results: results
598
- });
599
- module.remove.loading();
600
- module.addResults(searchHTML);
601
- module.inject.id(results);
602
- module.write.cache(searchTerm, {
603
- html : searchHTML,
604
- results : results
605
- });
606
- },
607
- remote: function(searchTerm, callback) {
608
- callback = $.isFunction(callback)
609
- ? callback
610
- : function(){}
611
- ;
612
- if($module.api('is loading')) {
613
- $module.api('abort');
614
- }
615
- module.setup.api(searchTerm, callback);
616
- $module
617
- .api('query')
618
- ;
619
- },
620
- object: function(searchTerm, source, searchFields) {
621
- searchTerm = module.remove.diacritics(String(searchTerm));
622
- var
623
- results = [],
624
- exactResults = [],
625
- fuzzyResults = [],
626
- searchExp = searchTerm.replace(regExp.escape, '\\$&'),
627
- matchRegExp = new RegExp(regExp.beginsWith + searchExp, 'i'),
628
-
629
- // avoid duplicates when pushing results
630
- addResult = function(array, result) {
631
- var
632
- notResult = ($.inArray(result, results) == -1),
633
- notFuzzyResult = ($.inArray(result, fuzzyResults) == -1),
634
- notExactResults = ($.inArray(result, exactResults) == -1)
635
- ;
636
- if(notResult && notFuzzyResult && notExactResults) {
637
- array.push(result);
638
- }
639
- }
640
- ;
641
- source = source || settings.source;
642
- searchFields = (searchFields !== undefined)
643
- ? searchFields
644
- : settings.searchFields
645
- ;
403
+ can: {
404
+ useAPI: function () {
405
+ return $.fn.api !== undefined;
406
+ },
407
+ show: function () {
408
+ return module.is.focused() && !module.is.visible() && !module.is.empty();
409
+ },
410
+ transition: function () {
411
+ return settings.transition && $.fn.transition !== undefined && $module.transition('is supported');
412
+ },
413
+ },
646
414
 
647
- // search fields should be array to loop correctly
648
- if(!Array.isArray(searchFields)) {
649
- searchFields = [searchFields];
650
- }
415
+ is: {
416
+ animating: function () {
417
+ return $results.hasClass(className.animating);
418
+ },
419
+ chrome: function () {
420
+ return !!window.chrome && !window.StyleMedia;
421
+ },
422
+ hidden: function () {
423
+ return $results.hasClass(className.hidden);
424
+ },
425
+ inMessage: function (event) {
426
+ if (!event.target) {
427
+ return;
428
+ }
429
+ var
430
+ $target = $(event.target),
431
+ isInDOM = $.contains(document.documentElement, event.target)
432
+ ;
433
+
434
+ return isInDOM && $target.closest(selector.message).length > 0;
435
+ },
436
+ empty: function () {
437
+ return $results.html() === '';
438
+ },
439
+ visible: function () {
440
+ return $results.filter(':visible').length > 0;
441
+ },
442
+ focused: function () {
443
+ return $prompt.filter(':focus').length > 0;
444
+ },
445
+ },
651
446
 
652
- // exit conditions if no source
653
- if(source === undefined || source === false) {
654
- module.error(error.source);
655
- return [];
656
- }
657
- // iterate through search fields looking for matches
658
- $.each(searchFields, function(index, field) {
659
- $.each(source, function(label, content) {
660
- var
661
- fieldExists = (typeof content[field] == 'string') || (typeof content[field] == 'number')
662
- ;
663
- if(fieldExists) {
664
- var text;
665
- if (typeof content[field] === 'string'){
666
- text = module.remove.diacritics(content[field]);
667
- } else {
668
- text = content[field].toString();
669
- }
670
- if( text.search(matchRegExp) !== -1) {
671
- // content starts with value (first in results)
672
- addResult(results, content);
673
- }
674
- else if(settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text) ) {
675
- // content fuzzy matches (last in results)
676
- addResult(exactResults, content);
677
- }
678
- else if(settings.fullTextSearch == true && module.fuzzySearch(searchTerm, text) ) {
679
- // content fuzzy matches (last in results)
680
- addResult(fuzzyResults, content);
681
- }
682
- }
683
- });
684
- });
685
- $.merge(exactResults, fuzzyResults);
686
- $.merge(results, exactResults);
687
- return results;
688
- }
689
- },
690
- exactSearch: function (query, term) {
691
- query = query.toLowerCase();
692
- term = term.toLowerCase();
693
- return term.indexOf(query) > -1;
694
- },
695
- fuzzySearch: function(query, term) {
696
- var
697
- termLength = term.length,
698
- queryLength = query.length
699
- ;
700
- if(typeof query !== 'string') {
701
- return false;
702
- }
703
- query = query.toLowerCase();
704
- term = term.toLowerCase();
705
- if(queryLength > termLength) {
706
- return false;
707
- }
708
- if(queryLength === termLength) {
709
- return (query === term);
710
- }
711
- search: for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
712
- var
713
- queryCharacter = query.charCodeAt(characterIndex)
714
- ;
715
- while(nextCharacterIndex < termLength) {
716
- if(term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
717
- continue search;
718
- }
719
- }
720
- return false;
721
- }
722
- return true;
723
- },
447
+ get: {
448
+ settings: function () {
449
+ if ($.isPlainObject(parameters) && parameters.searchFullText) {
450
+ settings.fullTextSearch = parameters.searchFullText;
451
+ module.error(settings.error.oldSearchSyntax, element);
452
+ }
453
+ if (settings.ignoreDiacritics && !String.prototype.normalize) {
454
+ settings.ignoreDiacritics = false;
455
+ module.error(error.noNormalize, element);
456
+ }
457
+ },
458
+ inputEvent: function () {
459
+ var
460
+ prompt = $prompt[0],
461
+ inputEvent = prompt !== undefined && prompt.oninput !== undefined
462
+ ? 'input'
463
+ : (prompt !== undefined && prompt.onpropertychange !== undefined
464
+ ? 'propertychange'
465
+ : 'keyup')
466
+ ;
467
+
468
+ return inputEvent;
469
+ },
470
+ value: function () {
471
+ return $prompt.val();
472
+ },
473
+ results: function () {
474
+ return $module.data(metadata.results);
475
+ },
476
+ result: function (value, results) {
477
+ var
478
+ result = false
479
+ ;
480
+ value = value !== undefined
481
+ ? value
482
+ : module.get.value();
483
+ results = results !== undefined
484
+ ? results
485
+ : module.get.results();
486
+ if (settings.type === 'category') {
487
+ module.debug('Finding result that matches', value);
488
+ $.each(results, function (index, category) {
489
+ if (Array.isArray(category.results)) {
490
+ result = module.search.object(value, category.results)[0];
491
+ // don't continue searching if a result is found
492
+ if (result) {
493
+ return false;
494
+ }
495
+ }
496
+ });
497
+ } else {
498
+ module.debug('Finding result in results object', value);
499
+ result = module.search.object(value, results)[0];
500
+ }
501
+
502
+ return result || false;
503
+ },
504
+ },
724
505
 
725
- parse: {
726
- response: function(response, searchTerm) {
727
- if(Array.isArray(response)){
728
- var o={};
729
- o[fields.results]=response;
730
- response = o;
731
- }
732
- var
733
- searchHTML = module.generateResults(response)
734
- ;
735
- module.verbose('Parsing server response', response);
736
- if(response !== undefined) {
737
- if(searchTerm !== undefined && response[fields.results] !== undefined) {
738
- module.addResults(searchHTML);
739
- module.inject.id(response[fields.results]);
740
- module.write.cache(searchTerm, {
741
- html : searchHTML,
742
- results : response[fields.results]
743
- });
744
- module.save.results(response[fields.results]);
745
- }
746
- }
747
- }
748
- },
506
+ select: {
507
+ firstResult: function () {
508
+ module.verbose('Selecting first result');
509
+ $result.first().addClass(className.active);
510
+ },
511
+ },
749
512
 
750
- cancel: {
751
- query: function() {
752
- if( module.can.useAPI() ) {
753
- $module.api('abort');
754
- }
755
- }
756
- },
513
+ set: {
514
+ focus: function () {
515
+ $module.addClass(className.focus);
516
+ },
517
+ loading: function () {
518
+ $module.addClass(className.loading);
519
+ },
520
+ value: function (value) {
521
+ module.verbose('Setting search input value', value);
522
+ $prompt
523
+ .val(value)
524
+ ;
525
+ },
526
+ type: function (type) {
527
+ type = type || settings.type;
528
+ if (className[type]) {
529
+ $module.addClass(className[type]);
530
+ }
531
+ },
532
+ buttonPressed: function () {
533
+ $searchButton.addClass(className.pressed);
534
+ },
535
+ },
757
536
 
758
- has: {
759
- minimumCharacters: function() {
760
- var
761
- searchTerm = module.get.value(),
762
- numCharacters = searchTerm.length
763
- ;
764
- return (numCharacters >= settings.minCharacters);
765
- },
766
- results: function() {
767
- if($results.length === 0) {
768
- return false;
769
- }
770
- var
771
- html = $results.html()
772
- ;
773
- return html != '';
774
- }
775
- },
537
+ remove: {
538
+ loading: function () {
539
+ $module.removeClass(className.loading);
540
+ },
541
+ focus: function () {
542
+ $module.removeClass(className.focus);
543
+ },
544
+ buttonPressed: function () {
545
+ $searchButton.removeClass(className.pressed);
546
+ },
547
+ diacritics: function (text) {
548
+ return settings.ignoreDiacritics ? text.normalize('NFD').replace(/[\u0300-\u036F]/g, '') : text;
549
+ },
550
+ },
776
551
 
777
- clear: {
778
- cache: function(value) {
779
- var
780
- cache = $module.data(metadata.cache)
781
- ;
782
- if(!value) {
783
- module.debug('Clearing cache', value);
784
- $module.removeData(metadata.cache);
785
- }
786
- else if(value && cache && cache[value]) {
787
- module.debug('Removing value from cache', value);
788
- delete cache[value];
789
- $module.data(metadata.cache, cache);
790
- }
791
- }
792
- },
552
+ query: function (callback) {
553
+ callback = isFunction(callback)
554
+ ? callback
555
+ : function () {};
556
+ var
557
+ searchTerm = module.get.value(),
558
+ cache = module.read.cache(searchTerm)
559
+ ;
560
+ callback = callback || function () {};
561
+ if (module.has.minimumCharacters()) {
562
+ if (cache) {
563
+ module.debug('Reading result from cache', searchTerm);
564
+ module.save.results(cache.results);
565
+ module.addResults(cache.html);
566
+ module.inject.id(cache.results);
567
+ callback();
568
+ } else {
569
+ module.debug('Querying for', searchTerm);
570
+ if ($.isPlainObject(settings.source) || Array.isArray(settings.source)) {
571
+ module.search.local(searchTerm);
572
+ callback();
573
+ } else if (module.can.useAPI()) {
574
+ module.search.remote(searchTerm, callback);
575
+ } else {
576
+ module.error(error.source);
577
+ callback();
578
+ }
579
+ }
580
+ settings.onSearchQuery.call(element, searchTerm);
581
+ } else {
582
+ module.hideResults();
583
+ }
584
+ },
793
585
 
794
- read: {
795
- cache: function(name) {
796
- var
797
- cache = $module.data(metadata.cache)
798
- ;
799
- if(settings.cache) {
800
- module.verbose('Checking cache for generated html for query', name);
801
- return (typeof cache == 'object') && (cache[name] !== undefined)
802
- ? cache[name]
803
- : false
804
- ;
805
- }
806
- return false;
807
- }
808
- },
586
+ search: {
587
+ local: function (searchTerm) {
588
+ var
589
+ results = module.search.object(searchTerm, settings.source),
590
+ searchHTML
591
+ ;
592
+ module.set.loading();
593
+ module.save.results(results);
594
+ module.debug('Returned full local search results', results);
595
+ if (settings.maxResults > 0) {
596
+ module.debug('Using specified max results', results);
597
+ results = results.slice(0, settings.maxResults);
598
+ }
599
+ if (settings.type === 'category') {
600
+ results = module.create.categoryResults(results);
601
+ }
602
+ searchHTML = module.generateResults({
603
+ results: results,
604
+ });
605
+ module.remove.loading();
606
+ module.addResults(searchHTML);
607
+ module.inject.id(results);
608
+ module.write.cache(searchTerm, {
609
+ html: searchHTML,
610
+ results: results,
611
+ });
612
+ },
613
+ remote: function (searchTerm, callback) {
614
+ callback = isFunction(callback)
615
+ ? callback
616
+ : function () {};
617
+ if ($module.api('is loading')) {
618
+ $module.api('abort');
619
+ }
620
+ module.setup.api(searchTerm, callback);
621
+ $module
622
+ .api('query')
623
+ ;
624
+ },
625
+ object: function (searchTerm, source, searchFields) {
626
+ searchTerm = module.remove.diacritics(String(searchTerm));
627
+ var
628
+ results = [],
629
+ exactResults = [],
630
+ fuzzyResults = [],
631
+ searchExp = searchTerm.replace(regExp.escape, '\\$&'),
632
+ matchRegExp = new RegExp(regExp.beginsWith + searchExp, 'i'),
633
+
634
+ // avoid duplicates when pushing results
635
+ addResult = function (array, result) {
636
+ var
637
+ notResult = $.inArray(result, results) === -1,
638
+ notFuzzyResult = $.inArray(result, fuzzyResults) === -1,
639
+ notExactResults = $.inArray(result, exactResults) === -1
640
+ ;
641
+ if (notResult && notFuzzyResult && notExactResults) {
642
+ array.push(result);
643
+ }
644
+ }
645
+ ;
646
+ source = source || settings.source;
647
+ searchFields = searchFields !== undefined
648
+ ? searchFields
649
+ : settings.searchFields;
650
+
651
+ // search fields should be array to loop correctly
652
+ if (!Array.isArray(searchFields)) {
653
+ searchFields = [searchFields];
654
+ }
655
+
656
+ // exit conditions if no source
657
+ if (source === undefined || source === false) {
658
+ module.error(error.source);
659
+
660
+ return [];
661
+ }
662
+ // iterate through search fields looking for matches
663
+ var lastSearchFieldIndex = searchFields.length - 1;
664
+ $.each(source, function (label, content) {
665
+ var concatenatedContent = [];
666
+ $.each(searchFields, function (index, field) {
667
+ var
668
+ fieldExists = (typeof content[field] === 'string') || (typeof content[field] === 'number')
669
+ ;
670
+ if (fieldExists) {
671
+ var text;
672
+ text = typeof content[field] === 'string'
673
+ ? module.remove.diacritics(content[field])
674
+ : content[field].toString();
675
+ if (settings.fullTextSearch === 'all') {
676
+ concatenatedContent.push(text);
677
+ if (index < lastSearchFieldIndex) {
678
+ return true;
679
+ }
680
+ text = concatenatedContent.join(' ');
681
+ }
682
+ if (settings.fullTextSearch !== 'all' && text.search(matchRegExp) !== -1) {
683
+ // content starts with value (first in results)
684
+ addResult(results, content);
685
+ } else if (settings.fullTextSearch === 'exact' && module.exactSearch(searchTerm, text)) {
686
+ addResult(exactResults, content);
687
+ } else if (settings.fullTextSearch === 'some' && module.wordSearch(searchTerm, text)) {
688
+ addResult(exactResults, content);
689
+ } else if (settings.fullTextSearch === 'all' && module.wordSearch(searchTerm, text, true)) {
690
+ addResult(exactResults, content);
691
+ } else if (settings.fullTextSearch === true && module.fuzzySearch(searchTerm, text)) {
692
+ // content fuzzy matches (last in results)
693
+ addResult(fuzzyResults, content);
694
+ }
695
+ }
696
+ });
697
+ });
698
+ $.merge(exactResults, fuzzyResults);
699
+ $.merge(results, exactResults);
700
+
701
+ return results;
702
+ },
703
+ },
704
+ exactSearch: function (query, term) {
705
+ query = query.toLowerCase();
706
+ term = term.toLowerCase();
809
707
 
810
- create: {
811
- categoryResults: function(results) {
812
- var
813
- categoryResults = {}
814
- ;
815
- $.each(results, function(index, result) {
816
- if(!result.category) {
817
- return;
818
- }
819
- if(categoryResults[result.category] === undefined) {
820
- module.verbose('Creating new category of results', result.category);
821
- categoryResults[result.category] = {
822
- name : result.category,
823
- results : [result]
824
- };
825
- }
826
- else {
827
- categoryResults[result.category].results.push(result);
828
- }
829
- });
830
- return categoryResults;
831
- },
832
- id: function(resultIndex, categoryIndex) {
833
- var
834
- resultID = (resultIndex + 1), // not zero indexed
835
- letterID,
836
- id
837
- ;
838
- if(categoryIndex !== undefined) {
839
- // start char code for "A"
840
- letterID = String.fromCharCode(97 + categoryIndex);
841
- id = letterID + resultID;
842
- module.verbose('Creating category result id', id);
843
- }
844
- else {
845
- id = resultID;
846
- module.verbose('Creating result id', id);
847
- }
848
- return id;
849
- },
850
- results: function() {
851
- if($results.length === 0) {
852
- $results = $('<div />')
853
- .addClass(className.results)
854
- .appendTo($module)
855
- ;
856
- }
857
- }
858
- },
708
+ return term.indexOf(query) > -1;
709
+ },
710
+ wordSearch: function (query, term, matchAll) {
711
+ var allWords = query.split(/\s+/),
712
+ w,
713
+ wL = allWords.length,
714
+ found = false
715
+ ;
716
+ for (w = 0; w < wL; w++) {
717
+ found = module.exactSearch(allWords[w], term);
718
+ if ((!found && matchAll) || (found && !matchAll)) {
719
+ break;
720
+ }
721
+ }
859
722
 
860
- inject: {
861
- result: function(result, resultIndex, categoryIndex) {
862
- module.verbose('Injecting result into results');
863
- var
864
- $selectedResult = (categoryIndex !== undefined)
865
- ? $results
866
- .children().eq(categoryIndex)
867
- .children(selector.results)
868
- .first()
869
- .children(selector.result)
870
- .eq(resultIndex)
871
- : $results
872
- .children(selector.result).eq(resultIndex)
873
- ;
874
- module.verbose('Injecting results metadata', $selectedResult);
875
- $selectedResult
876
- .data(metadata.result, result)
877
- ;
878
- },
879
- id: function(results) {
880
- module.debug('Injecting unique ids into results');
881
- var
882
- // since results may be object, we must use counters
883
- categoryIndex = 0,
884
- resultIndex = 0
885
- ;
886
- if(settings.type === 'category') {
887
- // iterate through each category result
888
- $.each(results, function(index, category) {
889
- if(category.results.length > 0){
890
- resultIndex = 0;
891
- $.each(category.results, function(index, result) {
892
- if(result.id === undefined) {
893
- result.id = module.create.id(resultIndex, categoryIndex);
723
+ return found;
724
+ },
725
+ fuzzySearch: function (query, term) {
726
+ var
727
+ termLength = term.length,
728
+ queryLength = query.length
729
+ ;
730
+ if (typeof query !== 'string') {
731
+ return false;
732
+ }
733
+ query = query.toLowerCase();
734
+ term = term.toLowerCase();
735
+ if (queryLength > termLength) {
736
+ return false;
737
+ }
738
+ if (queryLength === termLength) {
739
+ return query === term;
894
740
  }
895
- module.inject.result(result, resultIndex, categoryIndex);
896
- resultIndex++;
897
- });
898
- categoryIndex++;
741
+ for (var characterIndex = 0, nextCharacterIndex = 0; characterIndex < queryLength; characterIndex++) {
742
+ var
743
+ continueSearch = false,
744
+ queryCharacter = query.charCodeAt(characterIndex)
745
+ ;
746
+ while (nextCharacterIndex < termLength) {
747
+ if (term.charCodeAt(nextCharacterIndex++) === queryCharacter) {
748
+ continueSearch = true;
749
+
750
+ break;
751
+ }
752
+ }
753
+
754
+ if (!continueSearch) {
755
+ return false;
756
+ }
757
+ }
758
+
759
+ return true;
760
+ },
761
+
762
+ parse: {
763
+ response: function (response, searchTerm) {
764
+ if (Array.isArray(response)) {
765
+ var o = {};
766
+ o[fields.results] = response;
767
+ response = o;
768
+ }
769
+ var
770
+ searchHTML = module.generateResults(response)
771
+ ;
772
+ module.verbose('Parsing server response', response);
773
+ if (response !== undefined) {
774
+ if (searchTerm !== undefined && response[fields.results] !== undefined) {
775
+ module.addResults(searchHTML);
776
+ module.inject.id(response[fields.results]);
777
+ module.write.cache(searchTerm, {
778
+ html: searchHTML,
779
+ results: response[fields.results],
780
+ });
781
+ module.save.results(response[fields.results]);
782
+ }
783
+ }
784
+ },
785
+ },
786
+
787
+ cancel: {
788
+ query: function () {
789
+ if (module.can.useAPI()) {
790
+ $module.api('abort');
791
+ }
792
+ },
793
+ },
794
+
795
+ has: {
796
+ minimumCharacters: function () {
797
+ var
798
+ searchTerm = module.get.value(),
799
+ numCharacters = searchTerm.length
800
+ ;
801
+
802
+ return numCharacters >= settings.minCharacters;
803
+ },
804
+ results: function () {
805
+ if ($results.length === 0) {
806
+ return false;
807
+ }
808
+ var
809
+ html = $results.html()
810
+ ;
811
+
812
+ return html !== '';
813
+ },
814
+ },
815
+
816
+ clear: {
817
+ cache: function (value) {
818
+ var
819
+ cache = $module.data(metadata.cache)
820
+ ;
821
+ if (!value) {
822
+ module.debug('Clearing cache', value);
823
+ $module.removeData(metadata.cache);
824
+ } else if (value && cache && cache[value]) {
825
+ module.debug('Removing value from cache', value);
826
+ delete cache[value];
827
+ $module.data(metadata.cache, cache);
828
+ }
829
+ },
830
+ },
831
+
832
+ read: {
833
+ cache: function (name) {
834
+ var
835
+ cache = $module.data(metadata.cache)
836
+ ;
837
+ if (settings.cache) {
838
+ module.verbose('Checking cache for generated html for query', name);
839
+
840
+ return (typeof cache === 'object') && (cache[name] !== undefined)
841
+ ? cache[name]
842
+ : false;
843
+ }
844
+
845
+ return false;
846
+ },
847
+ },
848
+
849
+ create: {
850
+ categoryResults: function (results) {
851
+ var
852
+ categoryResults = {}
853
+ ;
854
+ $.each(results, function (index, result) {
855
+ if (!result.category) {
856
+ return;
857
+ }
858
+ if (categoryResults[result.category] === undefined) {
859
+ module.verbose('Creating new category of results', result.category);
860
+ categoryResults[result.category] = {
861
+ name: result.category,
862
+ results: [result],
863
+ };
864
+ } else {
865
+ categoryResults[result.category].results.push(result);
866
+ }
867
+ });
868
+
869
+ return categoryResults;
870
+ },
871
+ id: function (resultIndex, categoryIndex) {
872
+ var
873
+ resultID = resultIndex + 1, // not zero indexed
874
+ letterID,
875
+ id
876
+ ;
877
+ if (categoryIndex !== undefined) {
878
+ // start char code for "A"
879
+ letterID = String.fromCharCode(97 + categoryIndex);
880
+ id = letterID + resultID;
881
+ module.verbose('Creating category result id', id);
882
+ } else {
883
+ id = resultID;
884
+ module.verbose('Creating result id', id);
885
+ }
886
+
887
+ return id;
888
+ },
889
+ results: function () {
890
+ if ($results.length === 0) {
891
+ $results = $('<div />')
892
+ .addClass(className.results)
893
+ .appendTo($module)
894
+ ;
895
+ }
896
+ },
897
+ },
898
+
899
+ inject: {
900
+ result: function (result, resultIndex, categoryIndex) {
901
+ module.verbose('Injecting result into results');
902
+ var
903
+ $selectedResult = categoryIndex !== undefined
904
+ ? $results
905
+ .children().eq(categoryIndex)
906
+ .children(selector.results)
907
+ .first()
908
+ .children(selector.result)
909
+ .eq(resultIndex)
910
+ : $results
911
+ .children(selector.result).eq(resultIndex)
912
+ ;
913
+ module.verbose('Injecting results metadata', $selectedResult);
914
+ $selectedResult
915
+ .data(metadata.result, result)
916
+ ;
917
+ },
918
+ id: function (results) {
919
+ module.debug('Injecting unique ids into results');
920
+ var
921
+ // since results may be object, we must use counters
922
+ categoryIndex = 0,
923
+ resultIndex = 0
924
+ ;
925
+ if (settings.type === 'category') {
926
+ // iterate through each category result
927
+ $.each(results, function (index, category) {
928
+ if (category.results.length > 0) {
929
+ resultIndex = 0;
930
+ $.each(category.results, function (index, result) {
931
+ if (result.id === undefined) {
932
+ result.id = module.create.id(resultIndex, categoryIndex);
933
+ }
934
+ module.inject.result(result, resultIndex, categoryIndex);
935
+ resultIndex++;
936
+ });
937
+ categoryIndex++;
938
+ }
939
+ });
940
+ } else {
941
+ // top level
942
+ $.each(results, function (index, result) {
943
+ if (result.id === undefined) {
944
+ result.id = module.create.id(resultIndex);
945
+ }
946
+ module.inject.result(result, resultIndex);
947
+ resultIndex++;
948
+ });
949
+ }
950
+
951
+ return results;
952
+ },
953
+ },
954
+
955
+ save: {
956
+ results: function (results) {
957
+ module.verbose('Saving current search results to metadata', results);
958
+ $module.data(metadata.results, results);
959
+ },
960
+ },
961
+
962
+ write: {
963
+ cache: function (name, value) {
964
+ var
965
+ cache = $module.data(metadata.cache) !== undefined
966
+ ? $module.data(metadata.cache)
967
+ : {}
968
+ ;
969
+ if (settings.cache) {
970
+ module.verbose('Writing generated html to cache', name, value);
971
+ cache[name] = value;
972
+ $module
973
+ .data(metadata.cache, cache)
974
+ ;
975
+ }
976
+ },
977
+ },
978
+
979
+ addResults: function (html) {
980
+ if (isFunction(settings.onResultsAdd)) {
981
+ if (settings.onResultsAdd.call($results, html) === false) {
982
+ module.debug('onResultsAdd callback cancelled default action');
983
+
984
+ return false;
985
+ }
986
+ }
987
+ if (html) {
988
+ $results
989
+ .html(html)
990
+ ;
991
+ module.refreshResults();
992
+ if (settings.selectFirstResult) {
993
+ module.select.firstResult();
994
+ }
995
+ module.showResults();
996
+ } else {
997
+ module.hideResults(function () {
998
+ $results.empty();
999
+ });
1000
+ }
1001
+ },
1002
+
1003
+ showResults: function (callback) {
1004
+ callback = isFunction(callback)
1005
+ ? callback
1006
+ : function () {};
1007
+ if (resultsDismissed) {
1008
+ return;
1009
+ }
1010
+ if (!module.is.visible() && module.has.results()) {
1011
+ if (module.can.transition()) {
1012
+ module.debug('Showing results with css animations');
1013
+ $results
1014
+ .transition({
1015
+ animation: settings.transition + ' in',
1016
+ debug: settings.debug,
1017
+ verbose: settings.verbose,
1018
+ silent: settings.silent,
1019
+ duration: settings.duration,
1020
+ onShow: function () {
1021
+ var $firstResult = $module.find(selector.result).eq(0);
1022
+ module.ensureVisible($firstResult);
1023
+ },
1024
+ onComplete: function () {
1025
+ callback();
1026
+ },
1027
+ queue: true,
1028
+ })
1029
+ ;
1030
+ } else {
1031
+ module.debug('Showing results with javascript');
1032
+ $results
1033
+ .stop()
1034
+ .fadeIn(settings.duration, settings.easing)
1035
+ ;
1036
+ }
1037
+ settings.onResultsOpen.call($results);
1038
+ }
1039
+ },
1040
+ hideResults: function (callback) {
1041
+ callback = isFunction(callback)
1042
+ ? callback
1043
+ : function () {};
1044
+ if (module.is.visible()) {
1045
+ if (module.can.transition()) {
1046
+ module.debug('Hiding results with css animations');
1047
+ $results
1048
+ .transition({
1049
+ animation: settings.transition + ' out',
1050
+ debug: settings.debug,
1051
+ verbose: settings.verbose,
1052
+ silent: settings.silent,
1053
+ duration: settings.duration,
1054
+ onComplete: function () {
1055
+ callback();
1056
+ },
1057
+ queue: true,
1058
+ })
1059
+ ;
1060
+ } else {
1061
+ module.debug('Hiding results with javascript');
1062
+ $results
1063
+ .stop()
1064
+ .fadeOut(settings.duration, settings.easing)
1065
+ ;
1066
+ }
1067
+ settings.onResultsClose.call($results);
1068
+ }
1069
+ },
1070
+
1071
+ generateResults: function (response) {
1072
+ module.debug('Generating html from response', response);
1073
+ var
1074
+ template = settings.templates[settings.type],
1075
+ isProperObject = $.isPlainObject(response[fields.results]) && !$.isEmptyObject(response[fields.results]),
1076
+ isProperArray = Array.isArray(response[fields.results]) && response[fields.results].length > 0,
1077
+ html = ''
1078
+ ;
1079
+ if (isProperObject || isProperArray) {
1080
+ if (settings.maxResults > 0) {
1081
+ if (isProperObject) {
1082
+ if (settings.type === 'standard') {
1083
+ module.error(error.maxResults);
1084
+ }
1085
+ } else {
1086
+ response[fields.results] = response[fields.results].slice(0, settings.maxResults);
1087
+ }
1088
+ }
1089
+ if (isFunction(template)) {
1090
+ html = template(response, fields, settings.preserveHTML);
1091
+ } else {
1092
+ module.error(error.noTemplate, false);
1093
+ }
1094
+ } else if (settings.showNoResults) {
1095
+ html = module.displayMessage(error.noResults, 'empty', error.noResultsHeader);
1096
+ }
1097
+ settings.onResults.call(element, response);
1098
+
1099
+ return html;
1100
+ },
1101
+
1102
+ displayMessage: function (text, type, header) {
1103
+ type = type || 'standard';
1104
+ module.debug('Displaying message', text, type, header);
1105
+ module.addResults(settings.templates.message(text, type, header));
1106
+
1107
+ return settings.templates.message(text, type, header);
1108
+ },
1109
+
1110
+ setting: function (name, value) {
1111
+ if ($.isPlainObject(name)) {
1112
+ $.extend(true, settings, name);
1113
+ } else if (value !== undefined) {
1114
+ settings[name] = value;
1115
+ } else {
1116
+ return settings[name];
1117
+ }
1118
+ },
1119
+ internal: function (name, value) {
1120
+ if ($.isPlainObject(name)) {
1121
+ $.extend(true, module, name);
1122
+ } else if (value !== undefined) {
1123
+ module[name] = value;
1124
+ } else {
1125
+ return module[name];
1126
+ }
1127
+ },
1128
+ debug: function () {
1129
+ if (!settings.silent && settings.debug) {
1130
+ if (settings.performance) {
1131
+ module.performance.log(arguments);
1132
+ } else {
1133
+ module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1134
+ module.debug.apply(console, arguments);
1135
+ }
1136
+ }
1137
+ },
1138
+ verbose: function () {
1139
+ if (!settings.silent && settings.verbose && settings.debug) {
1140
+ if (settings.performance) {
1141
+ module.performance.log(arguments);
1142
+ } else {
1143
+ module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1144
+ module.verbose.apply(console, arguments);
1145
+ }
1146
+ }
1147
+ },
1148
+ error: function () {
1149
+ if (!settings.silent) {
1150
+ module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1151
+ module.error.apply(console, arguments);
1152
+ }
1153
+ },
1154
+ performance: {
1155
+ log: function (message) {
1156
+ var
1157
+ currentTime,
1158
+ executionTime,
1159
+ previousTime
1160
+ ;
1161
+ if (settings.performance) {
1162
+ currentTime = Date.now();
1163
+ previousTime = time || currentTime;
1164
+ executionTime = currentTime - previousTime;
1165
+ time = currentTime;
1166
+ performance.push({
1167
+ Name: message[0],
1168
+ Arguments: [].slice.call(message, 1) || '',
1169
+ Element: element,
1170
+ 'Execution Time': executionTime,
1171
+ });
1172
+ }
1173
+ clearTimeout(module.performance.timer);
1174
+ module.performance.timer = setTimeout(module.performance.display, 500);
1175
+ },
1176
+ display: function () {
1177
+ var
1178
+ title = settings.name + ':',
1179
+ totalTime = 0
1180
+ ;
1181
+ time = false;
1182
+ clearTimeout(module.performance.timer);
1183
+ $.each(performance, function (index, data) {
1184
+ totalTime += data['Execution Time'];
1185
+ });
1186
+ title += ' ' + totalTime + 'ms';
1187
+ if (moduleSelector) {
1188
+ title += ' \'' + moduleSelector + '\'';
1189
+ }
1190
+ if ($allModules.length > 1) {
1191
+ title += ' (' + $allModules.length + ')';
1192
+ }
1193
+ if (performance.length > 0) {
1194
+ console.groupCollapsed(title);
1195
+ if (console.table) {
1196
+ console.table(performance);
1197
+ } else {
1198
+ $.each(performance, function (index, data) {
1199
+ console.log(data.Name + ': ' + data['Execution Time'] + 'ms');
1200
+ });
1201
+ }
1202
+ console.groupEnd();
1203
+ }
1204
+ performance = [];
1205
+ },
1206
+ },
1207
+ invoke: function (query, passedArguments, context) {
1208
+ var
1209
+ object = instance,
1210
+ maxDepth,
1211
+ found,
1212
+ response
1213
+ ;
1214
+ passedArguments = passedArguments || queryArguments;
1215
+ context = context || element;
1216
+ if (typeof query === 'string' && object !== undefined) {
1217
+ query = query.split(/[ .]/);
1218
+ maxDepth = query.length - 1;
1219
+ $.each(query, function (depth, value) {
1220
+ var camelCaseValue = depth !== maxDepth
1221
+ ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1222
+ : query
1223
+ ;
1224
+ if ($.isPlainObject(object[camelCaseValue]) && (depth !== maxDepth)) {
1225
+ object = object[camelCaseValue];
1226
+ } else if (object[camelCaseValue] !== undefined) {
1227
+ found = object[camelCaseValue];
1228
+
1229
+ return false;
1230
+ } else if ($.isPlainObject(object[value]) && (depth !== maxDepth)) {
1231
+ object = object[value];
1232
+ } else if (object[value] !== undefined) {
1233
+ found = object[value];
1234
+
1235
+ return false;
1236
+ } else {
1237
+ module.error(error.method, query);
1238
+
1239
+ return false;
1240
+ }
1241
+ });
1242
+ }
1243
+ if (isFunction(found)) {
1244
+ response = found.apply(context, passedArguments);
1245
+ } else if (found !== undefined) {
1246
+ response = found;
1247
+ }
1248
+ if (Array.isArray(returnedValue)) {
1249
+ returnedValue.push(response);
1250
+ } else if (returnedValue !== undefined) {
1251
+ returnedValue = [returnedValue, response];
1252
+ } else if (response !== undefined) {
1253
+ returnedValue = response;
1254
+ }
1255
+
1256
+ return found;
1257
+ },
1258
+ };
1259
+ if (methodInvoked) {
1260
+ if (instance === undefined) {
1261
+ module.initialize();
899
1262
  }
900
- });
901
- }
902
- else {
903
- // top level
904
- $.each(results, function(index, result) {
905
- if(result.id === undefined) {
906
- result.id = module.create.id(resultIndex);
1263
+ module.invoke(query);
1264
+ } else {
1265
+ if (instance !== undefined) {
1266
+ instance.invoke('destroy');
907
1267
  }
908
- module.inject.result(result, resultIndex);
909
- resultIndex++;
910
- });
1268
+ module.initialize();
911
1269
  }
912
- return results;
913
- }
1270
+ });
1271
+
1272
+ return returnedValue !== undefined
1273
+ ? returnedValue
1274
+ : this;
1275
+ };
1276
+
1277
+ $.fn.search.settings = {
1278
+
1279
+ name: 'Search',
1280
+ namespace: 'search',
1281
+
1282
+ silent: false,
1283
+ debug: false,
1284
+ verbose: false,
1285
+ performance: true,
1286
+
1287
+ // template to use (specified in settings.templates)
1288
+ type: 'standard',
1289
+
1290
+ // minimum characters required to search
1291
+ minCharacters: 1,
1292
+
1293
+ // whether to select first result after searching automatically
1294
+ selectFirstResult: false,
1295
+
1296
+ // API config
1297
+ apiSettings: false,
1298
+
1299
+ // object to search
1300
+ source: false,
1301
+
1302
+ // Whether search should query current term on focus
1303
+ searchOnFocus: true,
1304
+
1305
+ // fields to search
1306
+ searchFields: [
1307
+ 'id',
1308
+ 'title',
1309
+ 'description',
1310
+ ],
1311
+
1312
+ // field to display in standard results template
1313
+ displayField: '',
1314
+
1315
+ // search anywhere in value (set to 'exact' to require exact matches
1316
+ fullTextSearch: 'exact',
1317
+
1318
+ // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
1319
+ ignoreDiacritics: false,
1320
+
1321
+ // whether to add events to prompt automatically
1322
+ automatic: true,
1323
+
1324
+ // delay before hiding menu after blur
1325
+ hideDelay: 0,
1326
+
1327
+ // delay before searching
1328
+ searchDelay: 200,
1329
+
1330
+ // maximum results returned from search
1331
+ maxResults: 7,
1332
+
1333
+ // whether to store lookups in local cache
1334
+ cache: true,
1335
+
1336
+ // whether no results errors should be shown
1337
+ showNoResults: true,
1338
+
1339
+ // preserve possible html of resultset values
1340
+ preserveHTML: true,
1341
+
1342
+ // transition settings
1343
+ transition: 'scale',
1344
+ duration: 200,
1345
+ easing: 'easeOutExpo',
1346
+
1347
+ // callbacks
1348
+ onSelect: false,
1349
+ onResultsAdd: false,
1350
+
1351
+ onSearchQuery: function (query) {},
1352
+ onResults: function (response) {},
1353
+
1354
+ onResultsOpen: function () {},
1355
+ onResultsClose: function () {},
1356
+
1357
+ className: {
1358
+ animating: 'animating',
1359
+ active: 'active',
1360
+ category: 'category',
1361
+ empty: 'empty',
1362
+ focus: 'focus',
1363
+ hidden: 'hidden',
1364
+ loading: 'loading',
1365
+ results: 'results',
1366
+ pressed: 'down',
914
1367
  },
915
1368
 
916
- save: {
917
- results: function(results) {
918
- module.verbose('Saving current search results to metadata', results);
919
- $module.data(metadata.results, results);
920
- }
1369
+ error: {
1370
+ source: 'Cannot search. No source used, and Fomantic API module was not included',
1371
+ noResultsHeader: 'No Results',
1372
+ noResults: 'Your search returned no results',
1373
+ noTemplate: 'A valid template name was not specified.',
1374
+ oldSearchSyntax: 'searchFullText setting has been renamed fullTextSearch for consistency, please adjust your settings.',
1375
+ serverError: 'There was an issue querying the server.',
1376
+ maxResults: 'Results must be an array to use maxResults setting',
1377
+ method: 'The method you called is not defined.',
1378
+ noNormalize: '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.',
921
1379
  },
922
1380
 
923
- write: {
924
- cache: function(name, value) {
925
- var
926
- cache = ($module.data(metadata.cache) !== undefined)
927
- ? $module.data(metadata.cache)
928
- : {}
929
- ;
930
- if(settings.cache) {
931
- module.verbose('Writing generated html to cache', name, value);
932
- cache[name] = value;
933
- $module
934
- .data(metadata.cache, cache)
935
- ;
936
- }
937
- }
1381
+ metadata: {
1382
+ cache: 'cache',
1383
+ results: 'results',
1384
+ result: 'result',
938
1385
  },
939
1386
 
940
- addResults: function(html) {
941
- if( $.isFunction(settings.onResultsAdd) ) {
942
- if( settings.onResultsAdd.call($results, html) === false ) {
943
- module.debug('onResultsAdd callback cancelled default action');
944
- return false;
945
- }
946
- }
947
- if(html) {
948
- $results
949
- .html(html)
950
- ;
951
- module.refreshResults();
952
- if(settings.selectFirstResult) {
953
- module.select.firstResult();
954
- }
955
- module.showResults();
956
- }
957
- else {
958
- module.hideResults(function() {
959
- $results.empty();
960
- });
961
- }
1387
+ regExp: {
1388
+ escape: /[$()*+./?[\\\]^{|}-]/g,
1389
+ beginsWith: '(?:\\s|^)',
962
1390
  },
963
1391
 
964
- showResults: function(callback) {
965
- callback = $.isFunction(callback)
966
- ? callback
967
- : function(){}
968
- ;
969
- if(resultsDismissed) {
970
- return;
971
- }
972
- if(!module.is.visible() && module.has.results()) {
973
- if( module.can.transition() ) {
974
- module.debug('Showing results with css animations');
975
- $results
976
- .transition({
977
- animation : settings.transition + ' in',
978
- debug : settings.debug,
979
- verbose : settings.verbose,
980
- duration : settings.duration,
981
- onShow : function() {
982
- var $firstResult = $module.find(selector.result).eq(0);
983
- module.ensureVisible($firstResult);
984
- },
985
- onComplete : function() {
986
- callback();
987
- },
988
- queue : true
989
- })
990
- ;
991
- }
992
- else {
993
- module.debug('Showing results with javascript');
994
- $results
995
- .stop()
996
- .fadeIn(settings.duration, settings.easing)
997
- ;
998
- }
999
- settings.onResultsOpen.call($results);
1000
- }
1392
+ // maps api response attributes to internal representation
1393
+ fields: {
1394
+ categories: 'results', // array of categories (category view)
1395
+ categoryName: 'name', // name of category (category view)
1396
+ categoryResults: 'results', // array of results (category view)
1397
+ description: 'description', // result description
1398
+ image: 'image', // result image
1399
+ price: 'price', // result price
1400
+ results: 'results', // array of results (standard)
1401
+ title: 'title', // result title
1402
+ url: 'url', // result url
1403
+ action: 'action', // "view more" object name
1404
+ actionText: 'text', // "view more" text
1405
+ actionURL: 'url', // "view more" url
1001
1406
  },
1002
- hideResults: function(callback) {
1003
- callback = $.isFunction(callback)
1004
- ? callback
1005
- : function(){}
1006
- ;
1007
- if( module.is.visible() ) {
1008
- if( module.can.transition() ) {
1009
- module.debug('Hiding results with css animations');
1010
- $results
1011
- .transition({
1012
- animation : settings.transition + ' out',
1013
- debug : settings.debug,
1014
- verbose : settings.verbose,
1015
- duration : settings.duration,
1016
- onComplete : function() {
1017
- callback();
1018
- },
1019
- queue : true
1020
- })
1021
- ;
1022
- }
1023
- else {
1024
- module.debug('Hiding results with javascript');
1025
- $results
1026
- .stop()
1027
- .fadeOut(settings.duration, settings.easing)
1028
- ;
1029
- }
1030
- settings.onResultsClose.call($results);
1031
- }
1407
+
1408
+ selector: {
1409
+ prompt: '.prompt',
1410
+ searchButton: '.search.button',
1411
+ results: '.results',
1412
+ message: '.results > .message',
1413
+ category: '.category',
1414
+ result: '.result',
1415
+ title: '.title, .name',
1032
1416
  },
1033
1417
 
1034
- generateResults: function(response) {
1035
- module.debug('Generating html from response', response);
1036
- var
1037
- template = settings.templates[settings.type],
1038
- isProperObject = ($.isPlainObject(response[fields.results]) && !$.isEmptyObject(response[fields.results])),
1039
- isProperArray = (Array.isArray(response[fields.results]) && response[fields.results].length > 0),
1040
- html = ''
1041
- ;
1042
- if(isProperObject || isProperArray ) {
1043
- if(settings.maxResults > 0) {
1044
- if(isProperObject) {
1045
- if(settings.type == 'standard') {
1046
- module.error(error.maxResults);
1418
+ templates: {
1419
+ escape: function (string, preserveHTML) {
1420
+ if (preserveHTML) {
1421
+ return string;
1422
+ }
1423
+ var
1424
+ badChars = /["'<>`]/g,
1425
+ shouldEscape = /["&'<>`]/,
1426
+ escape = {
1427
+ '<': '&lt;',
1428
+ '>': '&gt;',
1429
+ '"': '&quot;',
1430
+ "'": '&#x27;',
1431
+ '`': '&#x60;',
1432
+ },
1433
+ escapedChar = function (chr) {
1434
+ return escape[chr];
1435
+ };
1436
+ if (shouldEscape.test(string)) {
1437
+ string = string.replace(/&(?![\d#a-z]{1,12};)/gi, '&amp;');
1438
+
1439
+ return string.replace(badChars, escapedChar);
1047
1440
  }
1048
- }
1049
- else {
1050
- response[fields.results] = response[fields.results].slice(0, settings.maxResults);
1051
- }
1052
- }
1053
- if($.isFunction(template)) {
1054
- html = template(response, fields, settings.preserveHTML);
1055
- }
1056
- else {
1057
- module.error(error.noTemplate, false);
1058
- }
1059
- }
1060
- else if(settings.showNoResults) {
1061
- html = module.displayMessage(error.noResults, 'empty', error.noResultsHeader);
1062
- }
1063
- settings.onResults.call(element, response);
1064
- return html;
1065
- },
1066
1441
 
1067
- displayMessage: function(text, type, header) {
1068
- type = type || 'standard';
1069
- module.debug('Displaying message', text, type, header);
1070
- module.addResults( settings.templates.message(text, type, header) );
1071
- return settings.templates.message(text, type, header);
1072
- },
1442
+ return string;
1443
+ },
1444
+ message: function (message, type, header) {
1445
+ var
1446
+ html = ''
1447
+ ;
1448
+ if (message !== undefined && type !== undefined) {
1449
+ html += ''
1450
+ + '<div class="message ' + type + '">';
1451
+ if (header) {
1452
+ html += ''
1453
+ + '<div class="header">' + header + '</div>';
1454
+ }
1455
+ html += ' <div class="description">' + message + '</div>';
1456
+ html += '</div>';
1457
+ }
1458
+
1459
+ return html;
1460
+ },
1461
+ category: function (response, fields, preserveHTML) {
1462
+ var
1463
+ html = '',
1464
+ escape = $.fn.search.settings.templates.escape
1465
+ ;
1466
+ if (response[fields.categoryResults] !== undefined) {
1467
+ // each category
1468
+ $.each(response[fields.categoryResults], function (index, category) {
1469
+ if (category[fields.results] !== undefined && category.results.length > 0) {
1470
+ html += '<div class="category">';
1471
+
1472
+ if (category[fields.categoryName] !== undefined) {
1473
+ html += '<div class="name">' + escape(category[fields.categoryName], preserveHTML) + '</div>';
1474
+ }
1475
+
1476
+ // each item inside category
1477
+ html += '<div class="results">';
1478
+ $.each(category.results, function (index, result) {
1479
+ html += result[fields.url]
1480
+ ? '<a class="result" href="' + result[fields.url].replace(/"/g, '') + '">'
1481
+ : '<a class="result">';
1482
+ if (result[fields.image] !== undefined) {
1483
+ html += ''
1484
+ + '<div class="image">'
1485
+ + ' <img src="' + result[fields.image].replace(/"/g, '') + '">'
1486
+ + '</div>';
1487
+ }
1488
+ html += '<div class="content">';
1489
+ if (result[fields.price] !== undefined) {
1490
+ html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
1491
+ }
1492
+ if (result[fields.title] !== undefined) {
1493
+ html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
1494
+ }
1495
+ if (result[fields.description] !== undefined) {
1496
+ html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
1497
+ }
1498
+ html += ''
1499
+ + '</div>';
1500
+ html += '</a>';
1501
+ });
1502
+ html += '</div>';
1503
+ html += ''
1504
+ + '</div>';
1505
+ }
1506
+ });
1507
+ if (response[fields.action]) {
1508
+ html += fields.actionURL === false
1509
+ ? ''
1510
+ + '<div class="action">'
1511
+ + escape(response[fields.action][fields.actionText], preserveHTML)
1512
+ + '</div>'
1513
+ : ''
1514
+ + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g, '') + '" class="action">'
1515
+ + escape(response[fields.action][fields.actionText], preserveHTML)
1516
+ + '</a>';
1517
+ }
1518
+
1519
+ return html;
1520
+ }
1073
1521
 
1074
- setting: function(name, value) {
1075
- if( $.isPlainObject(name) ) {
1076
- $.extend(true, settings, name);
1077
- }
1078
- else if(value !== undefined) {
1079
- settings[name] = value;
1080
- }
1081
- else {
1082
- return settings[name];
1083
- }
1084
- },
1085
- internal: function(name, value) {
1086
- if( $.isPlainObject(name) ) {
1087
- $.extend(true, module, name);
1088
- }
1089
- else if(value !== undefined) {
1090
- module[name] = value;
1091
- }
1092
- else {
1093
- return module[name];
1094
- }
1095
- },
1096
- debug: function() {
1097
- if(!settings.silent && settings.debug) {
1098
- if(settings.performance) {
1099
- module.performance.log(arguments);
1100
- }
1101
- else {
1102
- module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':');
1103
- module.debug.apply(console, arguments);
1104
- }
1105
- }
1106
- },
1107
- verbose: function() {
1108
- if(!settings.silent && settings.verbose && settings.debug) {
1109
- if(settings.performance) {
1110
- module.performance.log(arguments);
1111
- }
1112
- else {
1113
- module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':');
1114
- module.verbose.apply(console, arguments);
1115
- }
1116
- }
1117
- },
1118
- error: function() {
1119
- if(!settings.silent) {
1120
- module.error = Function.prototype.bind.call(console.error, console, settings.name + ':');
1121
- module.error.apply(console, arguments);
1122
- }
1123
- },
1124
- performance: {
1125
- log: function(message) {
1126
- var
1127
- currentTime,
1128
- executionTime,
1129
- previousTime
1130
- ;
1131
- if(settings.performance) {
1132
- currentTime = new Date().getTime();
1133
- previousTime = time || currentTime;
1134
- executionTime = currentTime - previousTime;
1135
- time = currentTime;
1136
- performance.push({
1137
- 'Name' : message[0],
1138
- 'Arguments' : [].slice.call(message, 1) || '',
1139
- 'Element' : element,
1140
- 'Execution Time' : executionTime
1141
- });
1142
- }
1143
- clearTimeout(module.performance.timer);
1144
- module.performance.timer = setTimeout(module.performance.display, 500);
1145
- },
1146
- display: function() {
1147
- var
1148
- title = settings.name + ':',
1149
- totalTime = 0
1150
- ;
1151
- time = false;
1152
- clearTimeout(module.performance.timer);
1153
- $.each(performance, function(index, data) {
1154
- totalTime += data['Execution Time'];
1155
- });
1156
- title += ' ' + totalTime + 'ms';
1157
- if(moduleSelector) {
1158
- title += ' \'' + moduleSelector + '\'';
1159
- }
1160
- if($allModules.length > 1) {
1161
- title += ' ' + '(' + $allModules.length + ')';
1162
- }
1163
- if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) {
1164
- console.groupCollapsed(title);
1165
- if(console.table) {
1166
- console.table(performance);
1167
- }
1168
- else {
1169
- $.each(performance, function(index, data) {
1170
- console.log(data['Name'] + ': ' + data['Execution Time']+'ms');
1171
- });
1172
- }
1173
- console.groupEnd();
1174
- }
1175
- performance = [];
1176
- }
1177
- },
1178
- invoke: function(query, passedArguments, context) {
1179
- var
1180
- object = instance,
1181
- maxDepth,
1182
- found,
1183
- response
1184
- ;
1185
- passedArguments = passedArguments || queryArguments;
1186
- context = element || context;
1187
- if(typeof query == 'string' && object !== undefined) {
1188
- query = query.split(/[\. ]/);
1189
- maxDepth = query.length - 1;
1190
- $.each(query, function(depth, value) {
1191
- var camelCaseValue = (depth != maxDepth)
1192
- ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1)
1193
- : query
1194
- ;
1195
- if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) {
1196
- object = object[camelCaseValue];
1197
- }
1198
- else if( object[camelCaseValue] !== undefined ) {
1199
- found = object[camelCaseValue];
1200
- return false;
1201
- }
1202
- else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) {
1203
- object = object[value];
1204
- }
1205
- else if( object[value] !== undefined ) {
1206
- found = object[value];
1207
1522
  return false;
1208
- }
1209
- else {
1523
+ },
1524
+ standard: function (response, fields, preserveHTML) {
1525
+ var
1526
+ html = '',
1527
+ escape = $.fn.search.settings.templates.escape
1528
+ ;
1529
+ if (response[fields.results] !== undefined) {
1530
+ // each result
1531
+ $.each(response[fields.results], function (index, result) {
1532
+ html += result[fields.url]
1533
+ ? '<a class="result" href="' + result[fields.url].replace(/"/g, '') + '">'
1534
+ : '<a class="result">';
1535
+ if (result[fields.image] !== undefined) {
1536
+ html += ''
1537
+ + '<div class="image">'
1538
+ + ' <img src="' + result[fields.image].replace(/"/g, '') + '">'
1539
+ + '</div>';
1540
+ }
1541
+ html += '<div class="content">';
1542
+ if (result[fields.price] !== undefined) {
1543
+ html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
1544
+ }
1545
+ if (result[fields.title] !== undefined) {
1546
+ html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
1547
+ }
1548
+ if (result[fields.description] !== undefined) {
1549
+ html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
1550
+ }
1551
+ html += ''
1552
+ + '</div>';
1553
+ html += '</a>';
1554
+ });
1555
+ if (response[fields.action]) {
1556
+ html += fields.actionURL === false
1557
+ ? ''
1558
+ + '<div class="action">'
1559
+ + escape(response[fields.action][fields.actionText], preserveHTML)
1560
+ + '</div>'
1561
+ : ''
1562
+ + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g, '') + '" class="action">'
1563
+ + escape(response[fields.action][fields.actionText], preserveHTML)
1564
+ + '</a>';
1565
+ }
1566
+
1567
+ return html;
1568
+ }
1569
+
1210
1570
  return false;
1211
- }
1212
- });
1213
- }
1214
- if( $.isFunction( found ) ) {
1215
- response = found.apply(context, passedArguments);
1216
- }
1217
- else if(found !== undefined) {
1218
- response = found;
1219
- }
1220
- if(Array.isArray(returnedValue)) {
1221
- returnedValue.push(response);
1222
- }
1223
- else if(returnedValue !== undefined) {
1224
- returnedValue = [returnedValue, response];
1225
- }
1226
- else if(response !== undefined) {
1227
- returnedValue = response;
1228
- }
1229
- return found;
1230
- }
1231
- };
1232
- if(methodInvoked) {
1233
- if(instance === undefined) {
1234
- module.initialize();
1235
- }
1236
- module.invoke(query);
1237
- }
1238
- else {
1239
- if(instance !== undefined) {
1240
- instance.invoke('destroy');
1241
- }
1242
- module.initialize();
1243
- }
1244
-
1245
- })
1246
- ;
1247
-
1248
- return (returnedValue !== undefined)
1249
- ? returnedValue
1250
- : this
1251
- ;
1252
- };
1253
-
1254
- $.fn.search.settings = {
1255
-
1256
- name : 'Search',
1257
- namespace : 'search',
1258
-
1259
- silent : false,
1260
- debug : false,
1261
- verbose : false,
1262
- performance : true,
1263
-
1264
- // template to use (specified in settings.templates)
1265
- type : 'standard',
1266
-
1267
- // minimum characters required to search
1268
- minCharacters : 1,
1269
-
1270
- // whether to select first result after searching automatically
1271
- selectFirstResult : false,
1272
-
1273
- // API config
1274
- apiSettings : false,
1275
-
1276
- // object to search
1277
- source : false,
1278
-
1279
- // Whether search should query current term on focus
1280
- searchOnFocus : true,
1281
-
1282
- // fields to search
1283
- searchFields : [
1284
- 'id',
1285
- 'title',
1286
- 'description'
1287
- ],
1288
-
1289
- // field to display in standard results template
1290
- displayField : '',
1291
-
1292
- // search anywhere in value (set to 'exact' to require exact matches
1293
- fullTextSearch : 'exact',
1294
-
1295
- // match results also if they contain diacritics of the same base character (for example searching for "a" will also match "á" or "â" or "à", etc...)
1296
- ignoreDiacritics : false,
1297
-
1298
- // whether to add events to prompt automatically
1299
- automatic : true,
1300
-
1301
- // delay before hiding menu after blur
1302
- hideDelay : 0,
1303
-
1304
- // delay before searching
1305
- searchDelay : 200,
1306
-
1307
- // maximum results returned from search
1308
- maxResults : 7,
1309
-
1310
- // whether to store lookups in local cache
1311
- cache : true,
1312
-
1313
- // whether no results errors should be shown
1314
- showNoResults : true,
1315
-
1316
- // preserve possible html of resultset values
1317
- preserveHTML : true,
1318
-
1319
- // transition settings
1320
- transition : 'scale',
1321
- duration : 200,
1322
- easing : 'easeOutExpo',
1323
-
1324
- // callbacks
1325
- onSelect : false,
1326
- onResultsAdd : false,
1327
-
1328
- onSearchQuery : function(query){},
1329
- onResults : function(response){},
1330
-
1331
- onResultsOpen : function(){},
1332
- onResultsClose : function(){},
1333
-
1334
- className: {
1335
- animating : 'animating',
1336
- active : 'active',
1337
- empty : 'empty',
1338
- focus : 'focus',
1339
- hidden : 'hidden',
1340
- loading : 'loading',
1341
- results : 'results',
1342
- pressed : 'down'
1343
- },
1344
-
1345
- error : {
1346
- source : 'Cannot search. No source used, and Semantic API module was not included',
1347
- noResultsHeader : 'No Results',
1348
- noResults : 'Your search returned no results',
1349
- logging : 'Error in debug logging, exiting.',
1350
- noEndpoint : 'No search endpoint was specified',
1351
- noTemplate : 'A valid template name was not specified.',
1352
- oldSearchSyntax : 'searchFullText setting has been renamed fullTextSearch for consistency, please adjust your settings.',
1353
- serverError : 'There was an issue querying the server.',
1354
- maxResults : 'Results must be an array to use maxResults setting',
1355
- method : 'The method you called is not defined.',
1356
- noNormalize : '"ignoreDiacritics" setting will be ignored. Browser does not support String().normalize(). You may consider including <https://cdn.jsdelivr.net/npm/unorm@1.4.1/lib/unorm.min.js> as a polyfill.'
1357
- },
1358
-
1359
- metadata: {
1360
- cache : 'cache',
1361
- results : 'results',
1362
- result : 'result'
1363
- },
1364
-
1365
- regExp: {
1366
- escape : /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
1367
- beginsWith : '(?:\s|^)'
1368
- },
1369
-
1370
- // maps api response attributes to internal representation
1371
- fields: {
1372
- categories : 'results', // array of categories (category view)
1373
- categoryName : 'name', // name of category (category view)
1374
- categoryResults : 'results', // array of results (category view)
1375
- description : 'description', // result description
1376
- image : 'image', // result image
1377
- price : 'price', // result price
1378
- results : 'results', // array of results (standard)
1379
- title : 'title', // result title
1380
- url : 'url', // result url
1381
- action : 'action', // "view more" object name
1382
- actionText : 'text', // "view more" text
1383
- actionURL : 'url' // "view more" url
1384
- },
1385
-
1386
- selector : {
1387
- prompt : '.prompt',
1388
- searchButton : '.search.button',
1389
- results : '.results',
1390
- message : '.results > .message',
1391
- category : '.category',
1392
- result : '.result',
1393
- title : '.title, .name'
1394
- },
1395
-
1396
- templates: {
1397
- escape: function(string, preserveHTML) {
1398
- if (preserveHTML){
1399
- return string;
1400
- }
1401
- var
1402
- badChars = /[<>"'`]/g,
1403
- shouldEscape = /[&<>"'`]/,
1404
- escape = {
1405
- "<": "&lt;",
1406
- ">": "&gt;",
1407
- '"': "&quot;",
1408
- "'": "&#x27;",
1409
- "`": "&#x60;"
1571
+ },
1410
1572
  },
1411
- escapedChar = function(chr) {
1412
- return escape[chr];
1413
- }
1414
- ;
1415
- if(shouldEscape.test(string)) {
1416
- string = string.replace(/&(?![a-z0-9#]{1,6};)/, "&amp;");
1417
- return string.replace(badChars, escapedChar);
1418
- }
1419
- return string;
1420
- },
1421
- message: function(message, type, header) {
1422
- var
1423
- html = ''
1424
- ;
1425
- if(message !== undefined && type !== undefined) {
1426
- html += ''
1427
- + '<div class="message ' + type + '">'
1428
- ;
1429
- if(header) {
1430
- html += ''
1431
- + '<div class="header">' + header + '</div>'
1432
- ;
1433
- }
1434
- html += ' <div class="description">' + message + '</div>';
1435
- html += '</div>';
1436
- }
1437
- return html;
1438
- },
1439
- category: function(response, fields, preserveHTML) {
1440
- var
1441
- html = '',
1442
- escape = $.fn.search.settings.templates.escape
1443
- ;
1444
- if(response[fields.categoryResults] !== undefined) {
1445
-
1446
- // each category
1447
- $.each(response[fields.categoryResults], function(index, category) {
1448
- if(category[fields.results] !== undefined && category.results.length > 0) {
1449
-
1450
- html += '<div class="category">';
1451
-
1452
- if(category[fields.categoryName] !== undefined) {
1453
- html += '<div class="name">' + escape(category[fields.categoryName], preserveHTML) + '</div>';
1454
- }
1573
+ };
1455
1574
 
1456
- // each item inside category
1457
- html += '<div class="results">';
1458
- $.each(category.results, function(index, result) {
1459
- if(result[fields.url]) {
1460
- html += '<a class="result" href="' + result[fields.url].replace(/"/g,"") + '">';
1461
- }
1462
- else {
1463
- html += '<a class="result">';
1464
- }
1465
- if(result[fields.image] !== undefined) {
1466
- html += ''
1467
- + '<div class="image">'
1468
- + ' <img src="' + result[fields.image].replace(/"/g,"") + '">'
1469
- + '</div>'
1470
- ;
1471
- }
1472
- html += '<div class="content">';
1473
- if(result[fields.price] !== undefined) {
1474
- html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
1475
- }
1476
- if(result[fields.title] !== undefined) {
1477
- html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
1478
- }
1479
- if(result[fields.description] !== undefined) {
1480
- html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
1481
- }
1482
- html += ''
1483
- + '</div>'
1484
- ;
1485
- html += '</a>';
1486
- });
1487
- html += '</div>';
1488
- html += ''
1489
- + '</div>'
1490
- ;
1491
- }
1492
- });
1493
- if(response[fields.action]) {
1494
- if(fields.actionURL === false) {
1495
- html += ''
1496
- + '<div class="action">'
1497
- + escape(response[fields.action][fields.actionText], preserveHTML)
1498
- + '</div>';
1499
- } else {
1500
- html += ''
1501
- + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g,"") + '" class="action">'
1502
- + escape(response[fields.action][fields.actionText], preserveHTML)
1503
- + '</a>';
1504
- }
1505
- }
1506
- return html;
1507
- }
1508
- return false;
1509
- },
1510
- standard: function(response, fields, preserveHTML) {
1511
- var
1512
- html = '',
1513
- escape = $.fn.search.settings.templates.escape
1514
- ;
1515
- if(response[fields.results] !== undefined) {
1516
-
1517
- // each result
1518
- $.each(response[fields.results], function(index, result) {
1519
- if(result[fields.url]) {
1520
- html += '<a class="result" href="' + result[fields.url].replace(/"/g,"") + '">';
1521
- }
1522
- else {
1523
- html += '<a class="result">';
1524
- }
1525
- if(result[fields.image] !== undefined) {
1526
- html += ''
1527
- + '<div class="image">'
1528
- + ' <img src="' + result[fields.image].replace(/"/g,"") + '">'
1529
- + '</div>'
1530
- ;
1531
- }
1532
- html += '<div class="content">';
1533
- if(result[fields.price] !== undefined) {
1534
- html += '<div class="price">' + escape(result[fields.price], preserveHTML) + '</div>';
1535
- }
1536
- if(result[fields.title] !== undefined) {
1537
- html += '<div class="title">' + escape(result[fields.title], preserveHTML) + '</div>';
1538
- }
1539
- if(result[fields.description] !== undefined) {
1540
- html += '<div class="description">' + escape(result[fields.description], preserveHTML) + '</div>';
1541
- }
1542
- html += ''
1543
- + '</div>'
1544
- ;
1545
- html += '</a>';
1546
- });
1547
- if(response[fields.action]) {
1548
- if(fields.actionURL === false) {
1549
- html += ''
1550
- + '<div class="action">'
1551
- + escape(response[fields.action][fields.actionText], preserveHTML)
1552
- + '</div>';
1553
- } else {
1554
- html += ''
1555
- + '<a href="' + response[fields.action][fields.actionURL].replace(/"/g,"") + '" class="action">'
1556
- + escape(response[fields.action][fields.actionText], preserveHTML)
1557
- + '</a>';
1558
- }
1559
- }
1560
- return html;
1561
- }
1562
- return false;
1563
- }
1564
- }
1565
- };
1566
-
1567
- })( jQuery, window, document );
1575
+ $.extend($.easing, {
1576
+ easeOutExpo: function (x) {
1577
+ return x === 1 ? 1 : 1 - Math.pow(2, -10 * x);
1578
+ },
1579
+ });
1580
+ })(jQuery, window, document);