From 7edd9086e40e4ec520201f66bd33aac3952e9a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laura=20Kl=C3=BCnder?= Date: Sat, 28 Oct 2017 16:09:02 +0200 Subject: [PATCH] javascript autocomplete results matching --- src/c3nav/site/static/site/css/c3nav.css | 13 +++- src/c3nav/site/static/site/js/c3nav.js | 78 +++++++++++++++++++++++- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/src/c3nav/site/static/site/css/c3nav.css b/src/c3nav/site/static/site/css/c3nav.css index 61ec6be8..d7dda81f 100644 --- a/src/c3nav/site/static/site/css/c3nav.css +++ b/src/c3nav/site/static/site/css/c3nav.css @@ -49,11 +49,14 @@ main.map { position: absolute; z-index: 2; top: 0; - padding: 10px; + padding: 10px 10px 26px; width: 100%; bottom: 0; max-width: 420px; pointer-events: none; + display: flex; + flex-direction: column; + overflow: hidden; } #sidebar section { pointer-events: auto; @@ -82,9 +85,17 @@ main.map { #sidebar section > #route-buttons { border-color: transparent !important; } +#resultswrapper { + flex-grow: 1; +} +#resultswrapper section { + max-height: 100%; + overflow: auto; +} #search { margin-bottom: 10px; + flex-shrink: 0; } .location { diff --git a/src/c3nav/site/static/site/js/c3nav.js b/src/c3nav/site/static/site/js/c3nav.js index 9c5e24d3..92b9a3be 100644 --- a/src/c3nav/site/static/site/js/c3nav.js +++ b/src/c3nav/site/static/site/js/c3nav.js @@ -10,14 +10,88 @@ c3nav = { c3nav.init_typeahead(); c3nav.init_map(); }, + init_typeahead: function () { c3nav.typeahead_locations = []; $.getJSON('/api/locations/?searchable', function (data) { - c3nav.typeahead_locations = data; + for (var i = 0; i < data.length; i++) { + var location = data[i]; + location.elem = $('
').append($('').text(location.title)) + .append($('').text(location.subtitle)); + location.title_words = location.title.toLowerCase().split(/\s+/); + location.match = ' '+location.title_words.join(' ')+' '; + c3nav.typeahead_locations.push(location); + } }); + + $('.locationinput input').on('input', c3nav._typeahead_input); }, + _typeahead_matches_compare: function (a, b) { + if (a[1] !== b[1]) return b[1]-a[1]; + if (a[2] !== b[2]) return b[2]-a[2]; + if (a[3] !== b[3]) return b[3]-a[3]; + return a[4]-b[4]; + }, + _typeahead_input: function (e) { + var matches = [], + val = $(this).val(), + val_trimmed = $.trim(val), + val_words = val_trimmed.toLowerCase().split(/\s+/), + $autocomplete = $('#autocomplete'); + $(this).parent().removeClass('selected').toggleClass('empty', (val === '')); + + if (val_trimmed === '') { + $autocomplete.html(''); + return; + } + + for (var i = 0; i < c3nav.typeahead_locations.length; i++) { + var location = c3nav.typeahead_locations[i], + leading_words_count = 0, + words_total_count = 0, + words_start_count = 0, + nomatch = false, + val_word, j; + + // each word has to be in the location + for (j = 0; j < val_words.length; j++) { + val_word = val_words[j]; + if (location.match.indexOf(val_word) === -1) { + nomatch = true; + break; + } + } + if (nomatch) continue; + + // how many words from the beginning are in the title + for (j = 0; j < val_words.length; j++) { + val_word = val_words[0]; + if (location.title_words[j] !== val_word && + (j !== val_words.length-1 || location.title_words[j].indexOf(val_word) !== 0)) break; + leading_words_count++; + } + + // how many words in total can be found + for (j = 0; j < val_words.length; j++) { + val_word = val_words[0]; + if (location.match.indexOf(' '+val_word+' ') !== -1) { + words_total_count++; + } else if (location.match.indexOf(' '+val_word) !== -1) { + words_start_count++; + } + } + + matches.push([location.elem, leading_words_count, words_total_count, words_start_count, i]) + } + + matches.sort(c3nav._typeahead_matches_compare); + + for (i=0;i