Improve searching for a page
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Peter Stuifzand 2020-06-01 21:36:23 +02:00
parent bb439fcfe7
commit e1254ba3b4
2 changed files with 121 additions and 84 deletions

View File

@ -65,26 +65,100 @@ function addIndicator(editor, indicator) {
let holder = document.getElementById('editor'); let holder = document.getElementById('editor');
function showSearchResults(searchTool, query, input, value, resultType) { function showSearchResults(searchTool, query, input, value, resultType) {
showSearchResultsExtended('#link-complete', 'link-template', searchTool, query, input, value, resultType, {belowCursor: true})
}
function showSearchResultsExtended(element, template, searchTool, query, input, value, resultType, options) {
let results = searchTool(query) let results = searchTool(query)
if (results.length === 0) { let opt = options || {};
return
const $lc = $(element)
$lc.data('result-type', resultType)
if (opt.belowCursor) {
let pos = getCaretCoordinates(input, value.selectionEnd, {})
let off = $(input).offset()
pos.top += off.top + pos.height
pos.left += off.left
$lc.offset(pos)
} }
let pos = getCaretCoordinates(input, value.selectionEnd, {}) var templateText = document.getElementById(template).innerHTML;
let off = $(input).offset() var rendered = Mustache.render(templateText, {page: value, results: results}, {}, ['[[', ']]']);
pos.top += off.top + pos.height
pos.left += off.left
const $lc = $('#link-complete')
$lc.data('result-type', resultType)
$lc.offset(pos)
var template = document.getElementById('link-template').innerHTML;
var rendered = Mustache.render(template, {results: results}, {}, ['[[', ']]']);
$lc.html(rendered).fadeIn() $lc.html(rendered).fadeIn()
} }
$(document).on('keydown', '.keyboard-list', function (event) {
console.log('keydown .keyboard-list')
if (!$(':visible', this).length) {
return true
}
const $popup = $(this)
if (event.key === 'Escape') {
$popup.fadeOut()
return false
}
if (event.key === 'Enter') {
const element = $popup.find('li.selected')
const linkName = element.text()
$popup.trigger('popup:selected', [linkName, $popup.data('result-type'), element])
$popup.fadeOut()
return false
}
if (event.key === 'ArrowUp') {
const selected = $popup.find('li.selected')
const prev = selected.prev('li')
if (prev.length) {
prev.addClass('selected')
selected.removeClass('selected')
prev[0].scrollIntoView({block: 'center', inline: 'nearest'})
} else {
// move back from dropdown to input
$popup.trigger('popup:leave')
selected.removeClass('selected')
}
return false
}
if (event.key === 'ArrowDown') {
const selected = $popup.find('li.selected')
const next = selected.next('li');
if (next.length) {
next.addClass('selected')
selected.removeClass('selected')
next[0].scrollIntoView({block: 'center', inline: 'nearest'})
}
return false
}
return true
})
$(document).on('keydown', '#search-input', function (event) {
console.log('keydown #search-input')
let $ac = $('#autocomplete');
let isVisible = $(':visible', $ac)
if (event.key === 'ArrowDown' && isVisible) {
$ac.focus()
$ac.find('li:first-child').addClass('selected')
return false
}
if (event.key === 'Escape') {
$(searchInput).val('');
$ac.fadeOut();
return false;
}
return true
})
$(document).on('popup:selected', '#autocomplete', function (event, linkName, resultType, element) {
if (resultType === 'search-result') {
element.find('a')[0].click()
return false;
}
})
if (holder) { if (holder) {
let editor = listEditor(holder, JSON.parse(holder.dataset.input)); let editor = listEditor(holder, JSON.parse(holder.dataset.input));
@ -101,57 +175,10 @@ if (holder) {
).save() ).save()
}) })
$(document).on('keydown', '#link-complete', function (event) {
if (!$('#link-complete:visible')) {
return true;
}
const $popup = $('#link-complete')
if (event.key === 'Escape') {
$popup.fadeOut()
return false
}
if (event.key === 'Enter') {
const linkName = $popup.find('li.selected').text()
$popup.trigger('popup:selected', [linkName, $popup.data('result-type')])
$popup.fadeOut()
return false
}
if (event.key === 'ArrowUp') {
const selected = $popup.find('li.selected')
const prev = selected.prev('li')
if (prev.length) {
prev.addClass('selected')
selected.removeClass('selected')
prev[0].scrollIntoView()
} else {
// move back from dropdown to input
$popup.trigger('popup:leave')
selected.removeClass('selected')
}
return false
}
if (event.key === 'ArrowDown') {
const selected = $popup.find('li.selected')
const next = selected.next('li');
if (next.length) {
next.addClass('selected')
selected.removeClass('selected')
next[0].scrollIntoView()
}
return false
}
return true
})
createPageSearch().then(function ({titleSearch, commandSearch, commands}) { createPageSearch().then(function ({titleSearch, commandSearch, commands}) {
editor.on('start-editing', function (input) { editor.on('start-editing', function (input) {
const $lc = $('#link-complete') const $lc = $('#link-complete');
$lc.on('popup:selected', function (event, linkName, resultType, element) {
$lc.on('popup:selected', function (event, linkName, resultType) {
let value = input.value let value = input.value
let end = input.selectionEnd let end = input.selectionEnd
if (resultType === 'link') { if (resultType === 'link') {
@ -216,7 +243,6 @@ if (holder) {
$(input).on('keydown', function (event) { $(input).on('keydown', function (event) {
const isVisible = $('#link-complete:visible').length > 0; const isVisible = $('#link-complete:visible').length > 0;
const $lc = $('#link-complete')
if (event.key === 'Escape' && isVisible) { if (event.key === 'Escape' && isVisible) {
$lc.fadeOut() $lc.fadeOut()
return false return false
@ -227,6 +253,7 @@ if (holder) {
$lc.find('li:first-child').addClass('selected') $lc.find('li:first-child').addClass('selected')
return false return false
} }
return true return true
}) })
@ -268,7 +295,6 @@ if (holder) {
$('#link-complete').off() $('#link-complete').off()
}) })
}) })
$.contextMenu({ $.contextMenu({
selector: '.marker', selector: '.marker',
items: { items: {
@ -287,29 +313,29 @@ if (holder) {
let timeout = null; let timeout = null;
let searchInput = document.getElementById('search-input'); let searchInput = document.getElementById('search-input');
search(searchInput).then(searcher => { search(searchInput).then(searcher => {
searchInput.addEventListener('keyup', function (e) {
clearTimeout(timeout);
if (e.key === 'Escape') { $(document).on('keyup', '#search-input', function (event) {
$(searchInput).val(''); clearTimeout(timeout);
$('#autocomplete').hide();
return;
}
timeout = setTimeout(function () { timeout = setTimeout(function () {
let query = $(searchInput).val() let query = $(searchInput).val()
if (query === '') { if (query === '') {
let autocomplete = document.getElementById('autocomplete'); let autocomplete = document.getElementById('autocomplete');
$(autocomplete).hide() $(autocomplete).hide()
return return false
} }
$('#autocomplete').show()
let result = searcher.search(query) showSearchResultsExtended('#autocomplete', 'result-template', query => searcher.search(query), query, searchInput, query, 'search-result')
const newpage = query.replace(/\s+/g, '_')
var template = document.getElementById('result-template').innerHTML; // $('#autocomplete').show()
var rendered = Mustache.render(template, {page: newpage, results: result}, {}, ['[[', ']]']); // let result = searcher.search(query)
let autocomplete = document.getElementById('autocomplete'); // const newpage = query.replace(/\s+/g, '_')
autocomplete.innerHTML = rendered; // var template = document.getElementById('result-template').innerHTML;
}, 500) // var rendered = Mustache.render(template, {page: newpage, results: result}, {}, ['[[', ']]']);
// let autocomplete = document.getElementById('autocomplete');
// autocomplete.innerHTML = rendered;
}, 200)
return true
}) })
}) })

View File

@ -20,11 +20,16 @@
position: absolute; position: absolute;
background: white; background: white;
border: 1px solid #ccc; border: 1px solid #ccc;
padding: 16px;
} }
#autocomplete li > a { #autocomplete li > a {
white-space: nowrap; white-space: nowrap;
} }
#autocomplete li {
padding: 4px 16px;
}
#autocomplete li.selected {
background: lightblue;
}
#link-complete { #link-complete {
z-index: 1; z-index: 1;
width: 217px; width: 217px;
@ -259,7 +264,7 @@
<p class="control"> <p class="control">
<input class="search input" id="search-input" type="text" placeholder="Find a page"> <input class="search input" id="search-input" type="text" placeholder="Find a page">
</p> </p>
<div id="autocomplete" class="hidden"></div> <div id="autocomplete" class="hide keyboard-list" tabindex="0"></div>
</div> </div>
</div> </div>
</div> </div>
@ -276,7 +281,7 @@
<div id="save-indicator" class="hide"></div> <div id="save-indicator" class="hide"></div>
</div> </div>
<div id="link-complete" class="hide" tabindex="0"></div> <div id="link-complete" class="hide keyboard-list" tabindex="0"></div>
{{ block "footer_scripts" . }} {{ block "footer_scripts" . }}
{{ end }} {{ end }}
<script src="/public/index.bundle.js"></script> <script src="/public/index.bundle.js"></script>
@ -285,7 +290,10 @@
[[#results]] [[#results]]
<li><a href="/[[ref]]">[[title]]</a></li> <li><a href="/[[ref]]">[[title]]</a></li>
[[/results]] [[/results]]
<ll><a href="/edit/[[page]]">Create a page</a></ll> [[^results]]
<li>No results</li>
[[/results]]
<li><a href="/edit/[[page]]">Create a page</a></li>
</ul> </ul>
</div> </div>
<div id="link-template" class="hide"> <div id="link-template" class="hide">
@ -293,6 +301,9 @@
[[#results]] [[#results]]
<li>[[item.title]]</li> <li>[[item.title]]</li>
[[/results]] [[/results]]
[[^results]]
<li>No results</li>
[[/results]]
</ul> </ul>
</div> </div>
</body> </body>