diff --git a/core/modules/toolbar/css/toolbar.base.css b/core/modules/toolbar/css/toolbar.base.css index 33fb0d5..4f501a7 100644 --- a/core/modules/toolbar/css/toolbar.base.css +++ b/core/modules/toolbar/css/toolbar.base.css @@ -24,7 +24,7 @@ body.toolbar { text-align: left; /* LTR */ -webkit-text-size-adjust: none; -webkit-touch-callout: none; - -webkit-user-select: none; + /*-webkit-user-select: none;*/ vertical-align: baseline; } #toolbar { diff --git a/core/modules/toolbar/js/toolbar.js b/core/modules/toolbar/js/toolbar.js index 94afb90..1521c9d 100644 --- a/core/modules/toolbar/js/toolbar.js +++ b/core/modules/toolbar/js/toolbar.js @@ -17,6 +17,7 @@ Drupal.behaviors.toolbar = { var $bar = $toolbar.find('.toolbar-bar'); var $tray = $toolbar.find('.toolbar-tray'); var $trigger = $toolbar.find('.toggle-tray'); + var $toolbarFilter = $tray.find('.form-type-search'); // Instanstiate the bar. if ($bar.length) { ToolBar.bar = new ToolBar($bar); @@ -25,6 +26,9 @@ Drupal.behaviors.toolbar = { if ($tray.length && $trigger.length) { ToolBar.tray = new TraySlider($tray, $trigger); } + if ($toolbarFilter.length) { + toolbarFilter(); + } } } }; @@ -318,6 +322,128 @@ $.extend(TraySlider.prototype, { } }); +/** + * Apply the search bar functionality. + */ +function toolbarFilter() { + // Target toolbar + var $toolbar = $('#toolbar') + // @todo Add a HTML ID. + var $input = $('input.filter', $toolbar); + // Initialize the current search needle. + var needle = $input.val(); + // Cache of all links that can be matched in the menu. + var links; + // Minimum search needle length. + var needleMinLength = 2; + // Append the results container. + var $results = $('
').insertAfter($input); + + /** + * Executes the search upon user input. + */ + function keyupHandler() { + var matches, $html, value = $(this).val(); + // Only proceed if the search needle has changed. + if (value !== needle) { + needle = value; + // Initialize the cache of menu links upon first search. + if (!links && needle.length >= needleMinLength) { + // @todo Limit to links in dropdown menus; i.e., skip menu additions. + links = buildSearchIndex($toolbar.find('li a')); + } + // Empty results container when deleting search text. + if (needle.length < needleMinLength) { + $results.empty(); + } + // Only search if the needle is long enough. + if (needle.length >= needleMinLength && links) { + matches = findMatches(needle, links); + // Build the list in a detached DOM node. + $html = buildResultsList(matches); + // Display results. + $results.empty().append($html); + } + } + } + + /** + * Builds the search index. + */ + function buildSearchIndex($links) { + return $links + .map(function () { + var text = (this.textContent || this.innerText); + // Skip menu entries that do not contain any text (e.g., the icon). + if (typeof text === 'undefined') { + return; + } + return { + text: text, + textMatch: text.toLowerCase(), + element: this + }; + }); + } + + /** + * Searches the index for a given needle and returns matching entries. + */ + function findMatches(needle, links) { + var needleMatch = needle.toLowerCase(); + // Select matching links from the cache. + return $.grep(links, function (link) { + return link.textMatch.indexOf(needleMatch) !== -1; + }); + } + + /** + * Builds the search result list in a detached DOM node. + */ + function buildResultsList(matches) { + var $html = $('