@pageboard/html 0.14.19 → 0.14.20

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