From 3cacb0bf9751045519b611a5d931867b9f7d42f2 Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 7 Feb 2024 12:20:07 -0500 Subject: [PATCH] Extract delegate for `TrixEditorElement` In preparation for [#1128][], this commit introduces a module-private `Delegate` class to serve as a representation of what form integration requires for the `` custom element. The structure of the `Delegate` class mirrors that of the `TrixEditorElement` from which its contents are extracted. First, there are the properties that mimic those of most form controls, including: * `labels` * `form` * `name` * `value` * `defaultValue` * `type` With the exception of `labels`, property access is mostly proxied through the associated `` element (accessed through its own `inputElement` property). Next, the `Delegate` defines methods that correspond to the Custom Element lifecycle events, including: * `connectedCallback` * `disconnectedCallback` * `setFormValue` The connected and disconnected callbacks mirror that of the `TrixEditorElement` itself. These callbacks attach and remove event listeners for `click` and `reset` events. The `setFormValue` is named to correspond with [ElementInternals.setFormValue][]. Along with introducing this callback method, this commit renames the `TrixEditorElement.setInputElementValue` method to `TrixEditorElement.setFormValue`. In addition to renaming `setInputElementValue`, this commit also defines `TrixEditorElement.formResetCallback` (along with other empty callbacks), then implements `TrixEditorElement.reset` as an alias. The name mirrors the [ElementInternals.formResetCallback][]. [#1128]: https://github.com/basecamp/trix/pull/1128 [ElementInternals.setFormValue]: https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/setFormValue [ElementInternals.formResetCallback]: https://web.dev/articles/more-capable-form-controls#void_formresetcallback --- src/test/system/custom_element_test.js | 36 ++++- src/trix/controllers/editor_controller.js | 2 +- src/trix/elements/trix_editor_element.js | 188 ++++++++++++++-------- 3 files changed, 157 insertions(+), 69 deletions(-) diff --git a/src/test/system/custom_element_test.js b/src/test/system/custom_element_test.js index 2e77e3fc4..9d99b486e 100644 --- a/src/test/system/custom_element_test.js +++ b/src/test/system/custom_element_test.js @@ -391,6 +391,12 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { }) }) + test("element returns empty string when value is missing", async () => { + const element = getEditorElement() + + assert.equal(element.value, "") + }) + test("element serializes HTML after attribute changes", async () => { const element = getEditorElement() let serializedHTML = element.value @@ -440,9 +446,17 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { return promise }) + test("editor resets to its original value on element reset", async () => { + const element = getEditorElement() + + await typeCharacters("hello") + element.reset() + expectDocument("\n") + }) + test("editor resets to its original value on form reset", async () => { const element = getEditorElement() - const { form } = element.inputElement + const { form } = element await typeCharacters("hello") form.reset() @@ -451,7 +465,7 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { test("editor resets to last-set value on form reset", async () => { const element = getEditorElement() - const { form } = element.inputElement + const { form } = element element.value = "hi" await typeCharacters("hello") @@ -461,7 +475,7 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { test("editor respects preventDefault on form reset", async () => { const element = getEditorElement() - const { form } = element.inputElement + const { form } = element const preventDefault = (event) => event.preventDefault() await typeCharacters("hello") @@ -473,6 +487,16 @@ testGroup("Custom element API", { template: "editor_empty" }, () => { }) }) +testGroup("HTML sanitization", { template: "editor_html" }, () => { + test("ignores text nodes in script elements", () => { + const element = getEditorElement() + element.value = "
safe
" + + assert.equal(element.innerHTML, "
safe
") + assert.equal(element.value, "
safe
") + }) +}) + testGroup("