@northdata/fomantic-ui 2.8.722 → 2.9.400

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