Files
pillar/src/scripts/elasticsearch.js
Tobias Johansson 6ae9a5ddeb Quick-Search: Added Quick-search in the topbar
Changed how and what we store in elastic to unify it with how we store
things in mongodb so we can have more generic javascript code
to render the data.

Elastic changes:
  Added:
  Node.project.url

  Altered to store id instead of url
  Node.picture

  Made Post searchable

./manage.py elastic reset_index
./manage.py elastic reindex

Thanks to Pablo and Sybren
2018-11-22 15:31:53 +01:00

339 lines
10 KiB
JavaScript

$(document).ready(function() {
var HITS_PER_PAGE = 10;
var MAX_VALUES_PER_FACET = 30;
// DOM binding
var $inputField = $('#q');
var $hits = $('#hits');
var $stats = $('#stats');
var $facets = $('#facets');
var $pagination = $('#pagination');
var what = '';
// Templates binding
var statsTemplate = Hogan.compile($('#stats-template').text());
var facetTemplate = Hogan.compile($('#facet-template').text());
var paginationTemplate = Hogan.compile($('#pagination-template').text());
// defined in tutti/4_search.js
var search = elasticSearcher;
// what are we looking for? users? assets (default)
what = $inputField.attr('what');
function do_search(query) {
if (query === undefined) {
return;
}
toggleIconEmptyInput(!query.trim());
search.setQuery(query, what); // what could be like "/users"
var pid = ProjectUtils.projectId();
if (pid) search.setProjectID(pid);
search.execute();
}
// Input binding
$inputField.on('keyup change', function() {
var query = $inputField.val();
do_search(query);
}).focus();
search.on('results', function(content) {
renderStats(content);
renderHits(content);
renderFacets(content);
renderPagination(content);
renderFirstHit($(hits).children('.search-hit:first'));
updateUrlParams();
});
/***************
* SEARCH RENDERING
* ***********/
function renderFirstHit(firstHit) {
firstHit.addClass('active');
firstHit.find('#search-loading').addClass('active');
function done() {
$('.search-loading').removeClass('active');
$('#search-error').hide();
$('#search-hit-container').show();
}
window.setTimeout(function() {
// Ignore getting that first result when there is none.
var hit_id = firstHit.attr('data-node-id');
if (hit_id === undefined) {
done();
return;
}
$.get('/nodes/' + hit_id + '/view', function(dataHtml) {
$('#search-hit-container').html(dataHtml);
})
.done(done)
.fail(function(data) {
$('.search-loading').removeClass('active');
$('#search-hit-container').hide();
$('#search-error').show().html('Houston!\n\n' + data.status + ' ' + data.statusText);
});
}, 1000);
}
// Initial search
initWithUrlParams();
function renderStats(content) {
var stats = {
nbHits: numberWithDelimiter(content.count),
processingTimeMS: content.took,
nbHits_plural: content.nbHits !== 1
};
$stats.html(statsTemplate.render(stats));
}
function renderHits(content) {
$hits.empty();
if (content.hits.length === 0) {
$hits.html('<p id="no-hits">We didn\'t find any items. Try searching something else.</p>');
}
else {
listof$hits = content.hits.map(function(hit){
return pillar.templates.Component.create$listItem(hit)
.addClass('js-search-hit cursor-pointer search-hit');
})
$hits.append(listof$hits);
}
}
function renderFacets(content) {
// If no results
if (content.hits.length === 0) {
$facets.empty();
facets = [];
return;
}
var storeValue = function(values, label) {
return function(item) {
var refined = search.isRefined(label, item.key);
values.push({
facet: label,
label: item.key_as_string || item.key,
value: item.key,
count: item.doc_count,
refined: refined,
});
};
};
var facets = [];
var aggs = content.aggs;
for (var label in aggs) {
var values = [];
var buckets = aggs[label].buckets;
if (buckets.length === 0) {
continue;
}
buckets.forEach(storeValue(values, label));
facets.push({
title: removeUnderscore(label),
values: values.slice(0),
});
}
// Display facets
var facetsHtml = '';
for (var indexFacet = 0; indexFacet < facets.length; ++indexFacet) {
var facet = facets[indexFacet];
//title, values[facet, value]
facetsHtml += facetTemplate.render(facet);
}
$facets.html(facetsHtml);
}
function renderPagination(content) {
// If no results
if (content.count === 0) {
$pagination.empty();
return;
}
var maxPages = 3;
var nbPages = Math.floor(content.count / HITS_PER_PAGE);
// Process pagination
var pages = [];
if (content.page > maxPages) {
pages.push({
current: false,
number: 0,
shownr: 1
});
}
for (var p = content.page - maxPages; p < content.page + maxPages; ++p) {
if (p < 0 || p > nbPages) {
continue;
}
pages.push({
current: content.page === p,
number: p,
shownr: p+1
});
}
if (content.page + maxPages < nbPages) {
pages.push({
current: false,
number: nbPages-1,
shownr: nbPages
});
}
var pagination = {
pages: pages,
};
if (content.page > 0) {
pagination.prev_page = {page: content.page - 1};
}
if (content.page < nbPages) {
pagination.next_page = {page: content.page + 1};
}
// Display pagination
$pagination.html(paginationTemplate.render(pagination));
}
function removeUnderscore(s) {
return s.replace(/_/g, ' ')
}
// Event bindings
// Click binding
$(document).on('click', '.show-more, .show-less', function(e) {
e.preventDefault();
$(this).closest('ul').find('.show-more').toggle();
$(this).closest('ul').find('.show-less').toggle();
return false;
});
$(document).on('click', '.toggleRefine', function() {
search.toggleTerm($(this).data('facet'), $(this).data('value'));
search.execute();
return false;
});
$(document).on('click', '.gotoPage', function() {
const page_idx = $(this).data('page');
search.setCurrentPage(page_idx);
search.execute();
$("html, body").animate({
scrollTop: 0
}, '500', 'swing');
return false;
});
$(document).on('click', '.sortBy', function() {
$(this).closest('.btn-group').find('.sort-by').text($(this).text());
//helper.setIndex(INDEX_NAME + $(this).data('index-suffix')).search();
return false;
});
$(document).on('click', '#input-loop', function() {
$inputField.val('').change();
});
// Dynamic styles
$('#facets').on("mouseenter mouseleave", ".button-checkbox", function(e) {
$(this).parent().find('.facet_link').toggleClass("hover");
});
$('#facets').on("mouseenter mouseleave", ".facet_link", function(e) {
$(this).parent().find('.button-checkbox button.btn').toggleClass("hover");
});
/************
* HELPERS
* ***********/
function toggleIconEmptyInput(isEmpty) {
if (isEmpty) {
$('#input-loop').addClass('glyphicon-loop');
$('#input-loop').removeClass('glyphicon-remove');
} else {
$('#input-loop').removeClass('glyphicon-loop');
$('#input-loop').addClass('glyphicon-remove');
}
}
function numberWithDelimiter(number, delimiter) {
number = number + '';
delimiter = delimiter || ',';
var split = number.split('.');
split[0] = split[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + delimiter);
return split.join('.');
}
var sortByCountDesc = function sortByCountDesc(a, b) {
return b.count - a.count;
};
var sortByName = function sortByName(a, b) {
return a.value.localeCompare(b.value);
};
var sortByRefined = function sortByRefined(sortFunction) {
return function(a, b) {
if (a.refined !== b.refined) {
if (a.refined) return -1;
if (b.refined) return 1;
}
return sortFunction(a, b);
};
};
function initWithUrlParams() {
var pageURL = decodeURIComponent(window.location.search.substring(1)),
urlVariables = pageURL.split('&'),
query,
i;
for (i = 0; i < urlVariables.length; i++) {
var parameterPair = urlVariables[i].split('='),
key = parameterPair[0],
sValue = parameterPair[1];
if (!key) continue;
if (key === 'q') {
query = sValue;
continue;
}
if (key === 'page') {
var page = Number.parseInt(sValue)
search.setCurrentPage(isNaN(page) ? 0 : page)
continue;
}
if (key === 'project') {
continue; // We take the project from the path
}
if (sValue !== undefined) {
var iValue = Number.parseInt(sValue),
value = isNaN(iValue) ? sValue : iValue;
search.toggleTerm(key, value);
continue;
}
console.log('Unhandled url parameter pair:', parameterPair)
}
$inputField.val(query);
do_search(query || '');
}
function updateUrlParams() {
var prevState = history.state,
prevTitle = document.title,
params = search.getParams(),
newUrl = window.location.pathname + '?';
delete params['project'] // We take the project from the path
newUrl += jQuery.param(params)
history.replaceState(prevState, prevTitle, newUrl);
}
});