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