Source code

Revision control

Copy as Markdown

Other Tools

/* 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);
}
/**
* 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() ?? "";
}
}