You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
4.1 KiB
JavaScript
153 lines
4.1 KiB
JavaScript
"use strict";
|
|
/* globals socket, app, define, ajaxify, config */
|
|
|
|
define('admin/modules/search', ['mousetrap'], function (mousetrap) {
|
|
var search = {};
|
|
|
|
function find(dict, term) {
|
|
var html = dict.filter(function (elem) {
|
|
return elem.translations.toLowerCase().includes(term);
|
|
}).map(function (params) {
|
|
var namespace = params.namespace;
|
|
var translations = params.translations;
|
|
var title = params.title;
|
|
|
|
var results = translations
|
|
// remove all lines without a match
|
|
.replace(new RegExp('^(?:(?!' + term + ').)*$', 'gmi'), '')
|
|
// remove lines that only match the title
|
|
.replace(new RegExp('(^|\\n).*?' + title + '.*?(\\n|$)', 'g'), '')
|
|
// get up to 25 characters of context on both sides of the match
|
|
// and wrap the match in a `.search-match` element
|
|
.replace(
|
|
new RegExp('^[\\s\\S]*?(.{0,25})(' + term + ')(.{0,25})[\\s\\S]*?$', 'gmi'),
|
|
'...$1<span class="search-match">$2</span>$3...<br>'
|
|
)
|
|
// collapse whitespace
|
|
.replace(/(?:\n ?)+/g, '\n')
|
|
.trim();
|
|
|
|
title = title.replace(
|
|
new RegExp('(^.*?)(' + term + ')(.*?$)', 'gi'),
|
|
'$1<span class="search-match">$2</span>$3'
|
|
);
|
|
|
|
return '<li role="presentation" class="result">' +
|
|
'<a role= "menuitem" href= "' + config.relative_path + '/' + namespace + '" >' +
|
|
title +
|
|
'<br>' + (!results ? '' :
|
|
('<small><code>' +
|
|
results +
|
|
'</small></code>')) +
|
|
'</a>' +
|
|
'</li>';
|
|
}).join('');
|
|
return html;
|
|
}
|
|
|
|
search.init = function () {
|
|
socket.emit('admin.getSearchDict', {}, function (err, dict) {
|
|
if (err) {
|
|
app.alertError(err);
|
|
throw err;
|
|
}
|
|
setupACPSearch(dict);
|
|
});
|
|
};
|
|
|
|
function setupACPSearch(dict) {
|
|
var dropdown = $('#acp-search .dropdown');
|
|
var menu = $('#acp-search .dropdown-menu');
|
|
var input = $('#acp-search input');
|
|
|
|
if (!config.searchEnabled) {
|
|
menu.addClass('search-disabled');
|
|
}
|
|
|
|
input.on('keyup', function () {
|
|
dropdown.addClass('open');
|
|
});
|
|
|
|
$('#acp-search').parents('form').on('submit', function (ev) {
|
|
var selected = menu.find('li.result > a.focus').attr('href');
|
|
if (!selected.length) {
|
|
selected = menu.find('li.result > a').first().attr('href');
|
|
}
|
|
var href = selected ? selected : config.relative_path + '/search/' + input.val();
|
|
|
|
ajaxify.go(href.replace(/^\//, ''));
|
|
|
|
setTimeout(function () {
|
|
dropdown.removeClass('open');
|
|
input.blur();
|
|
}, 150);
|
|
|
|
ev.preventDefault();
|
|
return false;
|
|
});
|
|
|
|
mousetrap(input[0]).bind(['up', 'down'], function (ev, key) {
|
|
var next;
|
|
if (key === 'up') {
|
|
next = menu.find('li.result > a.focus').removeClass('focus').parent().prev('.result').children();
|
|
if (!next.length) {
|
|
next = menu.find('li.result > a').last();
|
|
}
|
|
next.addClass('focus');
|
|
if (menu[0].getBoundingClientRect().top > next[0].getBoundingClientRect().top) {
|
|
next[0].scrollIntoView(true);
|
|
}
|
|
} else if (key === 'down') {
|
|
next = menu.find('li.result > a.focus').removeClass('focus').parent().next('.result').children();
|
|
if (!next.length) {
|
|
next = menu.find('li.result > a').first();
|
|
}
|
|
next.addClass('focus');
|
|
if (menu[0].getBoundingClientRect().bottom < next[0].getBoundingClientRect().bottom) {
|
|
next[0].scrollIntoView(false);
|
|
}
|
|
}
|
|
|
|
ev.preventDefault();
|
|
});
|
|
|
|
var prevValue;
|
|
|
|
input.on('keyup focus', function () {
|
|
var value = input.val().toLowerCase();
|
|
|
|
if (value === prevValue) {
|
|
return;
|
|
}
|
|
prevValue = value;
|
|
|
|
menu.children('.result').remove();
|
|
|
|
var len = value.length;
|
|
var results;
|
|
|
|
menu.toggleClass('state-start-typing', len === 0);
|
|
menu.toggleClass('state-keep-typing', len > 0 && len < 3);
|
|
|
|
if (len >= 3) {
|
|
menu.prepend(find(dict, value));
|
|
|
|
results = menu.children('.result').length;
|
|
|
|
menu.toggleClass('state-no-results', !results);
|
|
menu.toggleClass('state-yes-results', !!results);
|
|
|
|
menu.find('.search-forum')
|
|
.not('.divider')
|
|
.find('a')
|
|
.attr('href', config.relative_path + '/search/' + value)
|
|
.find('strong')
|
|
.html(value);
|
|
} else {
|
|
menu.removeClass('state-no-results state-yes-results');
|
|
}
|
|
});
|
|
}
|
|
|
|
return search;
|
|
}); |