Commit b9f402c5 authored by manuk's avatar manuk Committed by Commit Bot

[chrome:omnibox] Add input box and a filter/highlight toggle to search results.

When the filter option is selected, matches (rows) which do not match the search query are hidden; when the highlight option is selected, matches which do match the search query are highlighted (light blue).

Bug: 891303
Change-Id: I4c34dae1a1cef2c7baeffdd6de0355ef7ea53f0a
Reviewed-on: https://chromium-review.googlesource.com/c/1340904Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: default avatarTommy Li <tommycli@chromium.org>
Commit-Queue: manuk hovanesian <manukh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610969}
parent dcdb2ecc
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
background-color: #C0C0C0; background-color: #C0C0C0;
} }
.autocomplete-results-table td { .autocomplete-results-table tr {
background-color: #F0F0F0; background-color: #F0F0F0;
} }
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
text-decoration: underline; text-decoration: underline;
} }
.left-20 {
margin-left: 20px
}
.check-mark, .check-mark,
.x-mark { .x-mark {
background-position: center; background-position: center;
...@@ -53,3 +57,32 @@ p { ...@@ -53,3 +57,32 @@ p {
.additional-info-value { .additional-info-value {
white-space: nowrap; white-space: nowrap;
} }
.filtered-hidden {
display: none;
}
.autocomplete-results-table .filtered-highlighted {
background-color: lightskyblue;
/* TODO(manukh) This is a placholder color until other ui changes occur. */
}
.toggle input,
.toggle input:not(:checked) ~ .toggle-on,
.toggle input:checked ~ .toggle-off {
display: none;
}
.toggle span {
user-select: none;
display: inline-block;
padding: 3px 5px;
min-width: 60px;
text-align: center;
cursor: pointer;
border: 1px solid;
}
.toggle span:hover {
background-color: #f0f0f0;
}
...@@ -72,8 +72,18 @@ ...@@ -72,8 +72,18 @@
Show results per provider, not just merged results Show results per provider, not just merged results
</label> </label>
</p> </p>
<button id="copy-text" title="Copy visible table in text format. This is affected by the visibility of ouput; i.e. toggling `Show all details` affects what will be copied.">Copy as text</button> <div class="section">
<button id="copy-json" title="Copy responses in JSON format. This is not affected by the visibility of output and will copy responses in their entirety.">Copy as JSON</button> <button id="copy-text" title="Copy visible table in text format. This is affected by the visibility of ouput; i.e. toggling `Show all details` affects what will be copied.">Copy as text</button>
<button id="copy-json" title="Copy responses in JSON format. This is not affected by the visibility of output and will copy responses in their entirety.">Copy as JSON</button>
</div>
<div class="section">
<input id="filter-text" type="text" size="60" placeholder="Filter output">
<label class="toggle left-20">
<input id="filter-hide" type="checkbox">
<span class="toggle-off">Highlight</span>
<span class="toggle-on">Filter</span>
</label>
</div>
</template> </template>
<template id="omnibox-output-template"> <template id="omnibox-output-template">
...@@ -107,7 +117,11 @@ ...@@ -107,7 +117,11 @@
</table> </table>
</template> </template>
<omnibox-inputs id="omnibox-inputs" class="section"></omnibox-inputs> <div class="section">
<omnibox-output id="omnibox-output" class="section"></omnibox-output> <omnibox-inputs id="omnibox-inputs"></omnibox-inputs>
</div>
<div class="section">
<omnibox-output id="omnibox-output"></omnibox-output>
</div>
</body> </body>
</html> </html>
...@@ -65,11 +65,11 @@ ...@@ -65,11 +65,11 @@
} }
} }
/** @type {BrowserProxy} */ /** @type {!BrowserProxy} */
const browserProxy = new BrowserProxy(); const browserProxy = new BrowserProxy();
/** @type {OmniboxInputs} */ /** @type {!OmniboxInputs} */
let omniboxInputs; let omniboxInputs;
/** @type {omnibox_output.OmniboxOutput} */ /** @type {!omnibox_output.OmniboxOutput} */
let omniboxOutput; let omniboxOutput;
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
...@@ -95,5 +95,9 @@ ...@@ -95,5 +95,9 @@
event => event.detail === 'text' ? event => event.detail === 'text' ?
omniboxOutput.copyDelegate.copyTextOutput() : omniboxOutput.copyDelegate.copyTextOutput() :
omniboxOutput.copyDelegate.copyJsonOutput()); omniboxOutput.copyDelegate.copyJsonOutput());
omniboxInputs.addEventListener(
'filter-input-changed',
event => omniboxOutput.filterDelegate.filter(
event.detail.filterText, event.detail.filterHide));
}); });
})(); })();
...@@ -14,22 +14,41 @@ class OmniboxElement extends HTMLElement { ...@@ -14,22 +14,41 @@ class OmniboxElement extends HTMLElement {
this.attachShadow({mode: 'open'}); this.attachShadow({mode: 'open'});
const template = OmniboxElement.getTemplate(templateId); const template = OmniboxElement.getTemplate(templateId);
this.shadowRoot.appendChild(template); this.shadowRoot.appendChild(template);
/** @type {!ShadowRoot} */
this.shadowRoot;
} }
/** /**
* Searches local shadow root for element by id * Get an element that's known to exist within this OmniboxElement.
* Searches local shadow root for element by id.
* @param {string} id * @param {string} id
* @return {Element} * @return {!Element}
*/ */
$$(id) { $$(id) {
return this.shadowRoot.getElementById(id); return OmniboxElement.getById_(id, (this.shadowRoot));
} }
/** /**
* Get a template that's known to exist within the DOM document.
* @param {string} templateId * @param {string} templateId
* @return {Element} * @return {!Element}
*/ */
static getTemplate(templateId) { static getTemplate(templateId) {
return $(templateId).content.cloneNode(true); return OmniboxElement.getById_(templateId).content.cloneNode(true);
}
/**
* Get an element that's known to exist by its ID. We use this instead of just
* calling getElementById because this lets us satisfy the JSCompiler type
* system.
* @private
* @param {string} id
* @param {!Node=} context
* @return {!Element}
*/
static getById_(id, context) {
return assertInstanceof(
(context || document).getElementById(id), Element,
`Missing required element: ${id}`);
} }
} }
...@@ -41,6 +41,7 @@ class OmniboxInputs extends OmniboxElement { ...@@ -41,6 +41,7 @@ class OmniboxInputs extends OmniboxElement {
setupElementListeners_() { setupElementListeners_() {
const onQueryInputsChanged = this.onQueryInputsChanged_.bind(this); const onQueryInputsChanged = this.onQueryInputsChanged_.bind(this);
const onDisplayInputsChanged = this.onDisplayInputsChanged_.bind(this); const onDisplayInputsChanged = this.onDisplayInputsChanged_.bind(this);
const onFilterInputsChange = this.onFilterInputChange_.bind(this);
this.$$('input-text').addEventListener('input', onQueryInputsChanged); this.$$('input-text').addEventListener('input', onQueryInputsChanged);
this.$$('lock-cursor-position') this.$$('lock-cursor-position')
...@@ -59,11 +60,16 @@ class OmniboxInputs extends OmniboxElement { ...@@ -59,11 +60,16 @@ class OmniboxInputs extends OmniboxElement {
.addEventListener('click', () => this.onCopyOutput_('text')); .addEventListener('click', () => this.onCopyOutput_('text'));
this.$$('copy-json') this.$$('copy-json')
.addEventListener('click', () => this.onCopyOutput_('json')); .addEventListener('click', () => this.onCopyOutput_('json'));
this.$$('filter-text').addEventListener('input', onFilterInputsChange);
this.$$('filter-hide').addEventListener('change', onFilterInputsChange);
} }
// TODO (manukh) rename below on*InputsChanged methods to on*Changed to reduce
// verbosity.
/** @private */ /** @private */
onQueryInputsChanged_() { onQueryInputsChanged_() {
/** @type {QueryInputs} */ /** @type {!QueryInputs} */
const queryInputs = { const queryInputs = {
inputText: this.$$('input-text').value, inputText: this.$$('input-text').value,
cursorPosition: this.cursorPosition_, cursorPosition: this.cursorPosition_,
...@@ -77,7 +83,7 @@ class OmniboxInputs extends OmniboxElement { ...@@ -77,7 +83,7 @@ class OmniboxInputs extends OmniboxElement {
/** @private */ /** @private */
onDisplayInputsChanged_() { onDisplayInputsChanged_() {
/** @type {DisplayInputs} */ /** @type {!DisplayInputs} */
const displayInputs = { const displayInputs = {
showIncompleteResults: this.$$('show-incomplete-results').checked, showIncompleteResults: this.$$('show-incomplete-results').checked,
showDetails: this.$$('show-details').checked, showDetails: this.$$('show-details').checked,
...@@ -104,6 +110,16 @@ class OmniboxInputs extends OmniboxElement { ...@@ -104,6 +110,16 @@ class OmniboxInputs extends OmniboxElement {
onCopyOutput_(format) { onCopyOutput_(format) {
this.dispatchEvent(new CustomEvent('copy-request', {detail: format})); this.dispatchEvent(new CustomEvent('copy-request', {detail: format}));
} }
/** @private */
onFilterInputChange_() {
this.dispatchEvent(new CustomEvent('filter-input-changed', {
detail: {
filterText: this.$$('filter-text').value,
filterHide: this.$$('filter-hide').checked,
}
}));
}
} }
window.customElements.define(OmniboxInputs.is, OmniboxInputs); window.customElements.define(OmniboxInputs.is, OmniboxInputs);
...@@ -112,3 +112,15 @@ Clipboard.prototype.writeText = function(text) {}; ...@@ -112,3 +112,15 @@ Clipboard.prototype.writeText = function(text) {};
/** @const {!Clipboard} */ /** @const {!Clipboard} */
Navigator.prototype.clipboard; Navigator.prototype.clipboard;
/**
* TODO(manukh): remove this once it is added to Closure Compiler itself.
* @see https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap
* @param {?function(this:S, T, number, !Array<T>): R} callback
* @param {S=} opt_this
* @return {!Array<R>}
* @this {IArrayLike<T>|string}
* @template T,S,R
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
*/
Array.prototype.flatMap = function(callback, opt_this) {};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment