T53161 javascript search stuff almost complete.

This commit is contained in:
2017-11-24 17:47:38 +01:00
parent 1bda98228c
commit 9cd3d97c75
7 changed files with 245 additions and 155 deletions

View File

@@ -18,7 +18,20 @@ client = Elasticsearch()
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def do_search(query: str) -> dict:
def add_aggs_to_search(search):
"""
"""
agg_terms = ['node_type', 'media', 'tags', 'is_free']
for term in agg_terms:
search.aggs.bucket(term, 'terms', field=term)
#search.aggs.bucket('project', 'terms', field='project.name')
def do_search(query: str, terms: dict) -> dict:
""" """
Given user input search for node/stuff Given user input search for node/stuff
""" """
@@ -32,15 +45,26 @@ def do_search(query: str) -> dict:
Q('term', media=query), Q('term', media=query),
Q('term', tags=query), Q('term', tags=query),
] ]
#must = []
#for field, value in terms.items():
# must.append(
bool_query = Q('bool', should=should) bool_query = Q('bool', should=should)
search = Search(using=client) search = Search(using=client)
search.query = bool_query search.query = bool_query
add_aggs_to_search(search)
if current_app.config['DEBUG']: if current_app.config['DEBUG']:
log.debug(json.dumps(search.to_dict(), indent=4)) print(json.dumps(search.to_dict(), indent=4))
response = search.execute() response = search.execute()
if current_app.config['DEBUG']:
print(json.dumps(response.to_dict(), indent=4))
return response.to_dict() return response.to_dict()
@@ -61,6 +85,9 @@ def do_user_search(query: str) -> dict:
response = search.execute() response = search.execute()
if current_app.config['DEBUG']:
log.debug('%s', json.dumps(response.to_dict(), indent=4))
return response.to_dict() return response.to_dict()
@@ -82,4 +109,7 @@ def do_user_search_admin(query: str) -> dict:
response = search.execute() response = search.execute()
if current_app.config['DEBUG']:
log.debug(json.dumps(response.to_dict(), indent=4))
return response.to_dict() return response.to_dict()

View File

@@ -30,10 +30,28 @@ def _valid_search() -> str:
return searchword return searchword
def _term_filters() -> dict:
"""
Check if frontent want to filter stuff
"""
terms = [
'node_type', 'media',
'tags', 'is_free', 'projectname']
parsed_terms = {}
for term in terms:
parsed_terms[term] = request.args.get(term, '')
return parsed_terms
@blueprint_search.route('/') @blueprint_search.route('/')
def search_nodes(): def search_nodes():
searchword = _valid_search() searchword = _valid_search()
data = queries.do_search(searchword) terms = _term_filters()
data = queries.do_search(searchword, terms)
return jsonify(data) return jsonify(data)

View File

@@ -1,11 +1,5 @@
$(document).ready(function() { $(document).ready(function() {
/********************
* INITIALIZATION
*
* TODO (stephan)
* *******************/
var HITS_PER_PAGE = 25; var HITS_PER_PAGE = 25;
var MAX_VALUES_PER_FACET = 30; var MAX_VALUES_PER_FACET = 30;
@@ -23,65 +17,44 @@ $(document).ready(function() {
var sliderTemplate = Hogan.compile($('#slider-template').text()); var sliderTemplate = Hogan.compile($('#slider-template').text());
var paginationTemplate = Hogan.compile($('#pagination-template').text()); var paginationTemplate = Hogan.compile($('#pagination-template').text());
// replace with something elasticy! // something elasticy!
// Client initialization var search = elasticSearcher;
var algolia = algoliasearch(APPLICATION_ID, SEARCH_ONLY_API_KEY); // facets: $.map(FACET_CONFIG, function(facet) {
// return !facet.disjunctive ? facet.name : null;
// Helper initialization // }),
var params = { // disjunctiveFacets: $.map(FACET_CONFIG, function(facet) {
hitsPerPage: HITS_PER_PAGE, // return facet.disjunctive ? facet.name : null;
maxValuesPerFacet: MAX_VALUES_PER_FACET, // })
facets: $.map(FACET_CONFIG, function(facet) { //};
return !facet.disjunctive ? facet.name : null;
}),
disjunctiveFacets: $.map(FACET_CONFIG, function(facet) {
return facet.disjunctive ? facet.name : null;
})
};
// replace with something elastici!
// Setup the search helper
var helper = algoliasearchHelper(algolia, INDEX_NAME, params);
// Check if we passed hidden facets in the FACET_CONFIG
var result = $.grep(FACET_CONFIG, function(e) {
return e.hidden && e.hidden == true;
});
for (var i = 0; i < result.length; i++) {
var f = result[i];
helper.addFacetRefinement(f.name, f.value);
}
// Input binding // Input binding
$inputField.on('keyup change', function() { $inputField.on('keyup change', function() {
var query = $inputField.val(); var query = $inputField.val();
if(query === undefined) { return; }
toggleIconEmptyInput(!query.trim()); toggleIconEmptyInput(!query.trim());
helper.setQuery(query).search(); search.setQuery(query);
//setURLParams(search);
search.execute();
}).focus(); }).focus();
// AlgoliaHelper events // AlgoliaHelper events
helper.on('change', function(state) { //helper.on('change', function(state) {
setURLParams(state); //setURLParams(search);
}); //});
helper.on('error', function(error) { search.on('results', function(content){
console.log(error);
});
helper.on('result', function(content, state) {
renderStats(content); renderStats(content);
renderHits(content); renderHits(content);
renderFacets(content, state); renderFacets(content);
renderPagination(content); renderPagination(content);
bindSearchObjects(); bindSearchObjects();
renderFirstHit($(hits).children('.search-hit:first')); renderFirstHit($(hits).children('.search-hit:first'));
}); });
/************ //});
* SEARCH
/***************
* SEARCH RENDERING
* ***********/ * ***********/
function renderFirstHit(firstHit) { function renderFirstHit(firstHit) {
@@ -113,11 +86,11 @@ $(document).ready(function() {
$('#search-error').show().html('Houston!\n\n' + data.status + ' ' + data.statusText); $('#search-error').show().html('Houston!\n\n' + data.status + ' ' + data.statusText);
}); });
}, 1000); }, 1000);
}; }
// Initial search // Initial search
initWithUrlParams(); initWithUrlParams();
helper.search(); //helper.search();
function convertTimestamp(timestamp) { function convertTimestamp(timestamp) {
var d = new Date(timestamp * 1000), // Convert the passed timestamp to milliseconds var d = new Date(timestamp * 1000), // Convert the passed timestamp to milliseconds
@@ -134,8 +107,8 @@ $(document).ready(function() {
function renderStats(content) { function renderStats(content) {
var stats = { var stats = {
nbHits: numberWithDelimiter(content.nbHits), nbHits: numberWithDelimiter(content.count),
processingTimeMS: content.processingTimeMS, processingTimeMS: content.took,
nbHits_plural: content.nbHits !== 1 nbHits_plural: content.nbHits !== 1
}; };
$stats.html(statsTemplate.render(stats)); $stats.html(statsTemplate.render(stats));
@@ -145,13 +118,13 @@ $(document).ready(function() {
var hitsHtml = ''; var hitsHtml = '';
for (var i = 0; i < content.hits.length; ++i) { for (var i = 0; i < content.hits.length; ++i) {
// console.log(content.hits[i]); // console.log(content.hits[i]);
var created = content.hits[i]['created']; var created = content.hits[i].created;
if (created) { if (created) {
content.hits[i]['created'] = convertTimestamp(created); content.hits[i].created = convertTimestamp(created);
} }
var updated = content.hits[i]['updated']; var updated = content.hits[i].updated;
if (updated) { if (updated) {
content.hits[i]['updated'] = convertTimestamp(updated); content.hits[i].updated = convertTimestamp(updated);
} }
hitsHtml += hitTemplate.render(content.hits[i]); hitsHtml += hitTemplate.render(content.hits[i]);
} }
@@ -159,87 +132,67 @@ $(document).ready(function() {
$hits.html(hitsHtml); $hits.html(hitsHtml);
} }
function renderFacets(content, state) { function renderFacets(content) {
// If no results // If no results
if (content.hits.length === 0) { if (content.hits.length === 0) {
$facets.empty(); $facets.empty();
return; return;
} }
// Process facets var storeValue = function (values, label){
var facets = [];
for (var facetIndex = 0; facetIndex < FACET_CONFIG.length; ++facetIndex) {
var facetParams = FACET_CONFIG[facetIndex];
if (facetParams.hidden) {
continue
}
var facetResult = content.getFacetByName(facetParams.name);
if (facetResult) {
var facetContent = {};
facetContent.facet = facetParams.name;
facetContent.title = facetParams.title;
facetContent.type = facetParams.type;
if (facetParams.type === 'slider') { return function(item){
// if the facet is a slider values.push({
facetContent.min = facetResult.stats.min; facet: label,
facetContent.max = facetResult.stats.max; label: item.key,
var valueMin = state.getNumericRefinement(facetParams.name, '>=') || facetResult.stats.min; value: item.key,
var valueMax = state.getNumericRefinement(facetParams.name, '<=') || facetResult.stats.max; count: item.doc_count,
valueMin = Math.min(facetContent.max, Math.max(facetContent.min, valueMin)); });
valueMax = Math.min(facetContent.max, Math.max(facetContent.min, valueMax)); };
facetContent.values = [valueMin, valueMax]; };
} else {
// format and sort the facet values console.log('FACETS');
var values = []; var facets =[];
for (var v in facetResult.data) { var aggs = content.aggs;
var label = '';
if (v === 'true') { for (var label in aggs) {
label = 'Yes';
} else if (v === 'false') { let values = [];
label = 'No';
} let buckets = aggs[label].buckets;
// Remove any underscore from the value
else { if (buckets.length === 0) { continue; }
label = v.replace(/_/g, " ");
} buckets.forEach(storeValue(values, label));
values.push({
label: label, facets.push({
value: v, title: label,
count: facetResult.data[v], values: values.slice(0),
refined: helper.isRefined(facetParams.name, v) });
}); }
}
var sortFunction = facetParams.sortFunction || sortByCountDesc;
if (facetParams.topListIfRefined) sortFunction = sortByRefined(sortFunction);
values.sort(sortFunction);
facetContent.values = values.slice(0, 10);
facetContent.has_other_values = values.length > 10;
facetContent.other_values = values.slice(10);
facetContent.disjunctive = facetParams.disjunctive;
}
facets.push(facetContent);
}
}
// Display facets // Display facets
var facetsHtml = ''; var facetsHtml = '';
for (var indexFacet = 0; indexFacet < facets.length; ++indexFacet) { for (var indexFacet = 0; indexFacet < facets.length; ++indexFacet) {
var facet = facets[indexFacet]; var facet = facets[indexFacet];
if (facet.type && facet.type === 'slider') facetsHtml += sliderTemplate.render(facet); //title, values[facet, value]
else facetsHtml += facetTemplate.render(facet); facetsHtml += facetTemplate.render(facet);
} }
$facets.html(facetsHtml); $facets.html(facetsHtml);
} }
function renderPagination(content) { function renderPagination(content) {
// If no results // If no results
if (content.hits.length === 0) { if (content.count === 0) {
$pagination.empty(); $pagination.empty();
return; return;
} }
var maxPages = 2; var maxPages = 2;
var nbPages = content.count / HITS_PER_PAGE;
// Process pagination // Process pagination
var pages = []; var pages = [];
@@ -252,7 +205,7 @@ $(document).ready(function() {
// pages.push({ current: false, number: '...', disabled: true }); // pages.push({ current: false, number: '...', disabled: true });
} }
for (var p = content.page - maxPages; p < content.page + maxPages; ++p) { for (var p = content.page - maxPages; p < content.page + maxPages; ++p) {
if (p < 0 || p >= content.nbPages) { if (p < 0 || p >= nbPages) {
continue; continue;
} }
pages.push({ pages.push({
@@ -260,18 +213,18 @@ $(document).ready(function() {
number: (p + 1) number: (p + 1)
}); });
} }
if (content.page + maxPages < content.nbPages) { if (content.page + maxPages < nbPages) {
// They don't really add much... // They don't really add much...
// pages.push({ current: false, number: '...', disabled: true }); // pages.push({ current: false, number: '...', disabled: true });
pages.push({ pages.push({
current: false, current: false,
number: content.nbPages number: nbPages
}); });
} }
var pagination = { var pagination = {
pages: pages, pages: pages,
prev_page: (content.page > 0 ? content.page : false), prev_page: (content.page > 0 ? content.page : false),
next_page: (content.page + 1 < content.nbPages ? content.page + 2 : false) next_page: (content.page + 1 < nbPages ? content.page + 2 : false)
}; };
// Display pagination // Display pagination
$pagination.html(paginationTemplate.render(pagination)); $pagination.html(paginationTemplate.render(pagination));
@@ -297,12 +250,15 @@ $(document).ready(function() {
$(this).closest('ul').find('.show-less').toggle(); $(this).closest('ul').find('.show-less').toggle();
return false; return false;
}); });
$(document).on('click', '.toggleRefine', function() { $(document).on('click', '.toggleRefine', function() {
helper.toggleRefine($(this).data('facet'), $(this).data('value')).search(); search.addTerm($(this).data('facet'), $(this).data('value'));
search.execute();
return false; return false;
}); });
$(document).on('click', '.gotoPage', function() { $(document).on('click', '.gotoPage', function() {
helper.setCurrentPage(+$(this).data('page') - 1).search(); //helper.setCurrentPage(+$(this).data('page') - 1).search();
$("html, body").animate({ $("html, body").animate({
scrollTop: 0 scrollTop: 0
}, '500', 'swing'); }, '500', 'swing');
@@ -310,7 +266,7 @@ $(document).ready(function() {
}); });
$(document).on('click', '.sortBy', function() { $(document).on('click', '.sortBy', function() {
$(this).closest('.btn-group').find('.sort-by').text($(this).text()); $(this).closest('.btn-group').find('.sort-by').text($(this).text());
helper.setIndex(INDEX_NAME + $(this).data('index-suffix')).search(); //helper.setIndex(INDEX_NAME + $(this).data('index-suffix')).search();
return false; return false;
}); });
$(document).on('click', '#input-loop', function() { $(document).on('click', '#input-loop', function() {
@@ -374,33 +330,35 @@ $(document).ready(function() {
} }
var query = decodeURIComponent(sURLVariables[0].split('=')[1]); var query = decodeURIComponent(sURLVariables[0].split('=')[1]);
$inputField.val(query); $inputField.val(query);
helper.setQuery(query); search.setQuery(query);
for (var i = 2; i < sURLVariables.length; i++) { for (var i = 2; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('='); var sParameterName = sURLVariables[i].split('=');
var facet = decodeURIComponent(sParameterName[0]); var facet = decodeURIComponent(sParameterName[0]);
var value = decodeURIComponent(sParameterName[1]); var value = decodeURIComponent(sParameterName[1]);
helper.toggleRefine(facet, value, false); //helper.toggleRefine(facet, value, false);
} }
// Page has to be set in the end to avoid being overwritten // Page has to be set in the end to avoid being overwritten
var page = decodeURIComponent(sURLVariables[1].split('=')[1]) - 1; var page = decodeURIComponent(sURLVariables[1].split('=')[1]) - 1;
helper.setCurrentPage(page); search.setCurrentPage(page);
} }
function setURLParams(state) { function setURLParams(state) {
var urlParams = '#'; var urlParams = '?';
var currentQuery = state.query; var currentQuery = state.query;
urlParams += 'q=' + encodeURIComponent(currentQuery); urlParams += 'q=' + encodeURIComponent(currentQuery);
var currentPage = state.page + 1; var currentPage = state.page + 1;
urlParams += '&page=' + currentPage; urlParams += '&page=' + currentPage;
for (var facetRefine in state.facetsRefinements) {
urlParams += '&' + encodeURIComponent(facetRefine) + '=' + encodeURIComponent(state.facetsRefinements[facetRefine]); //for (var facetRefine in state.facetsRefinements) {
} // urlParams += '&' + encodeURIComponent(facetRefine) + '=' + encodeURIComponent(state.facetsRefinements[facetRefine]);
for (var disjunctiveFacetrefine in state.disjunctiveFacetsRefinements) { //}
for (var value in state.disjunctiveFacetsRefinements[disjunctiveFacetrefine]) { //for (var disjunctiveFacetrefine in state.disjunctiveFacetsRefinements) {
urlParams += '&' + encodeURIComponent(disjunctiveFacetrefine) + '=' + encodeURIComponent(state.disjunctiveFacetsRefinements[disjunctiveFacetrefine][value]); // for (var value in state.disjunctiveFacetsRefinements[disjunctiveFacetrefine]) {
} // urlParams += '&' + encodeURIComponent(disjunctiveFacetrefine) + '=' + encodeURIComponent(state.disjunctiveFacetsRefinements[disjunctiveFacetrefine][value]);
} // }
//}
location.replace(urlParams); location.replace(urlParams);
} }

View File

@@ -3,15 +3,108 @@
* index and algolia settings are defined in layout.pug * index and algolia settings are defined in layout.pug
*/ */
var elasticSearcher = (function() {
var deze = {
query:"",
url:"",
newhits: [],
terms: {},
page: 0,
setQuery: (function(q, _url){
console.log('setQuery!: ' + q);
deze.query=q;
if (_url !== undefined) {
deze.url=_url;
}
}),
setCurrentPage: (function(page){
if(page === undefined){
return;
}
deze.page = page;
}),
//result callback
results: (function(content){}),
//error callback
error: (function(message){
console.log(message);
}),
on: (function(type, callback){
deze[type] = callback;
}),
//parse the agg stuff
aggs: (function(data){
return deze.newhits.aggregations;
}),
addTerm: (function(term, value){
deze.terms[term] = value;
}),
//get response from elastic and rebuild json
//so we can be a drop in of angolia
execute: (function(){
params = {
q: deze.query,
page: deze.page,
};
//add term filters
Object.assign(params, deze.terms);
var pstr = jQuery.param( params );
var jqxhr = $.getJSON("/api/newsearch" + deze.url + "?"+ pstr, function( data ) {
let hits = data.hits.hits;
var newhits = hits.map(function(hit){
return hit._source;
});
deze.newhits = newhits.slice(0);
//cb(newhits.slice(0));
deze.results({
'count': data.hits.total,
'hits': newhits.slice(0),
'took': data.took,
'page': deze.page,
'aggs': data.aggregations,
});
});
})
};
return {
execute: deze.execute,
on: deze.on,
setQuery: deze.setQuery,
setCurrentPage: deze.setCurrentPage,
query: deze.query,
page: deze.page,
addTerm: deze.addTerm,
};
})();
var elasticSearch = (function($, url) { var elasticSearch = (function($, url) {
console.log(url); console.log(url);
return function findMatches(q, cb, async){ return function findMatches(q, cb, async){
if (!cb) { return; } if (!cb) { return; }
$.fn.getSearch(q, cb, async, url); $.fn.getSearch(q, cb, async, url);
}; };
}); });
(function( $ ){ (function( $ ){
$.fn.getSearch = function(q, cb, async, url){ $.fn.getSearch = function(q, cb, async, url){
@@ -20,7 +113,9 @@ var elasticSearch = (function($, url) {
if(url === undefined){ if(url === undefined){
url = ''; url = '';
} }
console.log('searching! '+ url + q);
console.log('searching! '+ url + q);
$.getJSON("/api/newsearch" + url + "?q=" + q, function( data ) { $.getJSON("/api/newsearch" + url + "?q=" + q, function( data ) {
let hits = data.hits.hits; let hits = data.hits.hits;
newhits = hits.map(function(hit){ newhits = hits.map(function(hit){

View File

@@ -1,6 +1,6 @@
(function ( $ ) { (function ( $ ) {
// See organizations/view_embed.pug for example use. // See organizations/view_embed.pug for example use.
$.fn.userSearch = function(algolia_application_id, algolia_public_key, algolia_index_users, on_selected) { $.fn.userSearch = function(on_selected) {
var target = this; var target = this;
this.autocomplete({hint: false}, [ this.autocomplete({hint: false}, [

View File

@@ -203,9 +203,6 @@ h4 Organization members
script. script.
$(document).ready(function() { $(document).ready(function() {
$('#user-select').userSearch( $('#user-select').userSearch(
'{{config.ALGOLIA_USER}}',
'{{config.ALGOLIA_PUBLIC_KEY}}',
'{{config.ALGOLIA_INDEX_USERS}}',
function (event, hit, dataset) { function (event, hit, dataset) {
var $existing = $('li.sharing-users-item[data-user-id="' + hit.objectID + '"]'); var $existing = $('li.sharing-users-item[data-user-id="' + hit.objectID + '"]');
if ($existing.length) { if ($existing.length) {
@@ -224,9 +221,6 @@ script.
} }
); );
$('#admin-select').userSearch( $('#admin-select').userSearch(
'{{config.ALGOLIA_USER}}',
'{{config.ALGOLIA_PUBLIC_KEY}}',
'{{config.ALGOLIA_INDEX_USERS}}',
function (event, hit, dataset) { function (event, hit, dataset) {
setAdmin(hit.objectID, hit.full_name); setAdmin(hit.objectID, hit.full_name);
} }

View File

@@ -86,12 +86,7 @@ script.
addUser(hit.objectID); addUser(hit.objectID);
} }
$('#user-select').userSearch( $('#user-select').userSearch(shareWithUser);
'{{config.ALGOLIA_USER}}',
'{{config.ALGOLIA_PUBLIC_KEY}}',
'{{config.ALGOLIA_INDEX_USERS}}',
shareWithUser
);
}); });
function addUser(userId){ function addUser(userId){
if (!userId || userId.length == 0) { if (!userId || userId.length == 0) {