Replace the autocompleted suffix only instead of the whole value using setRangeText. Differential Revision: https://phabricator.services.mozilla.com/D309381
209 lines
4.3 KiB
JavaScript
209 lines
4.3 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/. */
|
|
|
|
/**
|
|
* @import {MultilineEditor} from "chrome://browser/content/multilineeditor/multiline-editor.mjs"
|
|
*/
|
|
|
|
/**
|
|
* Controller for the Smartbar editor.
|
|
*
|
|
* The controller abstracts the underlying editor implementation allowing
|
|
* the Smartbar to also work with a standard HTML input.
|
|
*/
|
|
export class SmartbarInputController {
|
|
/**
|
|
* @param {object} adapter
|
|
* Adapter with input and editor references.
|
|
* @param {MultilineEditor | HTMLInputElement} adapter.input
|
|
* The input element.
|
|
* @param {object} adapter.editor
|
|
* The editor object.
|
|
*/
|
|
constructor(adapter) {
|
|
/** @type {MultilineEditor | HTMLInputElement} */
|
|
this.input = adapter.input;
|
|
/** @type {object} */
|
|
this.editor = adapter.editor;
|
|
}
|
|
|
|
/**
|
|
* Focuses the input element.
|
|
*/
|
|
focus() {
|
|
this.input.focus();
|
|
}
|
|
|
|
/**
|
|
* Removes focus from the input element.
|
|
*/
|
|
blur() {
|
|
this.input.blur();
|
|
}
|
|
|
|
/**
|
|
* Whether the input is read-only.
|
|
*
|
|
* @type {boolean}
|
|
*/
|
|
get readOnly() {
|
|
return this.input.readOnly;
|
|
}
|
|
|
|
set readOnly(val) {
|
|
this.input.readOnly = val;
|
|
}
|
|
|
|
/**
|
|
* The placeholder text for the input.
|
|
*
|
|
* @type {string}
|
|
*/
|
|
get placeholder() {
|
|
return this.input.placeholder ?? "";
|
|
}
|
|
|
|
set placeholder(val) {
|
|
this.input.placeholder = val ?? "";
|
|
}
|
|
|
|
/**
|
|
* The current value of the input.
|
|
*
|
|
* @type {string}
|
|
*/
|
|
get value() {
|
|
return this.input.value ?? "";
|
|
}
|
|
|
|
/**
|
|
* Sets the value of the input.
|
|
*
|
|
* @param {string} val
|
|
*/
|
|
setValue(val) {
|
|
this.input.value = val ?? "";
|
|
}
|
|
|
|
/**
|
|
* The start offset of the selection.
|
|
*
|
|
* @type {number}
|
|
*/
|
|
get selectionStart() {
|
|
return this.input.selectionStart ?? 0;
|
|
}
|
|
|
|
set selectionStart(val) {
|
|
this.setSelectionRange(val, this.selectionEnd ?? val);
|
|
}
|
|
|
|
/**
|
|
* The end offset of the selection.
|
|
*
|
|
* @type {number}
|
|
*/
|
|
get selectionEnd() {
|
|
return this.input.selectionEnd ?? 0;
|
|
}
|
|
|
|
set selectionEnd(val) {
|
|
this.setSelectionRange(this.selectionStart ?? 0, val);
|
|
}
|
|
|
|
/**
|
|
* Sets the selection range in the input.
|
|
*
|
|
* @param {number} start
|
|
* The start offset.
|
|
* @param {number} end
|
|
* The end offset.
|
|
*/
|
|
setSelectionRange(start, end) {
|
|
if (!this.input.setSelectionRange) {
|
|
return;
|
|
}
|
|
const from = Math.max(0, start ?? 0);
|
|
const to = Math.max(from, end ?? from);
|
|
this.input.setSelectionRange(from, to);
|
|
}
|
|
|
|
/**
|
|
* Replace a range of text and update the selection.
|
|
*
|
|
* @param {string} replacement
|
|
* @param {number} start
|
|
* @param {number} end
|
|
* @param {SelectionMode} [selectionMode]
|
|
*/
|
|
setRangeText(replacement, start, end, selectionMode) {
|
|
this.input.setRangeText(replacement, start, end, selectionMode);
|
|
}
|
|
|
|
/**
|
|
* Selects all text in the input.
|
|
*/
|
|
select() {
|
|
this.input.select?.();
|
|
}
|
|
|
|
/**
|
|
* Dispatches an input event on the input element.
|
|
*
|
|
* @param {object} [options]
|
|
* The event options.
|
|
* @param {string} [options.inputType="insertText"]
|
|
* The input type.
|
|
* @param {string} [options.data=""]
|
|
* The data being inserted.
|
|
*/
|
|
dispatchInput({ inputType = "insertText", data = "" } = {}) {
|
|
this.input.dispatchEvent(
|
|
new InputEvent("input", {
|
|
bubbles: true,
|
|
composed: true,
|
|
inputType,
|
|
data,
|
|
})
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Dispatches a selectionchange event on the input element.
|
|
*/
|
|
dispatchSelectionChange() {
|
|
this.input.dispatchEvent(
|
|
new Event("selectionchange", { bubbles: true, composed: true })
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Whether the editor is in composition mode.
|
|
*
|
|
* @type {boolean}
|
|
*/
|
|
get composing() {
|
|
return this.editor.composing ?? false;
|
|
}
|
|
|
|
/**
|
|
* The number of selection ranges in the editor.
|
|
*
|
|
* @type {number}
|
|
*/
|
|
get selectionRangeCount() {
|
|
return this.editor.selection?.rangeCount ?? 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the string representation of the current selection with formatting.
|
|
*
|
|
* @returns {string}
|
|
* The formatted selection string.
|
|
*/
|
|
selectionToStringWithFormat() {
|
|
return this.editor.selection?.toStringWithFormat() ?? "";
|
|
}
|
|
}
|