fomantic-ui 2.9.1-beta.16 → 2.9.1-beta.18

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