From 43a97878ce14b72f0981164f87f2e35e14151312 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:22:09 +0200 Subject: Adding upstream version 110.0.1. Signed-off-by: Daniel Baumann --- testing/web-platform/tests/input-events/META.yml | 4 + .../tests/input-events/idlharness.window.js | 14 + .../tests/input-events/input-events-cut-paste.html | 141 ++ .../input-events/input-events-exec-command.html | 230 ++ ...ents-get-target-ranges-backspace.tentative.html | 2065 ++++++++++++++++++ ...et-ranges-deleting-in-list-items.tentative.html | 1744 ++++++++++++++++ ...e-across-editing-host-boundaries.tentative.html | 598 ++++++ ...ranges-during-and-after-dispatch.tentative.html | 63 + ...-get-target-ranges-forwarddelete.tentative.html | 2209 ++++++++++++++++++++ ...ning-dl-element-and-another-list.tentative.html | 285 +++ ...arget-ranges-joining-dl-elements.tentative.html | 605 ++++++ ...t-ranges-non-collapsed-selection.tentative.html | 741 +++++++ .../input-events-get-target-ranges.html | 154 ++ .../input-events/input-events-get-target-ranges.js | 518 +++++ .../tests/input-events/input-events-typing.html | 285 +++ .../input-events/select-event-drag-remove.html | 32 + 16 files changed, 9688 insertions(+) create mode 100644 testing/web-platform/tests/input-events/META.yml create mode 100644 testing/web-platform/tests/input-events/idlharness.window.js create mode 100644 testing/web-platform/tests/input-events/input-events-cut-paste.html create mode 100644 testing/web-platform/tests/input-events/input-events-exec-command.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-backspace.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-range-across-editing-host-boundaries.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges.html create mode 100644 testing/web-platform/tests/input-events/input-events-get-target-ranges.js create mode 100644 testing/web-platform/tests/input-events/input-events-typing.html create mode 100644 testing/web-platform/tests/input-events/select-event-drag-remove.html (limited to 'testing/web-platform/tests/input-events') diff --git a/testing/web-platform/tests/input-events/META.yml b/testing/web-platform/tests/input-events/META.yml new file mode 100644 index 0000000000..79e0cbe522 --- /dev/null +++ b/testing/web-platform/tests/input-events/META.yml @@ -0,0 +1,4 @@ +spec: https://w3c.github.io/input-events/ +suggested_reviewers: + - johanneswilm + - siusin diff --git a/testing/web-platform/tests/input-events/idlharness.window.js b/testing/web-platform/tests/input-events/idlharness.window.js new file mode 100644 index 0000000000..3a9a34837e --- /dev/null +++ b/testing/web-platform/tests/input-events/idlharness.window.js @@ -0,0 +1,14 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +'use strict'; + +idl_test( + ['input-events'], + ['uievents', 'dom'], + idl_array => { + idl_array.add_objects({ + InputEvent: ['new InputEvent("foo")'], + }); + } +); diff --git a/testing/web-platform/tests/input-events/input-events-cut-paste.html b/testing/web-platform/tests/input-events/input-events-cut-paste.html new file mode 100644 index 0000000000..f2ca5a0a65 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-cut-paste.html @@ -0,0 +1,141 @@ + + +Cut and Paste should trigger corresponding InputEvent + + + + + + +

To manually run this test, please follow the steps below:
+1. Select 'plain' => Cut (e.g. Ctrl/Cmd-X) => Paste (e.g. Ctrl/Cmd-V).
+2. Select 'rich' => Cut => Paste.
+3. Select 'prevent' => Paste.
+4. Select 'prevent' => Cut => Select 'normal' => Paste.
+
+If a "PASS" result appears the test passes, otherwise it fails

+ +

rich

+

prevent

+

normal

+ diff --git a/testing/web-platform/tests/input-events/input-events-exec-command.html b/testing/web-platform/tests/input-events/input-events-exec-command.html new file mode 100644 index 0000000000..8f8493651e --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-exec-command.html @@ -0,0 +1,230 @@ + + +execCommand() should only trigger 'input' + + +
+ diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-backspace.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-backspace.tentative.html new file mode 100644 index 0000000000..347ac61c3e --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-backspace.tentative.html @@ -0,0 +1,2065 @@ + + + +InputEvent.getTargetRanges() at Backspace +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html new file mode 100644 index 0000000000..7c225cd051 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-in-list-items.tentative.html @@ -0,0 +1,1744 @@ + + + + + + + +InputEvent.getTargetRanges() at deleting in/around/across list item elements +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-range-across-editing-host-boundaries.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-range-across-editing-host-boundaries.tentative.html new file mode 100644 index 0000000000..04f632a929 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-deleting-range-across-editing-host-boundaries.tentative.html @@ -0,0 +1,598 @@ + + +InputEvent.getTargetRanges() of deleting a range across editing host boundaries +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html new file mode 100644 index 0000000000..be4656d04a --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-during-and-after-dispatch.tentative.html @@ -0,0 +1,63 @@ + + +InputEvent.getTargetRanges() should return same array in various timings +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html new file mode 100644 index 0000000000..aa282bb126 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-forwarddelete.tentative.html @@ -0,0 +1,2209 @@ + + + +InputEvent.getTargetRanges() at Delete (forward delete) +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html new file mode 100644 index 0000000000..cebddac4c5 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-element-and-another-list.tentative.html @@ -0,0 +1,285 @@ + + + + + +InputEvent.getTargetRanges() at joining dl element and ol or ul element +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html new file mode 100644 index 0000000000..3e51dab775 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-joining-dl-elements.tentative.html @@ -0,0 +1,605 @@ + + + + + +InputEvent.getTargetRanges() at deleting in/around/across list item elements +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html new file mode 100644 index 0000000000..b8732327da --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges-non-collapsed-selection.tentative.html @@ -0,0 +1,741 @@ + + + + + + +InputEvent.getTargetRanges() with non-collapsed selection +
+ + + + + + + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges.html b/testing/web-platform/tests/input-events/input-events-get-target-ranges.html new file mode 100644 index 0000000000..bbb275d8d3 --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges.html @@ -0,0 +1,154 @@ + + +InputEvent.getTargetRanges() behavior + + + + + +

To manually run this test, please follow the steps below:
+1. Place caret at the end of 'hello world'.
+2. Press Ctrl-Backspace (Alt-Backspace on macOS) to delete word backwards.
+3. Place caret at the end of 'test2' => Press 'a' key.
+4. Select 'test2a' => Press 'b' key.
+5. Select 'b' => Bold text through context menu or Command-b on macOS.
+6. Place caret at the end of 'test3' => Press 'a' key => Press Backspace key.
+
+If a "PASS" result appears the test passes, otherwise it fails

+

hello world

+

test2

+ + diff --git a/testing/web-platform/tests/input-events/input-events-get-target-ranges.js b/testing/web-platform/tests/input-events/input-events-get-target-ranges.js new file mode 100644 index 0000000000..004416ec2a --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-get-target-ranges.js @@ -0,0 +1,518 @@ +"use strict"; + +// TODO: extend `EditorTestUtils` in editing/include/edit-test-utils.mjs + +const kBackspaceKey = "\uE003"; +const kDeleteKey = "\uE017"; +const kArrowRight = "\uE014"; +const kArrowLeft = "\uE012"; +const kShift = "\uE008"; +const kMeta = "\uE03d"; +const kControl = "\uE009"; +const kAlt = "\uE00A"; +const kKeyA = "a"; + +const kImgSrc = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAEElEQVR42mNgaGD4D8YwBgAw9AX9Y9zBwwAAAABJRU5ErkJggg=="; + +let gSelection, gEditor, gBeforeinput, gInput; + +function initializeTest(aInnerHTML) { + function onBeforeinput(event) { + // NOTE: Blink makes `getTargetRanges()` return empty range after + // propagation, but this test wants to check the result during + // propagation. Therefore, we need to cache the result, but will + // assert if `getTargetRanges()` returns different ranges after + // checking the cached ranges. + event.cachedRanges = event.getTargetRanges(); + gBeforeinput.push(event); + } + function onInput(event) { + event.cachedRanges = event.getTargetRanges(); + gInput.push(event); + } + if (gEditor !== document.querySelector("div[contenteditable]")) { + if (gEditor) { + gEditor.isListeningToInputEvents = false; + gEditor.removeEventListener("beforeinput", onBeforeinput); + gEditor.removeEventListener("input", onInput); + } + gEditor = document.querySelector("div[contenteditable]"); + } + gSelection = getSelection(); + gBeforeinput = []; + gInput = []; + if (!gEditor.isListeningToInputEvents) { + gEditor.isListeningToInputEvents = true; + gEditor.addEventListener("beforeinput", onBeforeinput); + gEditor.addEventListener("input", onInput); + } + + setupEditor(aInnerHTML); + gBeforeinput = []; + gInput = []; +} + +function getArrayOfRangesDescription(arrayOfRanges) { + if (arrayOfRanges === null) { + return "null"; + } + if (arrayOfRanges === undefined) { + return "undefined"; + } + if (!Array.isArray(arrayOfRanges)) { + return "Unknown Object"; + } + if (arrayOfRanges.length === 0) { + return "[]"; + } + let result = "["; + for (let range of arrayOfRanges) { + result += `{${getRangeDescription(range)}},`; + } + result += "]"; + return result; +} + +function getRangeDescription(range) { + function getNodeDescription(node) { + if (!node) { + return "null"; + } + switch (node.nodeType) { + case Node.TEXT_NODE: + case Node.COMMENT_NODE: + case Node.CDATA_SECTION_NODE: + return `${node.nodeName} "${node.data}"`; + case Node.ELEMENT_NODE: + return `<${node.nodeName.toLowerCase()}>`; + default: + return `${node.nodeName}`; + } + } + if (range === null) { + return "null"; + } + if (range === undefined) { + return "undefined"; + } + return range.startContainer == range.endContainer && + range.startOffset == range.endOffset + ? `(${getNodeDescription(range.startContainer)}, ${range.startOffset})` + : `(${getNodeDescription(range.startContainer)}, ${ + range.startOffset + }) - (${getNodeDescription(range.endContainer)}, ${range.endOffset})`; +} + +function sendDeleteKey(modifier) { + if (!modifier) { + return new test_driver.Actions() + .keyDown(kDeleteKey) + .keyUp(kDeleteKey) + .send(); + } + return new test_driver.Actions() + .keyDown(modifier) + .keyDown(kDeleteKey) + .keyUp(kDeleteKey) + .keyUp(modifier) + .send(); +} + +function sendBackspaceKey(modifier) { + if (!modifier) { + return new test_driver.Actions() + .keyDown(kBackspaceKey) + .keyUp(kBackspaceKey) + .send(); + } + return new test_driver.Actions() + .keyDown(modifier) + .keyDown(kBackspaceKey) + .keyUp(kBackspaceKey) + .keyUp(modifier) + .send(); +} + +function sendKeyA() { + return new test_driver.Actions() + .keyDown(kKeyA) + .keyUp(kKeyA) + .send(); +} + +function sendArrowLeftKey() { + return new test_driver.Actions() + .keyDown(kArrowLeft) + .keyUp(kArrowLeft) + .send(); +} + +function sendArrowRightKey() { + return new test_driver.Actions() + .keyDown(kArrowRight) + .keyUp(kArrowRight) + .send(); +} + +function checkGetTargetRangesOfBeforeinputOnDeleteSomething(expectedRanges) { + assert_equals( + gBeforeinput.length, + 1, + "One beforeinput event should be fired if the key operation tries to delete something" + ); + assert_true( + Array.isArray(gBeforeinput[0].cachedRanges), + "gBeforeinput[0].getTargetRanges() should return an array of StaticRange instances at least during propagation" + ); + let arrayOfExpectedRanges = Array.isArray(expectedRanges) + ? expectedRanges + : [expectedRanges]; + // Before checking the length of array of ranges, we should check the given + // range first because the ranges are more important than whether there are + // redundant additional unexpected ranges. + for ( + let i = 0; + i < + Math.max(arrayOfExpectedRanges.length, gBeforeinput[0].cachedRanges.length); + i++ + ) { + assert_equals( + getRangeDescription(gBeforeinput[0].cachedRanges[i]), + getRangeDescription(arrayOfExpectedRanges[i]), + `gBeforeinput[0].getTargetRanges()[${i}] should return expected range (inputType is "${gBeforeinput[0].inputType}")` + ); + } + assert_equals( + gBeforeinput[0].cachedRanges.length, + arrayOfExpectedRanges.length, + `getTargetRanges() of beforeinput event should return ${arrayOfExpectedRanges.length} ranges` + ); +} + +function checkGetTargetRangesOfInputOnDeleteSomething() { + assert_equals( + gInput.length, + 1, + "One input event should be fired if the key operation deletes something" + ); + // https://github.com/w3c/input-events/issues/113 + assert_true( + Array.isArray(gInput[0].cachedRanges), + "gInput[0].getTargetRanges() should return an array of StaticRange instances at least during propagation" + ); + assert_equals( + gInput[0].cachedRanges.length, + 0, + "gInput[0].getTargetRanges() should return empty array during propagation" + ); +} + +function checkGetTargetRangesOfInputOnDoNothing() { + assert_equals( + gInput.length, + 0, + "input event shouldn't be fired when the key operation does not cause modifying the DOM tree" + ); +} + +function checkBeforeinputAndInputEventsOnNOOP() { + assert_equals( + gBeforeinput.length, + 0, + "beforeinput event shouldn't be fired when the key operation does not cause modifying the DOM tree" + ); + assert_equals( + gInput.length, + 0, + "input event shouldn't be fired when the key operation does not cause modifying the DOM tree" + ); +} + +function checkEditorContentResultAsSubTest( + expectedResult, + description, + options = {} +) { + test(() => { + if (Array.isArray(expectedResult)) { + assert_in_array( + options.ignoreWhiteSpaceDifference + ? gEditor.innerHTML.replace(/ /g, " ") + : gEditor.innerHTML, + expectedResult + ); + } else { + assert_equals( + options.ignoreWhiteSpaceDifference + ? gEditor.innerHTML.replace(/ /g, " ") + : gEditor.innerHTML, + expectedResult + ); + } + }, `${description} - comparing innerHTML`); +} + +// Similar to `setupDiv` in editing/include/tests.js, this method sets +// innerHTML value of gEditor, and sets multiple selection ranges specified +// with the markers. +// - `[` specifies start boundary in a text node +// - `{` specifies start boundary before a node +// - `]` specifies end boundary in a text node +// - `}` specifies end boundary after a node +function setupEditor(innerHTMLWithRangeMarkers) { + const startBoundaries = innerHTMLWithRangeMarkers.match(/\{|\[/g) || []; + const endBoundaries = innerHTMLWithRangeMarkers.match(/\}|\]/g) || []; + if (startBoundaries.length !== endBoundaries.length) { + throw "Should match number of open/close markers"; + } + + gEditor.innerHTML = innerHTMLWithRangeMarkers; + gEditor.focus(); + + if (startBoundaries.length === 0) { + // Don't remove the range for now since some tests may assume that + // setting innerHTML does not remove all selection ranges. + return; + } + + function getNextRangeAndDeleteMarker(startNode) { + function getNextLeafNode(node) { + function inclusiveDeepestFirstChildNode(container) { + while (container.firstChild) { + container = container.firstChild; + } + return container; + } + if (node.hasChildNodes()) { + return inclusiveDeepestFirstChildNode(node); + } + if (node.nextSibling) { + return inclusiveDeepestFirstChildNode(node.nextSibling); + } + let nextSibling = (function nextSiblingOfAncestorElement(child) { + for ( + let parent = child.parentElement; + parent && parent != gEditor; + parent = parent.parentElement + ) { + if (parent.nextSibling) { + return parent.nextSibling; + } + } + return null; + })(node); + if (!nextSibling) { + return null; + } + return inclusiveDeepestFirstChildNode(nextSibling); + } + function scanMarkerInTextNode(textNode, offset) { + return /[\{\[\]\}]/.exec(textNode.data.substr(offset)); + } + let startMarker = (function scanNextStartMaker( + startContainer, + startOffset + ) { + function scanStartMakerInTextNode(textNode, offset) { + let scanResult = scanMarkerInTextNode(textNode, offset); + if (scanResult === null) { + return null; + } + if (scanResult[0] === "}" || scanResult[0] === "]") { + throw "An end marker is found before a start marker"; + } + return { + marker: scanResult[0], + container: textNode, + offset: scanResult.index + offset + }; + } + if (startContainer.nodeType === Node.TEXT_NODE) { + let scanResult = scanStartMakerInTextNode(startContainer, startOffset); + if (scanResult !== null) { + return scanResult; + } + } + let nextNode = startContainer; + while ((nextNode = getNextLeafNode(nextNode))) { + if (nextNode.nodeType === Node.TEXT_NODE) { + let scanResult = scanStartMakerInTextNode(nextNode, 0); + if (scanResult !== null) { + return scanResult; + } + continue; + } + } + return null; + })(startNode, 0); + if (startMarker === null) { + return null; + } + let endMarker = (function scanNextEndMarker(startContainer, startOffset) { + function scanEndMarkerInTextNode(textNode, offset) { + let scanResult = scanMarkerInTextNode(textNode, offset); + if (scanResult === null) { + return null; + } + if (scanResult[0] === "{" || scanResult[0] === "[") { + throw "A start marker is found before an end marker"; + } + return { + marker: scanResult[0], + container: textNode, + offset: scanResult.index + offset + }; + } + if (startContainer.nodeType === Node.TEXT_NODE) { + let scanResult = scanEndMarkerInTextNode(startContainer, startOffset); + if (scanResult !== null) { + return scanResult; + } + } + let nextNode = startContainer; + while ((nextNode = getNextLeafNode(nextNode))) { + if (nextNode.nodeType === Node.TEXT_NODE) { + let scanResult = scanEndMarkerInTextNode(nextNode, 0); + if (scanResult !== null) { + return scanResult; + } + continue; + } + } + return null; + })(startMarker.container, startMarker.offset + 1); + if (endMarker === null) { + throw "Found an open marker, but not found corresponding close marker"; + } + function indexOfContainer(container, child) { + let offset = 0; + for (let node = container.firstChild; node; node = node.nextSibling) { + if (node == child) { + return offset; + } + offset++; + } + throw "child must be a child node of container"; + } + (function deleteFoundMarkers() { + function removeNode(node) { + let container = node.parentElement; + let offset = indexOfContainer(container, node); + node.remove(); + return { container, offset }; + } + if (startMarker.container == endMarker.container) { + // If the text node becomes empty, remove it and set collapsed range + // to the position where there is the text node. + if (startMarker.container.length === 2) { + if (!/[\[\{][\]\}]/.test(startMarker.container.data)) { + throw `Unexpected text node (data: "${startMarker.container.data}")`; + } + let { container, offset } = removeNode(startMarker.container); + startMarker.container = endMarker.container = container; + startMarker.offset = endMarker.offset = offset; + startMarker.marker = endMarker.marker = ""; + return; + } + startMarker.container.data = `${startMarker.container.data.substring( + 0, + startMarker.offset + )}${startMarker.container.data.substring( + startMarker.offset + 1, + endMarker.offset + )}${startMarker.container.data.substring(endMarker.offset + 1)}`; + if (startMarker.offset >= startMarker.container.length) { + startMarker.offset = endMarker.offset = startMarker.container.length; + return; + } + endMarker.offset--; // remove the start marker's length + if (endMarker.offset > endMarker.container.length) { + endMarker.offset = endMarker.container.length; + } + return; + } + if (startMarker.container.length === 1) { + let { container, offset } = removeNode(startMarker.container); + startMarker.container = container; + startMarker.offset = offset; + startMarker.marker = ""; + } else { + startMarker.container.data = `${startMarker.container.data.substring( + 0, + startMarker.offset + )}${startMarker.container.data.substring(startMarker.offset + 1)}`; + } + if (endMarker.container.length === 1) { + let { container, offset } = removeNode(endMarker.container); + endMarker.container = container; + endMarker.offset = offset; + endMarker.marker = ""; + } else { + endMarker.container.data = `${endMarker.container.data.substring( + 0, + endMarker.offset + )}${endMarker.container.data.substring(endMarker.offset + 1)}`; + } + })(); + (function handleNodeSelectMarker() { + if (startMarker.marker === "{") { + if (startMarker.offset === 0) { + // The range start with the text node. + let container = startMarker.container.parentElement; + startMarker.offset = indexOfContainer( + container, + startMarker.container + ); + startMarker.container = container; + } else if (startMarker.offset === startMarker.container.data.length) { + // The range start after the text node. + let container = startMarker.container.parentElement; + startMarker.offset = + indexOfContainer(container, startMarker.container) + 1; + startMarker.container = container; + } else { + throw 'Start marker "{" is allowed start or end of a text node'; + } + } + if (endMarker.marker === "}") { + if (endMarker.offset === 0) { + // The range ends before the text node. + let container = endMarker.container.parentElement; + endMarker.offset = indexOfContainer(container, endMarker.container); + endMarker.container = container; + } else if (endMarker.offset === endMarker.container.data.length) { + // The range ends with the text node. + let container = endMarker.container.parentElement; + endMarker.offset = + indexOfContainer(container, endMarker.container) + 1; + endMarker.container = container; + } else { + throw 'End marker "}" is allowed start or end of a text node'; + } + } + })(); + let range = document.createRange(); + range.setStart(startMarker.container, startMarker.offset); + range.setEnd(endMarker.container, endMarker.offset); + return range; + } + + let ranges = []; + for ( + let range = getNextRangeAndDeleteMarker(gEditor.firstChild); + range; + range = getNextRangeAndDeleteMarker(range.endContainer) + ) { + ranges.push(range); + } + + gSelection.removeAllRanges(); + for (let range of ranges) { + gSelection.addRange(range); + } + + if (gSelection.rangeCount != ranges.length) { + throw `Failed to set selection to the given ranges whose length is ${ranges.length}, but only ${gSelection.rangeCount} ranges are added`; + } +} diff --git a/testing/web-platform/tests/input-events/input-events-typing.html b/testing/web-platform/tests/input-events/input-events-typing.html new file mode 100644 index 0000000000..a894beea9b --- /dev/null +++ b/testing/web-platform/tests/input-events/input-events-typing.html @@ -0,0 +1,285 @@ + + +Input Event typing tests + + + + + +
+ + diff --git a/testing/web-platform/tests/input-events/select-event-drag-remove.html b/testing/web-platform/tests/input-events/select-event-drag-remove.html new file mode 100644 index 0000000000..f5c2e702e5 --- /dev/null +++ b/testing/web-platform/tests/input-events/select-event-drag-remove.html @@ -0,0 +1,32 @@ + + +Drag select triggers the right event, and doesn't crash if it removes the target while at it + + + + + + + + + -- cgit v1.2.3