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.

241 lines
5.9 KiB
JavaScript

'use strict';
define('search', ['navigator', 'translator', 'storage', 'hooks'], function (nav, translator, storage, hooks) {
var Search = {
current: {},
};
Search.query = function (data, callback) {
// Detect if a tid was specified
var topicSearch = data.term.match(/^in:topic-([\d]+) /);
callback = callback || function () {};
if (!topicSearch) {
ajaxify.go('search?' + createQueryString(data));
callback();
} else {
var cleanedTerm = data.term.replace(topicSearch[0], '');
var tid = topicSearch[1];
if (cleanedTerm.length > 0) {
Search.queryTopic(tid, cleanedTerm, callback);
}
}
};
Search.api = function (data, callback) {
var apiURL = config.relative_path + '/api/search?' + createQueryString(data);
data.searchOnly = undefined;
var searchURL = config.relative_path + '/search?' + createQueryString(data);
$.get(apiURL, function (result) {
result.url = searchURL;
callback(result);
});
};
function createQueryString(data) {
var searchIn = data.in || 'titles';
var postedBy = data.by || '';
var term = data.term.replace(/^[ ?#]*/, '');
try {
term = encodeURIComponent(term);
} catch (e) {
return app.alertError('[[error:invalid-search-term]]');
}
var query = {
term: term,
in: searchIn,
};
if (data.matchWords) {
query.matchWords = data.matchWords;
}
if (postedBy && postedBy.length && (searchIn === 'posts' || searchIn === 'titles' || searchIn === 'titlesposts')) {
query.by = postedBy;
}
if (data.categories && data.categories.length) {
query.categories = data.categories;
if (data.searchChildren) {
query.searchChildren = data.searchChildren;
}
}
if (data.hasTags && data.hasTags.length) {
query.hasTags = data.hasTags;
}
if (parseInt(data.replies, 10) > 0) {
query.replies = data.replies;
query.repliesFilter = data.repliesFilter || 'atleast';
}
if (data.timeRange) {
query.timeRange = data.timeRange;
query.timeFilter = data.timeFilter || 'newer';
}
if (data.sortBy) {
query.sortBy = data.sortBy;
query.sortDirection = data.sortDirection;
}
if (data.showAs) {
query.showAs = data.showAs;
}
if (data.searchOnly) {
query.searchOnly = data.searchOnly;
}
hooks.fire('action:search.createQueryString', {
query: query,
data: data,
});
return decodeURIComponent($.param(query));
}
Search.getSearchPreferences = function () {
try {
return JSON.parse(storage.getItem('search-preferences') || '{}');
} catch (e) {
return {};
}
};
Search.highlightMatches = function (searchQuery, els) {
if (!searchQuery || !els.length) {
return;
}
searchQuery = utils.escapeHTML(searchQuery.replace(/^"/, '').replace(/"$/, '').trim());
var regexStr = searchQuery.split(' ')
.map(function (word) { return utils.escapeRegexChars(word); })
.join('|');
var regex = new RegExp('(' + regexStr + ')', 'gi');
els.each(function () {
var result = $(this);
var nested = [];
result.find('*').each(function () {
$(this).after('<!-- ' + nested.length + ' -->');
nested.push($('<div></div>').append($(this)));
});
result.html(result.html().replace(regex, function (match, p1) {
return '<strong class="search-match">' + p1 + '</strong>';
}));
nested.forEach(function (nestedEl, i) {
result.html(result.html().replace('<!-- ' + i + ' -->', function () {
return nestedEl.html();
}));
});
});
$('.search-result-text').find('img:not(.not-responsive)').addClass('img-responsive');
};
Search.queryTopic = function (tid, term) {
socket.emit('topics.search', {
tid: tid,
term: term,
}, function (err, pids) {
if (err) {
return app.alertError(err.message);
}
if (Array.isArray(pids)) {
// Sort pids numerically & store
Search.current = {
results: pids.sort(function (a, b) {
return a - b;
}),
tid: tid,
term: term,
};
Search.checkPagePresence(tid, function () {
Search.topicDOM.update(0);
});
}
});
};
Search.checkPagePresence = function (tid, callback) {
if (parseInt(ajaxify.data.tid, 10) !== parseInt(tid, 10)) {
ajaxify.go('topic/' + tid, callback);
} else {
callback();
}
};
Search.topicDOM = {
active: false,
};
Search.topicDOM.prev = function () {
Search.topicDOM.update((Search.current.index === 0) ? Search.current.results.length - 1 : Search.current.index - 1);
};
Search.topicDOM.next = function () {
Search.topicDOM.update((Search.current.index === Search.current.results.length - 1) ? 0 : Search.current.index + 1);
};
Search.topicDOM.update = function (index) {
var topicSearchEl = $('.topic-search');
Search.current.index = index;
Search.topicDOM.start();
if (Search.current.results.length > 0) {
topicSearchEl.find('.count').html((index + 1) + ' / ' + Search.current.results.length);
topicSearchEl.find('.prev, .next').removeAttr('disabled');
var data = {
pid: Search.current.results[index],
tid: Search.current.tid,
topicPostSort: config.topicPostSort,
};
socket.emit('posts.getPidIndex', data, function (err, postIndex) {
if (err) {
return app.alertError(err.message);
}
nav.scrollToIndex(postIndex, true);
});
} else {
translator.translate('[[search:no-matches]]', function (text) {
topicSearchEl.find('.count').html(text);
});
topicSearchEl.removeClass('hidden').find('.prev, .next').attr('disabled', 'disabled');
}
};
Search.topicDOM.start = function () {
$('.topic-search').removeClass('hidden');
if (!Search.topicDOM.active) {
Search.topicDOM.active = true;
// Bind to esc
require(['mousetrap'], function (mousetrap) {
mousetrap.bind('esc', Search.topicDOM.end);
});
}
};
Search.topicDOM.end = function () {
$('.topic-search').addClass('hidden').find('.prev, .next').attr('disabled', 'disabled');
Search.topicDOM.active = false;
// Unbind esc
require(['mousetrap'], function (mousetrap) {
mousetrap.unbind('esc', Search.topicDOM.end);
});
};
return Search;
});