This way we can remove the methods we used to update the size of the input based on its content. We take this as an opportunity to change the way we compute a single char dimension, which is used to offset the autocomplete popup so it aligns with the keyword being typed. We used to create a span, put a `x` in it, add it to the document, hidden, and then get its width and height. This is now replaced by setting custom properties for width and height, which we assign respectively a value of `1ch` and `1lh`, so we get the numbers we need. Because we're retrieving those value via the input computed style, we need to register the property and set a proper `<length>` syntax so we can get their px values. Differential Revision: https://phabricator.services.mozilla.com/D310274
210 lines
5.3 KiB
JavaScript
210 lines
5.3 KiB
JavaScript
/* Any copyright is dedicated to the Public Domain.
|
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
/* import-globals-from helper_inplace_editor.js */
|
|
|
|
"use strict";
|
|
|
|
loadHelperScript("helper_inplace_editor.js");
|
|
|
|
// Test the inplace-editor behavior.
|
|
|
|
add_task(async function () {
|
|
await addTab("data:text/html;charset=utf-8,inline editor tests");
|
|
const { host, doc } = await createHost();
|
|
|
|
await testMultipleInitialization(doc);
|
|
await testReturnCommit(doc);
|
|
await testBlurCommit(doc);
|
|
await testAdvanceCharCommit(doc);
|
|
await testAdvanceCharsFunction(doc);
|
|
await testEscapeCancel(doc);
|
|
await testInputAttributes(doc);
|
|
|
|
host.destroy();
|
|
gBrowser.removeCurrentTab();
|
|
});
|
|
|
|
function testMultipleInitialization(doc) {
|
|
doc.body.innerHTML = "";
|
|
const options = {};
|
|
const span = (options.element = createSpan(doc));
|
|
|
|
info("Creating multiple inplace-editor fields");
|
|
editableField(options);
|
|
editableField(options);
|
|
|
|
info("Clicking on the inplace-editor field to turn to edit mode");
|
|
span.click();
|
|
|
|
is(span.style.display, "none", "The original <span> is hidden");
|
|
is(doc.querySelectorAll("input").length, 1, "Only one <input>");
|
|
is(doc.querySelectorAll("span").length, 1, "Only one <span>");
|
|
}
|
|
|
|
function testReturnCommit(doc) {
|
|
info("Testing that pressing return commits the new value");
|
|
return new Promise(resolve => {
|
|
createInplaceEditorAndClick(
|
|
{
|
|
initial: "explicit initial",
|
|
start(editor) {
|
|
is(
|
|
editor.input.value,
|
|
"explicit initial",
|
|
"Explicit initial value should be used."
|
|
);
|
|
editor.input.value = "Test Value";
|
|
EventUtils.sendKey("return");
|
|
},
|
|
done: onDone("Test Value", true, resolve),
|
|
},
|
|
doc
|
|
);
|
|
});
|
|
}
|
|
|
|
function testBlurCommit(doc) {
|
|
info("Testing that bluring the field commits the new value");
|
|
return new Promise(resolve => {
|
|
createInplaceEditorAndClick(
|
|
{
|
|
start(editor) {
|
|
is(editor.input.value, "Edit Me!", "textContent of the span used.");
|
|
editor.input.value = "Test Value";
|
|
editor.input.blur();
|
|
},
|
|
done: onDone("Test Value", true, resolve),
|
|
},
|
|
doc,
|
|
"Edit Me!"
|
|
);
|
|
});
|
|
}
|
|
|
|
function testAdvanceCharCommit(doc) {
|
|
info("Testing that configured advanceChars commit the new value");
|
|
return new Promise(resolve => {
|
|
createInplaceEditorAndClick(
|
|
{
|
|
advanceChars: ":",
|
|
start() {
|
|
EventUtils.sendString("Test:");
|
|
},
|
|
done: onDone("Test", true, resolve),
|
|
},
|
|
doc
|
|
);
|
|
});
|
|
}
|
|
|
|
function testAdvanceCharsFunction(doc) {
|
|
info("Testing advanceChars as a function");
|
|
return new Promise(resolve => {
|
|
let firstTime = true;
|
|
|
|
createInplaceEditorAndClick(
|
|
{
|
|
initial: "",
|
|
advanceChars(charCode, text) {
|
|
if (charCode !== KeyboardEvent.DOM_VK_COLON) {
|
|
return false;
|
|
}
|
|
if (firstTime) {
|
|
firstTime = false;
|
|
return false;
|
|
}
|
|
|
|
// Just to make sure we check it somehow.
|
|
return !!text.length;
|
|
},
|
|
start() {
|
|
for (const ch of ":Test:") {
|
|
EventUtils.sendChar(ch);
|
|
}
|
|
},
|
|
done: onDone(":Test", true, resolve),
|
|
},
|
|
doc
|
|
);
|
|
});
|
|
}
|
|
|
|
function testEscapeCancel(doc) {
|
|
info("Testing that escape cancels the new value");
|
|
return new Promise(resolve => {
|
|
createInplaceEditorAndClick(
|
|
{
|
|
initial: "initial text",
|
|
start(editor) {
|
|
editor.input.value = "Test Value";
|
|
EventUtils.sendKey("escape");
|
|
},
|
|
done: onDone("initial text", false, resolve),
|
|
},
|
|
doc
|
|
);
|
|
});
|
|
}
|
|
|
|
function testInputAttributes(doc) {
|
|
info("Testing that inputAriaLabel works as expected");
|
|
doc.body.innerHTML = "";
|
|
|
|
let element = createSpan(doc);
|
|
editableField({
|
|
element,
|
|
inputAriaLabel: "TEST_ARIA_LABEL",
|
|
});
|
|
|
|
info("Clicking on the inplace-editor field to turn to edit mode");
|
|
element.click();
|
|
let input = doc.querySelector("input");
|
|
is(
|
|
input.getAttribute("aria-label"),
|
|
"TEST_ARIA_LABEL",
|
|
"Input has expected aria-label"
|
|
);
|
|
|
|
info("Testing that inputAriaLabelledBy works as expected");
|
|
doc.body.innerHTML = "";
|
|
element = createSpan(doc);
|
|
editableField({
|
|
element,
|
|
inputAriaLabelledBy: "TEST_ARIA_LABELLED_BY",
|
|
});
|
|
|
|
info("Clicking on the inplace-editor field to turn to edit mode");
|
|
element.click();
|
|
input = doc.querySelector("input");
|
|
is(
|
|
input.getAttribute("aria-labelledby"),
|
|
"TEST_ARIA_LABELLED_BY",
|
|
"Input has expected aria-labelledby"
|
|
);
|
|
|
|
info("Testing that inputClass works as expected");
|
|
doc.body.innerHTML = "";
|
|
element = createSpan(doc);
|
|
editableField({
|
|
element,
|
|
inputClass: "TEST_INPUT_CLASS",
|
|
});
|
|
|
|
info("Clicking on the inplace-editor field to turn to edit mode");
|
|
element.click();
|
|
input = doc.querySelector("input");
|
|
ok(
|
|
input.classList.contains("TEST_INPUT_CLASS"),
|
|
"Input has expected TEST_INPUT_CLASS class"
|
|
);
|
|
}
|
|
|
|
function onDone(value, isCommit, resolve) {
|
|
return function (actualValue, actualCommit) {
|
|
info("Inplace-editor's done callback executed, checking its state");
|
|
is(actualValue, value, "The value is correct");
|
|
is(actualCommit, isCommit, "The commit boolean is correct");
|
|
resolve();
|
|
};
|
|
}
|