Search: Fix scroll-to-top on escape (unmark). Rearrange javascript and add comments
This commit is contained in:
parent
66ae6b6e92
commit
fa88440e7e
|
@ -2,8 +2,8 @@ $( document ).ready(function() {
|
||||||
|
|
||||||
// Search functionality
|
// Search functionality
|
||||||
//
|
//
|
||||||
// Usage: call init() on startup. You can use hasFocus() to disable prevent keyhandling
|
// Usage: call init() on startup. You can use !hasFocus() to prevent keyhandling in your key
|
||||||
// while the user is typing his search.
|
// event handlers while the user is typing his search.
|
||||||
var search = {
|
var search = {
|
||||||
searchbar : $('#searchbar'),
|
searchbar : $('#searchbar'),
|
||||||
searchbar_outer : $('#searchbar-outer'),
|
searchbar_outer : $('#searchbar-outer'),
|
||||||
|
@ -25,10 +25,10 @@ $( document ).ready(function() {
|
||||||
breadcrumbs: {boost: 0}
|
breadcrumbs: {boost: 0}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mark_exclude : [], // ['.hljs']
|
mark_exclude : [],
|
||||||
current_searchterm : "",
|
current_searchterm : "",
|
||||||
SEARCH_PARAM : 'search',
|
URL_SEARCH_PARAM : 'search',
|
||||||
MARK_PARAM : 'highlight',
|
URL_MARK_PARAM : 'highlight',
|
||||||
|
|
||||||
SEARCH_HOTKEY_KEYCODE: 83,
|
SEARCH_HOTKEY_KEYCODE: 83,
|
||||||
ESCAPE_KEYCODE: 27,
|
ESCAPE_KEYCODE: 27,
|
||||||
|
@ -36,16 +36,8 @@ $( document ).ready(function() {
|
||||||
UP_KEYCODE: 38,
|
UP_KEYCODE: 38,
|
||||||
SELECT_KEYCODE: 13,
|
SELECT_KEYCODE: 13,
|
||||||
|
|
||||||
formatSearchMetric : function(count, searchterm) {
|
|
||||||
if (count == 1) {
|
// Helper to parse a url into its building blocks.
|
||||||
return count + " search result for '" + searchterm + "':";
|
|
||||||
} else if (count == 0) {
|
|
||||||
return "No search results for '" + searchterm + "'.";
|
|
||||||
} else {
|
|
||||||
return count + " search results for '" + searchterm + "':";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
parseURL : function (url) {
|
parseURL : function (url) {
|
||||||
var a = document.createElement('a');
|
var a = document.createElement('a');
|
||||||
a.href = url;
|
a.href = url;
|
||||||
|
@ -71,6 +63,7 @@ $( document ).ready(function() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
// Helper to recreate a url string from its building blocks.
|
||||||
renderURL : function (urlobject) {
|
renderURL : function (urlobject) {
|
||||||
var url = urlobject.protocol + "://" + urlobject.host;
|
var url = urlobject.protocol + "://" + urlobject.host;
|
||||||
if (urlobject.port != "") {
|
if (urlobject.port != "") {
|
||||||
|
@ -90,6 +83,7 @@ $( document ).ready(function() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
// Helper to escape html special chars for displaying the teasers
|
||||||
escapeHTML: (function() {
|
escapeHTML: (function() {
|
||||||
var MAP = {
|
var MAP = {
|
||||||
'&': '&',
|
'&': '&',
|
||||||
|
@ -104,18 +98,27 @@ $( document ).ready(function() {
|
||||||
};
|
};
|
||||||
})()
|
})()
|
||||||
,
|
,
|
||||||
|
formatSearchMetric : function(count, searchterm) {
|
||||||
|
if (count == 1) {
|
||||||
|
return count + " search result for '" + searchterm + "':";
|
||||||
|
} else if (count == 0) {
|
||||||
|
return "No search results for '" + searchterm + "'.";
|
||||||
|
} else {
|
||||||
|
return count + " search results for '" + searchterm + "':";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
formatSearchResult : function (result, searchterms) {
|
formatSearchResult : function (result, searchterms) {
|
||||||
// Show text around first occurrence of first search term.
|
|
||||||
var teaser = this.makeTeaser(this.escapeHTML(result.doc.body), searchterms);
|
var teaser = this.makeTeaser(this.escapeHTML(result.doc.body), searchterms);
|
||||||
|
|
||||||
// The ?MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
|
// The ?URL_MARK_PARAM= parameter belongs inbetween the page and the #heading-anchor
|
||||||
var url = result.ref.split("#");
|
var url = result.ref.split("#");
|
||||||
if (url.length == 1) {
|
if (url.length == 1) { // no anchor found
|
||||||
url.push("");
|
url.push("");
|
||||||
}
|
}
|
||||||
|
|
||||||
return $('<li><a href="'
|
return $('<li><a href="'
|
||||||
+ url[0] + '?' + this.MARK_PARAM + '=' + searchterms + '#' + url[1]
|
+ url[0] + '?' + this.URL_MARK_PARAM + '=' + searchterms + '#' + url[1]
|
||||||
+ '">' + result.doc.breadcrumbs + '</a>' // doc.title
|
+ '">' + result.doc.breadcrumbs + '</a>' // doc.title
|
||||||
+ '<span class="breadcrumbs">' + '</span>'
|
+ '<span class="breadcrumbs">' + '</span>'
|
||||||
+ '<span class="teaser">' + teaser + '</span>'
|
+ '<span class="teaser">' + teaser + '</span>'
|
||||||
|
@ -216,55 +219,6 @@ $( document ).ready(function() {
|
||||||
return teaser_split.join('');
|
return teaser_split.join('');
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
doSearch : function (searchterm) {
|
|
||||||
|
|
||||||
// Don't search the same twice
|
|
||||||
if (this.current_searchterm == searchterm) { return; }
|
|
||||||
else { this.current_searchterm = searchterm; }
|
|
||||||
|
|
||||||
if (this.searchindex == null) { return; }
|
|
||||||
|
|
||||||
// Do the actual search
|
|
||||||
var results = this.searchindex.search(searchterm, this.searchoptions);
|
|
||||||
var resultcount = Math.min(results.length, this.searchoptions.limit_results);
|
|
||||||
|
|
||||||
// Display search metrics
|
|
||||||
this.searchresults_header.text(this.formatSearchMetric(resultcount, searchterm));
|
|
||||||
|
|
||||||
// Clear and insert results
|
|
||||||
var searchterms = searchterm.split(' ');
|
|
||||||
this.searchresults.empty();
|
|
||||||
for(var i = 0; i < resultcount ; i++){
|
|
||||||
this.searchresults.append(this.formatSearchResult(results[i], searchterms));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Display and scroll to results
|
|
||||||
this.searchresults_outer.slideDown();
|
|
||||||
// this.searchicon.scrollTop(0);
|
|
||||||
}
|
|
||||||
,
|
|
||||||
doSearchOrMarkFromUrl : function () {
|
|
||||||
// Check current URL for search request
|
|
||||||
var url = this.parseURL(window.location.href);
|
|
||||||
if (url.params.hasOwnProperty(this.SEARCH_PARAM)
|
|
||||||
&& url.params[this.SEARCH_PARAM] != "") {
|
|
||||||
this.searchbar_outer.slideDown();
|
|
||||||
this.searchbar[0].value = decodeURIComponent(
|
|
||||||
(url.params[this.SEARCH_PARAM]+'').replace(/\+/g, '%20'));
|
|
||||||
this.searchbarKeyUpHandler();
|
|
||||||
} else {
|
|
||||||
this.searchbar_outer.slideUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (url.params.hasOwnProperty(this.MARK_PARAM)) {
|
|
||||||
var words = url.params[this.MARK_PARAM].split(' ');
|
|
||||||
var header = $('#' + url.hash);
|
|
||||||
this.content.mark(words, {
|
|
||||||
exclude : this.mark_exclude
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,
|
|
||||||
init : function () {
|
init : function () {
|
||||||
var this_ = this;
|
var this_ = this;
|
||||||
|
|
||||||
|
@ -296,6 +250,38 @@ $( document ).ready(function() {
|
||||||
return this.searchbar.is(':focus');
|
return this.searchbar.is(':focus');
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
unfocusSearchbar : function () {
|
||||||
|
// hacky, but just focusing a div only works once
|
||||||
|
var tmp = $('<input style="position: absolute; opacity: 0;">');
|
||||||
|
tmp.insertAfter(this.searchicon);
|
||||||
|
tmp.focus();
|
||||||
|
tmp.remove();
|
||||||
|
}
|
||||||
|
,
|
||||||
|
// On reload or browser history backwards/forwards events, parse the url and do search or mark
|
||||||
|
doSearchOrMarkFromUrl : function () {
|
||||||
|
// Check current URL for search request
|
||||||
|
var url = this.parseURL(window.location.href);
|
||||||
|
if (url.params.hasOwnProperty(this.URL_SEARCH_PARAM)
|
||||||
|
&& url.params[this.URL_SEARCH_PARAM] != "") {
|
||||||
|
this.searchbar_outer.slideDown();
|
||||||
|
this.searchbar[0].value = decodeURIComponent(
|
||||||
|
(url.params[this.URL_SEARCH_PARAM]+'').replace(/\+/g, '%20'));
|
||||||
|
this.searchbarKeyUpHandler(); // -> doSearch()
|
||||||
|
} else {
|
||||||
|
this.searchbar_outer.slideUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.params.hasOwnProperty(this.URL_MARK_PARAM)) {
|
||||||
|
var words = url.params[this.URL_MARK_PARAM].split(' ');
|
||||||
|
var header = $('#' + url.hash);
|
||||||
|
this.content.mark(words, {
|
||||||
|
exclude : this.mark_exclude
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
|
// Eventhandler for keyevents on `document`
|
||||||
globalKeyHandler : function (e) {
|
globalKeyHandler : function (e) {
|
||||||
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
|
if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) { return; }
|
||||||
|
|
||||||
|
@ -304,8 +290,10 @@ $( document ).ready(function() {
|
||||||
this.searchbar.removeClass("active");
|
this.searchbar.removeClass("active");
|
||||||
// this.searchbar[0].value = "";
|
// this.searchbar[0].value = "";
|
||||||
this.setSearchUrlParameters("",
|
this.setSearchUrlParameters("",
|
||||||
(this.searchbar[0].value.trim() != 0) ? "push" : "replace");
|
(this.searchbar[0].value.trim() != "") ? "push" : "replace");
|
||||||
|
if (this.hasFocus()) {
|
||||||
this.unfocusSearchbar();
|
this.unfocusSearchbar();
|
||||||
|
}
|
||||||
this.searchbar_outer.slideUp();
|
this.searchbar_outer.slideUp();
|
||||||
this.content.unmark();
|
this.content.unmark();
|
||||||
return;
|
return;
|
||||||
|
@ -349,21 +337,13 @@ $( document ).ready(function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
unfocusSearchbar : function () {
|
// Eventhandler for search icon
|
||||||
// hacky, but just focusing a div only works once
|
|
||||||
var tmp = $('<input style="position: absolute; opacity: 0;">');
|
|
||||||
tmp.insertAfter(this.searchicon);
|
|
||||||
tmp.focus();
|
|
||||||
tmp.remove();
|
|
||||||
}
|
|
||||||
,
|
|
||||||
searchIconClickHandler : function () {
|
searchIconClickHandler : function () {
|
||||||
this.searchbar_outer.slideToggle();
|
this.searchbar_outer.slideToggle();
|
||||||
this.searchbar.focus();
|
this.searchbar.focus();
|
||||||
// TODO:
|
|
||||||
// If invisible, clear URL search parameter
|
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
// Eventhandler for keyevents while the searchbar is focused
|
||||||
searchbarKeyUpHandler : function () {
|
searchbarKeyUpHandler : function () {
|
||||||
var searchterm = this.searchbar[0].value.trim();
|
var searchterm = this.searchbar[0].value.trim();
|
||||||
if (searchterm != "") {
|
if (searchterm != "") {
|
||||||
|
@ -375,32 +355,61 @@ $( document ).ready(function() {
|
||||||
this.searchresults.empty();
|
this.searchresults.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setSearchUrlParameters(searchterm, "if_begin_search");
|
this.setSearchUrlParameters(searchterm, "push_if_new_search_else_replace");
|
||||||
|
|
||||||
// Remove marks
|
// Remove marks
|
||||||
this.content.unmark();
|
this.content.unmark();
|
||||||
}
|
}
|
||||||
,
|
,
|
||||||
|
// Update current url with ?URL_SEARCH_PARAM= parameter, remove ?URL_MARK_PARAM and #heading-anchor .
|
||||||
|
// `action` can be one of "push", "replace", "push_if_new_search_else_replace"
|
||||||
|
// and replaces or pushes a new browser history item.
|
||||||
|
// "push_if_new_search_else_replace" pushes if there is no `?URL_SEARCH_PARAM=abc` yet.
|
||||||
setSearchUrlParameters : function(searchterm, action) {
|
setSearchUrlParameters : function(searchterm, action) {
|
||||||
// Update url with ?SEARCH_PARAM= parameter, remove ?MARK_PARAM and #heading-anchor
|
|
||||||
var url = this.parseURL(window.location.href);
|
var url = this.parseURL(window.location.href);
|
||||||
var first_search = ! url.params.hasOwnProperty(this.SEARCH_PARAM);
|
var first_search = ! url.params.hasOwnProperty(this.URL_SEARCH_PARAM);
|
||||||
if (searchterm != "" || action == "if_begin_search") {
|
if (searchterm != "" || action == "push_if_new_search_else_replace") {
|
||||||
url.params[this.SEARCH_PARAM] = searchterm;
|
url.params[this.URL_SEARCH_PARAM] = searchterm;
|
||||||
delete url.params[this.MARK_PARAM];
|
delete url.params[this.URL_MARK_PARAM];
|
||||||
url.hash = "";
|
url.hash = "";
|
||||||
} else {
|
} else {
|
||||||
delete url.params[this.SEARCH_PARAM];
|
delete url.params[this.URL_SEARCH_PARAM];
|
||||||
}
|
}
|
||||||
// A new search will also add a new history item, so the user can go back
|
// A new search will also add a new history item, so the user can go back
|
||||||
// to the page prior to searching. A updated search term will only replace
|
// to the page prior to searching. A updated search term will only replace
|
||||||
// the url.
|
// the url.
|
||||||
if (action == "push" || (action == "if_begin_search" && first_search) ) {
|
if (action == "push" || (action == "push_if_new_search_else_replace" && first_search) ) {
|
||||||
history.pushState({}, document.title, this.renderURL(url));
|
history.pushState({}, document.title, this.renderURL(url));
|
||||||
} else if (action == "replace" || (action == "if_begin_search" && !first_search) ) {
|
} else if (action == "replace" || (action == "push_if_new_search_else_replace" && !first_search) ) {
|
||||||
history.replaceState({}, document.title, this.renderURL(url));
|
history.replaceState({}, document.title, this.renderURL(url));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
,
|
||||||
|
doSearch : function (searchterm) {
|
||||||
|
|
||||||
|
// Don't search the same twice
|
||||||
|
if (this.current_searchterm == searchterm) { return; }
|
||||||
|
else { this.current_searchterm = searchterm; }
|
||||||
|
|
||||||
|
if (this.searchindex == null) { return; }
|
||||||
|
|
||||||
|
// Do the actual search
|
||||||
|
var results = this.searchindex.search(searchterm, this.searchoptions);
|
||||||
|
var resultcount = Math.min(results.length, this.searchoptions.limit_results);
|
||||||
|
|
||||||
|
// Display search metrics
|
||||||
|
this.searchresults_header.text(this.formatSearchMetric(resultcount, searchterm));
|
||||||
|
|
||||||
|
// Clear and insert results
|
||||||
|
var searchterms = searchterm.split(' ');
|
||||||
|
this.searchresults.empty();
|
||||||
|
for(var i = 0; i < resultcount ; i++){
|
||||||
|
this.searchresults.append(this.formatSearchResult(results[i], searchterms));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display and scroll to results
|
||||||
|
this.searchresults_outer.slideDown();
|
||||||
|
// this.searchicon.scrollTop(0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue