|
1 |
| -// jQuery plugin for an instant searching |
| 1 | +/* |
| 2 | + * This file is part of the Symfony package. |
| 3 | + * |
| 4 | + * (c) Fabien Potencier <[email protected]> |
| 5 | + * |
| 6 | + * For the full copyright and license information, please view the LICENSE |
| 7 | + * file that was distributed with this source code. |
| 8 | + */ |
| 9 | + |
| 10 | +/** |
| 11 | + * jQuery plugin for an instant searching. |
| 12 | + * |
| 13 | + * @author Oleg Voronkovich <[email protected]> |
| 14 | + */ |
2 | 15 | (function($) {
|
3 | 16 | $.fn.instantSearch = function(config) {
|
4 | 17 | return this.each(function() {
|
|
7 | 20 | };
|
8 | 21 |
|
9 | 22 | var defaultConfig = {
|
| 23 | + allowedTags: '', |
10 | 24 | minQueryLength: 2,
|
11 | 25 | maxPreviewItems: 10,
|
12 | 26 | previewDelay: 500,
|
13 | 27 | noItemsFoundMessage: 'No items found'
|
14 | 28 | };
|
15 | 29 |
|
16 |
| - var throttle = (function(){ |
17 |
| - var timer = 0; |
18 |
| - return function(callback, ms){ |
19 |
| - clearTimeout (timer); |
20 |
| - timer = setTimeout(callback, ms); |
| 30 | + function debounce(fn, delay) { |
| 31 | + var timer = null; |
| 32 | + return function () { |
| 33 | + var context = this, args = arguments; |
| 34 | + clearTimeout(timer); |
| 35 | + timer = setTimeout(function () { |
| 36 | + fn.apply(context, args); |
| 37 | + }, delay); |
21 | 38 | };
|
22 |
| - })(); |
| 39 | + } |
| 40 | + |
| 41 | + function isValidUrl(url) { |
| 42 | + var parser = document.createElement('a'); |
| 43 | + try { |
| 44 | + parser.href = url; |
| 45 | + return !!parser.hostname; |
| 46 | + } catch (e) { |
| 47 | + return false; |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + // See http://phpjs.org/functions/strip_tags/ |
| 52 | + function stripTags(input, allowed) { |
| 53 | + allowed = (((allowed || '') + '').toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); |
| 54 | + |
| 55 | + var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi; |
| 56 | + var commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi; |
| 57 | + |
| 58 | + return input.replace(commentsAndPhpTags, '').replace(tags, function($0, $1) { |
| 59 | + return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''; |
| 60 | + }); |
| 61 | + } |
23 | 62 |
|
24 | 63 | var initInstantSearch = function(el, config) {
|
25 | 64 | var $input = $(el);
|
26 |
| - var $form = $input.parents('form').first(); |
| 65 | + var $form = $input.closest('form'); |
27 | 66 | var $preview = $('<ul class="search-preview list-group"></ul>').appendTo($form);
|
28 | 67 |
|
| 68 | + config.noItemsFoundMessage = stripTags(config.noItemsFoundMessage); |
| 69 | + |
29 | 70 | var setPreviewItems = function(items) {
|
30 | 71 | $preview.empty();
|
31 | 72 |
|
|
34 | 75 | return;
|
35 | 76 | }
|
36 | 77 |
|
37 |
| - addItemToPreview(item) |
| 78 | + addItemToPreview(item); |
38 | 79 | });
|
39 | 80 | }
|
40 | 81 |
|
|
54 | 95 | }
|
55 | 96 |
|
56 | 97 | $.getJSON($form.attr('action') + '?' + $form.serialize(), function(items) {
|
57 |
| - if (items.length === 0) { |
| 98 | + // Sanitize items |
| 99 | + var sanitizedItems = []; |
| 100 | + $.each(items, function(index, item) { |
| 101 | + // Url can contains a 'javascript:' code |
| 102 | + if (isValidUrl(item.url)) { |
| 103 | + sanitizedItems.push({ |
| 104 | + url: item.url, |
| 105 | + result: stripTags(item.result, config.allowedTags) |
| 106 | + }); |
| 107 | + } |
| 108 | + }); |
| 109 | + |
| 110 | + if (sanitizedItems.length === 0) { |
58 | 111 | noItemsFound();
|
59 | 112 | return;
|
60 | 113 | }
|
61 | 114 |
|
62 |
| - setPreviewItems(items); |
| 115 | + setPreviewItems(sanitizedItems); |
63 | 116 | });
|
64 | 117 | }
|
65 | 118 |
|
| 119 | + var debouncedUpdatePreview = debounce(updatePreview, config.previewDelay); |
| 120 | + |
66 | 121 | $input.focusout(function(e) {
|
67 | 122 | $preview.fadeOut();
|
68 | 123 | });
|
|
73 | 128 | });
|
74 | 129 |
|
75 | 130 | $input.keyup(function(e) {
|
76 |
| - throttle(updatePreview, config.previewDelay); |
| 131 | + debouncedUpdatePreview(); |
77 | 132 | });
|
78 | 133 | }
|
79 | 134 | })(window.jQuery);
|
0 commit comments