Skip to content

Commit 2fbc7f7

Browse files
committed
feature #632 Fix jQuery instantSearch plugin and search result (yceruto)
This PR was squashed before being merged into the master branch (closes #632). Discussion ---------- Fix jQuery instantSearch plugin and search result ![search](https://user-images.githubusercontent.com/2028198/29907671-c766eaa8-8dea-11e7-97fb-78ff51a7a33e.png) **instantSearch** * Refactored to some known JavaScript pattern (implemented Prototype Design Pattern) * Allow override options through input attributes `data-*` and added support to text translation ("No results found") * Add article template prototype and render method (improved visibility) * Sent configured limit of items to search controller (this allows to configure more than 10 items as results from plugin) * Simplify properties and methods (improved visibility) **Search result** * Removed old effect of hide/show results on focus out/in of the input * Show publishedDate and author for each article found * Sync style with blog index page and some margin adjustments **Minor unrelated changes** * Fix @return type-hints for `PostRepository::findBySearchQuery()` method (better autocomplete) * Show logout link as last link always Commits ------- ea96338 Fix jQuery instantSearch plugin and search result
2 parents 1123e9b + ea96338 commit 2fbc7f7

File tree

17 files changed

+147
-586
lines changed

17 files changed

+147
-586
lines changed

assets/js/jquery.instantSearch.js

Lines changed: 75 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,92 +2,105 @@
22
* jQuery plugin for an instant searching.
33
*
44
* @author Oleg Voronkovich <[email protected]>
5+
* @author Yonel Ceruto <[email protected]>
56
*/
6-
(function($) {
7-
$.fn.instantSearch = function(config) {
8-
return this.each(function() {
9-
initInstantSearch(this, $.extend(true, defaultConfig, config || {}));
10-
});
7+
(function ($) {
8+
'use strict';
9+
10+
String.prototype.render = function (parameters) {
11+
return this.replace(/({{ (\w+) }})/g, function (match, pattern, name) {
12+
return parameters[name];
13+
})
1114
};
1215

13-
var defaultConfig = {
16+
// INSTANTS SEARCH PUBLIC CLASS DEFINITION
17+
// =======================================
18+
19+
var InstantSearch = function (element, options) {
20+
this.$input = $(element);
21+
this.$form = this.$input.closest('form');
22+
this.$preview = $('<ul class="search-preview list-group">').appendTo(this.$form);
23+
this.options = $.extend({}, InstantSearch.DEFAULTS, this.$input.data(), options);
24+
25+
this.$input.keyup(this.debounce());
26+
};
27+
28+
InstantSearch.DEFAULTS = {
1429
minQueryLength: 2,
15-
maxPreviewItems: 10,
16-
previewDelay: 500,
17-
noItemsFoundMessage: 'No results found.'
30+
limit: 10,
31+
delay: 500,
32+
noResultsMessage: 'No results found',
33+
itemTemplate: '\
34+
<article class="post">\
35+
<h2><a href="{{ url }}">{{ title }}</a></h2>\
36+
<p class="post-metadata">\
37+
<span class="metadata"><i class="fa fa-calendar"></i> {{ date }}</span>\
38+
<span class="metadata"><i class="fa fa-user"></i> {{ author }}</span>\
39+
</p>\
40+
<p>{{ summary }}</p>\
41+
</article>'
1842
};
1943

20-
function debounce(fn, delay) {
44+
InstantSearch.prototype.debounce = function () {
45+
var delay = this.options.delay;
46+
var search = this.search;
2147
var timer = null;
48+
var self = this;
49+
2250
return function () {
23-
var context = this, args = arguments;
2451
clearTimeout(timer);
2552
timer = setTimeout(function () {
26-
fn.apply(context, args);
53+
search.apply(self);
2754
}, delay);
2855
};
29-
}
30-
31-
var initInstantSearch = function(el, config) {
32-
var $input = $(el);
33-
var $form = $input.closest('form');
34-
var $preview = $('<ul class="search-preview list-group">').appendTo($form);
35-
36-
var setPreviewItems = function(items) {
37-
$preview.empty();
38-
39-
$.each(items, function(index, item) {
40-
if (index > config.maxPreviewItems) {
41-
return;
42-
}
56+
};
4357

44-
addItemToPreview(item);
45-
});
58+
InstantSearch.prototype.search = function () {
59+
var query = $.trim(this.$input.val()).replace(/\s{2,}/g, ' ');
60+
if (query.length < this.options.minQueryLength) {
61+
this.$preview.empty();
62+
return;
4663
}
4764

48-
var addItemToPreview = function(item) {
49-
var $link = $('<a>').attr('href', item.url).text(item.title);
50-
var $title = $('<h3>').attr('class', 'm-b-0').append($link);
51-
var $summary = $('<p>').text(item.summary);
52-
var $result = $('<div>').append($title).append($summary);
65+
var self = this;
66+
var data = this.$form.serializeArray();
67+
data['l'] = this.limit;
5368

54-
$preview.append($result);
55-
}
69+
$.getJSON(this.$form.attr('action'), data, function (items) {
70+
self.show(items);
71+
});
72+
};
5673

57-
var noItemsFound = function() {
58-
var $result = $('<div>').text(config.noItemsFoundMessage);
74+
InstantSearch.prototype.show = function (items) {
75+
var $preview = this.$preview;
76+
var itemTemplate = this.options.itemTemplate;
5977

78+
if (0 === items.length) {
79+
$preview.html(this.options.noResultsMessage);
80+
} else {
6081
$preview.empty();
61-
$preview.append($result);
82+
$.each(items, function (index, item) {
83+
$preview.append(itemTemplate.render(item));
84+
});
6285
}
86+
};
6387

64-
var updatePreview = function() {
65-
var query = $.trim($input.val()).replace(/\s{2,}/g, ' ');
88+
// INSTANTS SEARCH PLUGIN DEFINITION
89+
// =================================
6690

67-
if (query.length < config.minQueryLength) {
68-
$preview.empty();
69-
return;
70-
}
91+
function Plugin(option) {
92+
return this.each(function () {
93+
var $this = $(this);
94+
var instance = $this.data('instantSearch');
95+
var options = typeof option === 'object' && option;
7196

72-
$.getJSON($form.attr('action') + '?' + $form.serialize(), function(items) {
73-
if (items.length === 0) {
74-
noItemsFound();
75-
return;
76-
}
97+
if (!instance) $this.data('instantSearch', (instance = new InstantSearch(this, options)));
7798

78-
setPreviewItems(items);
79-
});
80-
}
81-
82-
$input.focusout(function(e) {
83-
$preview.fadeOut();
84-
});
99+
if (option === 'search') instance.search();
100+
})
101+
}
85102

86-
$input.focusin(function(e) {
87-
$preview.fadeIn();
88-
updatePreview();
89-
});
103+
$.fn.instantSearch = Plugin;
104+
$.fn.instantSearch.Constructor = InstantSearch;
90105

91-
$input.keyup(debounce(updatePreview, config.previewDelay));
92-
}
93106
})(window.jQuery);

assets/js/search.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ import './jquery.instantSearch.js';
22

33
$(function() {
44
$('.search-field').instantSearch({
5-
previewDelay: 100,
5+
delay: 100,
66
});
77
});

assets/scss/app.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,23 @@ body#comment_form_error h1.text-danger {
308308
width: 98%;
309309
}
310310
}
311+
312+
/* Page: 'Blog search'
313+
------------------------------------------------------------------------- */
314+
body#blog_search #main h1,
315+
body#blog_search #main p {
316+
margin-bottom: 0.5em
317+
}
318+
319+
body#blog_search article.post:first-child {
320+
margin-top: 2em;
321+
}
322+
323+
body#blog_search article.post {
324+
margin-bottom: 2em;
325+
}
326+
327+
body#blog_search .post-metadata {
328+
font-size: 16px;
329+
margin-bottom: 8px;
330+
}

public/build/css/app.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/js/admin.js

Lines changed: 13 additions & 469 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/js/app.js

Lines changed: 1 addition & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/js/common.js

Lines changed: 2 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/js/login.js

Lines changed: 1 addition & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/js/search.js

Lines changed: 1 addition & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/manifest.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)