forked from mirrors/gecko-dev
Differential Revision: https://phabricator.services.mozilla.com/D59691 --HG-- extra : moz-landing-system : lando
243 lines
6.5 KiB
JavaScript
243 lines
6.5 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
// This is loaded into all XUL windows. Wrap in a block to prevent
|
|
// leaking to window scope.
|
|
{
|
|
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
|
|
class MozSearchTextbox extends MozXULElement {
|
|
constructor() {
|
|
super();
|
|
|
|
this.inputField = document.createElementNS(HTML_NS, "input");
|
|
|
|
const METHODS = [
|
|
"focus",
|
|
"blur",
|
|
"select",
|
|
"setUserInput",
|
|
"setSelectionRange",
|
|
];
|
|
for (const method of METHODS) {
|
|
this[method] = (...args) => this.inputField[method](...args);
|
|
}
|
|
|
|
const READ_WRITE_PROPERTIES = [
|
|
"defaultValue",
|
|
"placeholder",
|
|
"readOnly",
|
|
"size",
|
|
"selectionStart",
|
|
"selectionEnd",
|
|
];
|
|
for (const property of READ_WRITE_PROPERTIES) {
|
|
Object.defineProperty(this, property, {
|
|
enumerable: true,
|
|
get() {
|
|
return this.inputField[property];
|
|
},
|
|
set(val) {
|
|
return (this.inputField[property] = val);
|
|
},
|
|
});
|
|
}
|
|
|
|
this.addEventListener("input", event => {
|
|
if (this.searchButton) {
|
|
this._searchIcons.selectedIndex = 0;
|
|
return;
|
|
}
|
|
if (this._timer) {
|
|
clearTimeout(this._timer);
|
|
}
|
|
this._timer =
|
|
this.timeout && setTimeout(this._fireCommand, this.timeout, this);
|
|
this._searchIcons.selectedIndex = this.value ? 1 : 0;
|
|
});
|
|
|
|
this.addEventListener("keypress", event => {
|
|
switch (event.keyCode) {
|
|
case KeyEvent.DOM_VK_ESCAPE:
|
|
if (this._clearSearch()) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
break;
|
|
case KeyEvent.DOM_VK_RETURN:
|
|
this._enterSearch();
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
static get inheritedAttributes() {
|
|
return {
|
|
".textbox-input":
|
|
"value,maxlength,disabled,size,readonly,placeholder,tabindex,accesskey,mozactionhint,spellcheck",
|
|
".textbox-search-icon":
|
|
"src=image,label=searchbuttonlabel,searchbutton,disabled",
|
|
".textbox-search-clear": "disabled",
|
|
};
|
|
}
|
|
|
|
connectedCallback() {
|
|
if (this.delayConnectedCallback()) {
|
|
return;
|
|
}
|
|
this.textContent = "";
|
|
|
|
const textboxSign = document.createXULElement("image");
|
|
textboxSign.className = "textbox-search-sign";
|
|
|
|
const input = this.inputField;
|
|
input.className = "textbox-input";
|
|
input.setAttribute("mozactionhint", "search");
|
|
input.addEventListener("focus", () =>
|
|
this.setAttribute("focused", "true")
|
|
);
|
|
input.addEventListener("blur", () => this.removeAttribute("focused"));
|
|
|
|
const searchBtn = (this._searchButtonIcon = document.createXULElement(
|
|
"image"
|
|
));
|
|
searchBtn.className = "textbox-search-icon";
|
|
searchBtn.addEventListener("click", e => this._iconClick(e));
|
|
|
|
// TODO: Bug 1534799 - Convert string to Fluent and use manual DOM construction
|
|
let clearBtn = MozXULElement.parseXULToFragment(
|
|
`
|
|
<image class="textbox-search-clear" label="&searchTextBox.clear.label;"/>
|
|
`,
|
|
["chrome://global/locale/textcontext.dtd"]
|
|
);
|
|
clearBtn = this._searchClearIcon = clearBtn.querySelector(
|
|
".textbox-search-clear"
|
|
);
|
|
clearBtn.addEventListener("click", () => this._clearSearch());
|
|
|
|
const deck = (this._searchIcons = document.createXULElement("deck"));
|
|
deck.className = "textbox-search-icons";
|
|
deck.append(searchBtn, clearBtn);
|
|
this.append(textboxSign, input, deck);
|
|
|
|
this._timer = null;
|
|
|
|
// Ensure the button state is up to date:
|
|
// eslint-disable-next-line no-self-assign
|
|
this.searchButton = this.searchButton;
|
|
|
|
this.initializeAttributeInheritance();
|
|
}
|
|
|
|
set timeout(val) {
|
|
this.setAttribute("timeout", val);
|
|
return val;
|
|
}
|
|
|
|
get timeout() {
|
|
return parseInt(this.getAttribute("timeout")) || 500;
|
|
}
|
|
|
|
set searchButton(val) {
|
|
if (val) {
|
|
this.setAttribute("searchbutton", "true");
|
|
this.removeAttribute("aria-autocomplete");
|
|
// Hack for the button to get the right accessible:
|
|
// If you update the 'onclick' event handler code within the
|
|
// _searchButtonIcon you also have to update the sha512 hash in the
|
|
// CSP of about:addons within extensions.xhtml.
|
|
this._searchButtonIcon.setAttribute("onclick", "true");
|
|
} else {
|
|
this.removeAttribute("searchbutton");
|
|
this._searchButtonIcon.removeAttribute("onclick");
|
|
this.setAttribute("aria-autocomplete", "list");
|
|
}
|
|
return val;
|
|
}
|
|
|
|
get searchButton() {
|
|
return this.getAttribute("searchbutton") == "true";
|
|
}
|
|
|
|
set value(val) {
|
|
this.inputField.value = val;
|
|
|
|
if (val) {
|
|
this._searchIcons.selectedIndex = this.searchButton ? 0 : 1;
|
|
} else {
|
|
this._searchIcons.selectedIndex = 0;
|
|
}
|
|
|
|
if (this._timer) {
|
|
clearTimeout(this._timer);
|
|
}
|
|
return val;
|
|
}
|
|
|
|
get value() {
|
|
return this.inputField.value;
|
|
}
|
|
|
|
get editor() {
|
|
return this.inputField.editor;
|
|
}
|
|
|
|
set disabled(val) {
|
|
this.inputField.disabled = val;
|
|
if (val) {
|
|
this.setAttribute("disabled", "true");
|
|
} else {
|
|
this.removeAttribute("disabled");
|
|
}
|
|
return val;
|
|
}
|
|
|
|
get disabled() {
|
|
return this.inputField.disabled;
|
|
}
|
|
|
|
_fireCommand(me) {
|
|
if (me._timer) {
|
|
clearTimeout(me._timer);
|
|
}
|
|
me._timer = null;
|
|
me.doCommand();
|
|
}
|
|
|
|
_iconClick() {
|
|
if (this.searchButton) {
|
|
this._enterSearch();
|
|
} else {
|
|
this.focus();
|
|
}
|
|
}
|
|
|
|
_enterSearch() {
|
|
if (this.disabled) {
|
|
return;
|
|
}
|
|
if (this.searchButton && this.value && !this.readOnly) {
|
|
this._searchIcons.selectedIndex = 1;
|
|
}
|
|
this._fireCommand(this);
|
|
}
|
|
|
|
_clearSearch() {
|
|
if (!this.disabled && !this.readOnly && this.value) {
|
|
this.value = "";
|
|
this._fireCommand(this);
|
|
this._searchIcons.selectedIndex = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
customElements.define("search-textbox", MozSearchTextbox);
|
|
}
|