diff --git a/public/src/app.js b/public/src/app.js
index d6f34dc2d3..3374f1b68c 100644
--- a/public/src/app.js
+++ b/public/src/app.js
@@ -75,10 +75,6 @@ app.cacheBuster = null;
app.load = function () {
handleStatusChange();
- if (config.searchEnabled) {
- app.handleSearch();
- }
-
$('body').on('click', '#new_topic', function (e) {
e.preventDefault();
app.newTopic();
@@ -103,17 +99,19 @@ app.cacheBuster = null;
'forum/pagination',
'translator',
'messages',
+ 'search',
'forum/unread',
'forum/header/notifications',
'forum/header/chat',
'timeago/jquery.timeago',
- ], function (taskbar, helpers, pagination, translator, messages, unread, notifications, chat) {
+ ], function (taskbar, helpers, pagination, translator, messages, search, unread, notifications, chat) {
notifications.prepareDOM();
chat.prepareDOM();
translator.prepareDOM();
taskbar.init();
helpers.register();
pagination.init();
+ search.init();
if (app.user.uid > 0) {
unread.initUnreadTopics();
@@ -404,218 +402,24 @@ app.cacheBuster = null;
}
app.enableTopicSearch = function (options) {
- if (!config.searchEnabled || !app.user.privileges['search:content']) {
- return;
- }
- /* eslint-disable-next-line */
- const searchOptions = Object.assign({ in: config.searchDefaultInQuick || 'titles' }, options.searchOptions);
- const quickSearchResults = options.searchElements.resultEl;
- const inputEl = options.searchElements.inputEl;
- let oldValue = inputEl.val();
- const filterCategoryEl = quickSearchResults.find('.filter-category');
-
- function updateCategoryFilterName() {
- if (ajaxify.data.template.category) {
- require(['translator'], function (translator) {
- translator.translate('[[search:search-in-category, ' + ajaxify.data.name + ']]', function (translated) {
- const name = $('
').html(translated).text();
- filterCategoryEl.find('.name').text(name);
- });
- });
- }
- filterCategoryEl.toggleClass('hidden', !ajaxify.data.template.category);
- }
-
- function doSearch() {
- require(['search'], function (search) {
- /* eslint-disable-next-line */
- options.searchOptions = Object.assign({}, searchOptions);
- options.searchOptions.term = inputEl.val();
- updateCategoryFilterName();
-
- if (ajaxify.data.template.category) {
- if (filterCategoryEl.find('input[type="checkbox"]').is(':checked')) {
- options.searchOptions.categories = [ajaxify.data.cid];
- options.searchOptions.searchChildren = true;
- }
- }
-
- quickSearchResults.removeClass('hidden').find('.quick-search-results-container').html('');
- quickSearchResults.find('.loading-indicator').removeClass('hidden');
- hooks.fire('action:search.quick.start', options);
- options.searchOptions.searchOnly = 1;
- search.api(options.searchOptions, function (data) {
- quickSearchResults.find('.loading-indicator').addClass('hidden');
- if (options.hideOnNoMatches && !data.posts.length) {
- return quickSearchResults.addClass('hidden').find('.quick-search-results-container').html('');
- }
- data.posts.forEach(function (p) {
- const text = $('' + p.content + '
').text();
- const query = inputEl.val().toLowerCase().replace(/^in:topic-\d+/, '');
- const start = Math.max(0, text.toLowerCase().indexOf(query) - 40);
- p.snippet = utils.escapeHTML((start > 0 ? '...' : '') +
- text.slice(start, start + 80) +
- (text.length - start > 80 ? '...' : ''));
- });
- app.parseAndTranslate('partials/quick-search-results', data, function (html) {
- if (html.length) {
- html.find('.timeago').timeago();
- }
- quickSearchResults.toggleClass('hidden', !html.length || !inputEl.is(':focus'))
- .find('.quick-search-results-container')
- .html(html.length ? html : '');
- const highlightEls = quickSearchResults.find(
- '.quick-search-results .quick-search-title, .quick-search-results .snippet'
- );
- search.highlightMatches(options.searchOptions.term, highlightEls);
- hooks.fire('action:search.quick.complete', {
- data: data,
- options: options,
- });
- });
- });
- });
- }
-
- quickSearchResults.find('.filter-category input[type="checkbox"]').on('change', function () {
- inputEl.focus();
- doSearch();
- });
-
- inputEl.off('keyup').on('keyup', utils.debounce(function () {
- if (inputEl.val().length < 3) {
- quickSearchResults.addClass('hidden');
- oldValue = inputEl.val();
- return;
- }
- if (inputEl.val() === oldValue) {
- return;
- }
- oldValue = inputEl.val();
- if (!inputEl.is(':focus')) {
- return quickSearchResults.addClass('hidden');
- }
- doSearch();
- }, 500));
-
- let mousedownOnResults = false;
- quickSearchResults.on('mousedown', function () {
- $(window).one('mouseup', function () {
- quickSearchResults.addClass('hidden');
- });
- mousedownOnResults = true;
- });
- inputEl.on('blur', function () {
- if (!inputEl.is(':focus') && !mousedownOnResults && !quickSearchResults.hasClass('hidden')) {
- quickSearchResults.addClass('hidden');
- }
- });
-
- let ajaxified = false;
- require(['hooks'], function (hooks) {
- hooks.on('action:ajaxify.end', function () {
- if (!ajaxify.isCold()) {
- ajaxified = true;
- }
- });
- });
-
- inputEl.on('focus', function () {
- mousedownOnResults = false;
- const query = inputEl.val();
- oldValue = query;
- if (query && quickSearchResults.find('#quick-search-results').children().length) {
- updateCategoryFilterName();
- if (ajaxified) {
- doSearch();
- ajaxified = false;
- } else {
- quickSearchResults.removeClass('hidden');
- }
- inputEl[0].setSelectionRange(
- query.startsWith('in:topic') ? query.indexOf(' ') + 1 : 0,
- query.length
- );
- }
- });
-
- inputEl.off('refresh').on('refresh', function () {
- doSearch();
+ console.warn('[deprecated] app.enableTopicSearch is deprecated, please use search.enableQuickSearch(options)');
+ require(['search'], function (search) {
+ search.enableQuickSearch(options);
});
};
app.handleSearch = function (searchOptions) {
- searchOptions = searchOptions || { in: config.searchDefaultInQuick || 'titles' };
- const searchButton = $('#search-button');
- const searchFields = $('#search-fields');
- const searchInput = $('#search-fields input');
- const quickSearchContainer = $('#quick-search-container');
-
- $('#search-form .advanced-search-link').off('mousedown').on('mousedown', function () {
- ajaxify.go('/search');
- });
-
- $('#search-form').off('submit').on('submit', function () {
- searchInput.blur();
- });
- searchInput.off('blur').on('blur', dismissSearch);
- searchInput.off('focus');
-
- const searchElements = {
- inputEl: searchInput,
- resultEl: quickSearchContainer,
- };
-
- app.enableTopicSearch({
- searchOptions: searchOptions,
- searchElements: searchElements,
- });
-
- function dismissSearch() {
- setTimeout(function () {
- if (!searchInput.is(':focus')) {
- searchFields.addClass('hidden');
- searchButton.removeClass('hidden');
- }
- }, 200);
- }
-
- searchButton.off('click').on('click', function (e) {
- if (!config.loggedIn && !app.user.privileges['search:content']) {
- app.alert({
- message: '[[error:search-requires-login]]',
- timeout: 3000,
- });
- ajaxify.go('login');
- return false;
- }
- e.stopPropagation();
-
- app.prepareSearch();
- return false;
- });
-
- $('#search-form').off('submit').on('submit', function () {
- const input = $(this).find('input');
- require(['search'], function (search) {
- const data = search.getSearchPreferences();
- data.term = input.val();
- hooks.fire('action:search.submit', {
- searchOptions: data,
- searchElements: searchElements,
- });
- search.query(data, function () {
- input.val('');
- });
- });
- return false;
+ console.warn('[deprecated] app.handleSearch is deprecated, please use search.init(options)');
+ require(['search'], function (search) {
+ search.init(searchOptions);
});
};
app.prepareSearch = function () {
- $('#search-fields').removeClass('hidden');
- $('#search-button').addClass('hidden');
- $('#search-fields input').focus();
+ console.warn('[deprecated] app.prepareSearch is deprecated, please use search.showAndFocusInput()');
+ require(['search'], function (search) {
+ search.showAndFocusInput();
+ });
};
function handleStatusChange() {
diff --git a/public/src/client/topic.js b/public/src/client/topic.js
index 03bdeb0736..47dfdba236 100644
--- a/public/src/client/topic.js
+++ b/public/src/client/topic.js
@@ -69,12 +69,12 @@ define('forum/topic', [
function handleTopicSearch() {
if (config.topicSearchEnabled) {
- require(['mousetrap'], function (mousetrap) {
+ require(['mousetrap', 'search'], function (mousetrap, search) {
mousetrap.bind(['command+f', 'ctrl+f'], function (e) {
if (ajaxify.data.template.topic) {
e.preventDefault();
$('#search-fields input').val('in:topic-' + ajaxify.data.tid + ' ');
- app.prepareSearch();
+ search.showAndFocusInput();
}
});
});
diff --git a/public/src/client/topic/merge.js b/public/src/client/topic/merge.js
index ba716d0738..4264838786 100644
--- a/public/src/client/topic/merge.js
+++ b/public/src/client/topic/merge.js
@@ -1,7 +1,7 @@
'use strict';
-define('forum/topic/merge', function () {
+define('forum/topic/merge', ['search'], function (search) {
const Merge = {};
let modal;
let mergeBtn;
@@ -30,7 +30,7 @@ define('forum/topic/merge', function () {
mergeTopics(mergeBtn);
});
- app.enableTopicSearch({
+ search.enableQuickSearch({
searchElements: {
inputEl: modal.find('.topic-search-input'),
resultEl: modal.find('.quick-search-container'),
diff --git a/public/src/modules/search.js b/public/src/modules/search.js
index cd53fac2e9..1249435c69 100644
--- a/public/src/modules/search.js
+++ b/public/src/modules/search.js
@@ -1,11 +1,219 @@
'use strict';
-
-define('search', ['navigator', 'translator', 'storage', 'hooks'], function (nav, translator, storage, hooks) {
+define('search', ['translator', 'storage', 'hooks'], function (translator, storage, hooks) {
const Search = {
current: {},
};
+ Search.init = function (searchOptions) {
+ if (!config.searchEnabled) {
+ return;
+ }
+
+ searchOptions = searchOptions || { in: config.searchDefaultInQuick || 'titles' };
+ const searchButton = $('#search-button');
+ const searchFields = $('#search-fields');
+ const searchInput = $('#search-fields input');
+ const quickSearchContainer = $('#quick-search-container');
+
+ $('#search-form .advanced-search-link').off('mousedown').on('mousedown', function () {
+ ajaxify.go('/search');
+ });
+
+ $('#search-form').off('submit').on('submit', function () {
+ searchInput.blur();
+ });
+ searchInput.off('blur').on('blur', function dismissSearch() {
+ setTimeout(function () {
+ if (!searchInput.is(':focus')) {
+ searchFields.addClass('hidden');
+ searchButton.removeClass('hidden');
+ }
+ }, 200);
+ });
+ searchInput.off('focus');
+
+ const searchElements = {
+ inputEl: searchInput,
+ resultEl: quickSearchContainer,
+ };
+
+ Search.enableQuickSearch({
+ searchOptions: searchOptions,
+ searchElements: searchElements,
+ });
+
+ searchButton.off('click').on('click', function (e) {
+ if (!config.loggedIn && !app.user.privileges['search:content']) {
+ app.alert({
+ message: '[[error:search-requires-login]]',
+ timeout: 3000,
+ });
+ ajaxify.go('login');
+ return false;
+ }
+ e.stopPropagation();
+
+ Search.showAndFocusInput();
+ return false;
+ });
+
+ $('#search-form').off('submit').on('submit', function () {
+ const input = $(this).find('input');
+ const data = Search.getSearchPreferences();
+ data.term = input.val();
+ hooks.fire('action:search.submit', {
+ searchOptions: data,
+ searchElements: searchElements,
+ });
+ Search.query(data, function () {
+ input.val('');
+ });
+
+ return false;
+ });
+ };
+
+ Search.enableQuickSearch = function (options) {
+ if (!config.searchEnabled || !app.user.privileges['search:content']) {
+ return;
+ }
+
+ const searchOptions = Object.assign({ in: config.searchDefaultInQuick || 'titles' }, options.searchOptions);
+ const quickSearchResults = options.searchElements.resultEl;
+ const inputEl = options.searchElements.inputEl;
+ let oldValue = inputEl.val();
+ const filterCategoryEl = quickSearchResults.find('.filter-category');
+
+ function updateCategoryFilterName() {
+ if (ajaxify.data.template.category) {
+ translator.translate('[[search:search-in-category, ' + ajaxify.data.name + ']]', function (translated) {
+ const name = $('').html(translated).text();
+ filterCategoryEl.find('.name').text(name);
+ });
+ }
+ filterCategoryEl.toggleClass('hidden', !ajaxify.data.template.category);
+ }
+
+ function doSearch() {
+ options.searchOptions = Object.assign({}, searchOptions);
+ options.searchOptions.term = inputEl.val();
+ updateCategoryFilterName();
+
+ if (ajaxify.data.template.category) {
+ if (filterCategoryEl.find('input[type="checkbox"]').is(':checked')) {
+ options.searchOptions.categories = [ajaxify.data.cid];
+ options.searchOptions.searchChildren = true;
+ }
+ }
+
+ quickSearchResults.removeClass('hidden').find('.quick-search-results-container').html('');
+ quickSearchResults.find('.loading-indicator').removeClass('hidden');
+ hooks.fire('action:search.quick.start', options);
+ options.searchOptions.searchOnly = 1;
+ Search.api(options.searchOptions, function (data) {
+ quickSearchResults.find('.loading-indicator').addClass('hidden');
+ if (options.hideOnNoMatches && !data.posts.length) {
+ return quickSearchResults.addClass('hidden').find('.quick-search-results-container').html('');
+ }
+ data.posts.forEach(function (p) {
+ const text = $('' + p.content + '
').text();
+ const query = inputEl.val().toLowerCase().replace(/^in:topic-\d+/, '');
+ const start = Math.max(0, text.toLowerCase().indexOf(query) - 40);
+ p.snippet = utils.escapeHTML((start > 0 ? '...' : '') +
+ text.slice(start, start + 80) +
+ (text.length - start > 80 ? '...' : ''));
+ });
+ app.parseAndTranslate('partials/quick-search-results', data, function (html) {
+ if (html.length) {
+ html.find('.timeago').timeago();
+ }
+ quickSearchResults.toggleClass('hidden', !html.length || !inputEl.is(':focus'))
+ .find('.quick-search-results-container')
+ .html(html.length ? html : '');
+ const highlightEls = quickSearchResults.find(
+ '.quick-search-results .quick-search-title, .quick-search-results .snippet'
+ );
+ Search.highlightMatches(options.searchOptions.term, highlightEls);
+ hooks.fire('action:search.quick.complete', {
+ data: data,
+ options: options,
+ });
+ });
+ });
+ }
+
+ quickSearchResults.find('.filter-category input[type="checkbox"]').on('change', function () {
+ inputEl.focus();
+ doSearch();
+ });
+
+ inputEl.off('keyup').on('keyup', utils.debounce(function () {
+ if (inputEl.val().length < 3) {
+ quickSearchResults.addClass('hidden');
+ oldValue = inputEl.val();
+ return;
+ }
+ if (inputEl.val() === oldValue) {
+ return;
+ }
+ oldValue = inputEl.val();
+ if (!inputEl.is(':focus')) {
+ return quickSearchResults.addClass('hidden');
+ }
+ doSearch();
+ }, 500));
+
+ let mousedownOnResults = false;
+ quickSearchResults.on('mousedown', function () {
+ $(window).one('mouseup', function () {
+ quickSearchResults.addClass('hidden');
+ });
+ mousedownOnResults = true;
+ });
+ inputEl.on('blur', function () {
+ if (!inputEl.is(':focus') && !mousedownOnResults && !quickSearchResults.hasClass('hidden')) {
+ quickSearchResults.addClass('hidden');
+ }
+ });
+
+ let ajaxified = false;
+ hooks.on('action:ajaxify.end', function () {
+ if (!ajaxify.isCold()) {
+ ajaxified = true;
+ }
+ });
+
+ inputEl.on('focus', function () {
+ mousedownOnResults = false;
+ const query = inputEl.val();
+ oldValue = query;
+ if (query && quickSearchResults.find('#quick-search-results').children().length) {
+ updateCategoryFilterName();
+ if (ajaxified) {
+ doSearch();
+ ajaxified = false;
+ } else {
+ quickSearchResults.removeClass('hidden');
+ }
+ inputEl[0].setSelectionRange(
+ query.startsWith('in:topic') ? query.indexOf(' ') + 1 : 0,
+ query.length
+ );
+ }
+ });
+
+ inputEl.off('refresh').on('refresh', function () {
+ doSearch();
+ });
+ };
+
+ Search.showAndFocusInput = function () {
+ $('#search-fields').removeClass('hidden');
+ $('#search-button').addClass('hidden');
+ $('#search-fields input').focus();
+ };
+
Search.query = function (data, callback) {
callback = callback || function () {};
ajaxify.go('search?' + createQueryString(data));
diff --git a/src/meta/js.js b/src/meta/js.js
index 7d5fc7fb42..742d27d61d 100644
--- a/src/meta/js.js
+++ b/src/meta/js.js
@@ -75,6 +75,7 @@ JS.scripts = {
'public/src/modules/storage.js',
'public/src/modules/handleBack.js',
'public/src/modules/messages.js',
+ 'public/src/modules/search.js',
],
admin: [