Skip to content

Commit bb4a1bd

Browse files
committed
Implement InputEvent.getTargetRanges() for the input events spec
https://bugs.webkit.org/show_bug.cgi?id=162947 <rdar://problem/28853079> Reviewed by Darin Adler. Source/JavaScriptCore: Boilerplate change to add a runtime guard for InputEvents-related IDL interfaces. See WebCore ChangeLog entry for more details. * runtime/CommonIdentifiers.h: Source/WebCore: Implements InputEvent.getTargetRanges(). See individual method changes below for more details. Adds a new hook for subclasses of CompositeEditCommand to vend a list of target StaticRanges when retrieving target ranges for an editing command on a contenteditable area. Tests: fast/events/before-input-delete-empty-list-target-ranges.html fast/events/before-input-delete-text-target-ranges.html fast/events/before-input-replace-text-target-ranges.html * CMakeLists.txt: * DerivedSources.make: * WebCore.xcodeproj/project.pbxproj: Add StaticRange.idl, StaticRange.cpp and StaticRange.h. * bindings/generic/RuntimeEnabledFeatures.h: (WebCore::RuntimeEnabledFeatures::setInputEventsEnabled): (WebCore::RuntimeEnabledFeatures::inputEventsEnabled): Add a new runtime bindings flag for InputEvents and guard both InputEvent and StaticRange behind it. * dom/DOMAllInOne.cpp: * dom/InputEvent.cpp: (WebCore::InputEvent::InputEvent): * dom/InputEvent.h: * dom/InputEvent.idl: * dom/StaticRange.cpp: Copied from Source/WebCore/dom/InputEvent.cpp. (WebCore::StaticRange::StaticRange): (WebCore::StaticRange::create): (WebCore::StaticRange::createFromRange): Convenience method for creating a StaticRange from a Range's start/end container and offset. (WebCore::StaticRange::startContainer): (WebCore::StaticRange::endContainer): (WebCore::StaticRange::collapsed): * dom/StaticRange.h: Copied from Source/WebCore/dom/InputEvent.cpp. (WebCore::StaticRange::startOffset): (WebCore::StaticRange::endOffset): * dom/StaticRange.idl: Copied from Source/WebCore/editing/ReplaceRangeWithTextCommand.h. * editing/CompositeEditCommand.cpp: (WebCore::CompositeEditCommand::willApplyCommand): (WebCore::CompositeEditCommand::targetRanges): Virtual method that returns a list of target ranges which are associated with this command. (WebCore::CompositeEditCommand::targetRangesForBindings): Non-virtual method that calls the above targetRanges(). Takes whether or not the CompositeEditCommand is editing a textarea or plain text input into account. (WebCore::CompositeEditCommand::moveParagraphs): * editing/CompositeEditCommand.h: * editing/EditCommand.cpp: (WebCore::EditCommand::frame): * editing/EditCommand.h: (WebCore::EditCommand::document): * editing/Editor.cpp: (WebCore::dispatchBeforeInputEvent): (WebCore::dispatchInputEvent): (WebCore::dispatchBeforeInputEvents): Changed the `beforeinput` event dispatch to use the regular Node::dispatchEvent instead of dispatchScopedEvent. This is because if the page prevents the `beforeinput` event, we need to know immediately in order to bail from the default action. (WebCore::dispatchInputEvents): (WebCore::Editor::willApplyEditing): Added a list of static ranges as a parameter when calling on the Editor to dispatch `beforeinput` events. By default, this uses the composite edit command's targetRangesForBindings(), though it may be special cased by subclasses of CompositeEditCommand (see ReplaceRangeWithTextCommand, SpellingCorrectionCommand, and TypingCommand). * editing/Editor.h: * editing/ReplaceRangeWithTextCommand.cpp: (WebCore::ReplaceRangeWithTextCommand::targetRanges): * editing/ReplaceRangeWithTextCommand.h: * editing/SpellingCorrectionCommand.cpp: (WebCore::SpellingCorrectionCommand::targetRanges): * editing/SpellingCorrectionCommand.h: * editing/TypingCommand.cpp: (WebCore::editActionIsDeleteByTyping): (WebCore::TypingCommand::shouldDeferWillApplyCommandUntilAddingTypingCommand): (WebCore::TypingCommand::willApplyCommand): (WebCore::TypingCommand::willAddTypingToOpenCommand): (WebCore::TypingCommand::deleteKeyPressed): (WebCore::TypingCommand::forwardDeleteKeyPressed): Moves the firing of the `beforeinput` until after the selection range to delete has been computed. * editing/TypingCommand.h: Source/WebKit2: Boilerplate change to add a runtime guard for InputEvents-related IDL interfaces. See WebCore ChangeLog entry for more details. * WebProcess/WebPage/WebPage.cpp: (WebKit::WebPage::updatePreferences): LayoutTests: Adds 3 new layout tests and tweaks some existing unit tests. See WebCore ChangeLog entry for more details. Tests verify the result of getTargetRanges() when breaking out of a list, deleting backwards and forwards at all text granularities, deleting selected text, and spell checking (candidate text replacement). * fast/events/before-input-delete-empty-list-target-ranges-expected.txt: Added. * fast/events/before-input-delete-empty-list-target-ranges.html: Added. * fast/events/before-input-delete-text-target-ranges-expected.txt: Added. * fast/events/before-input-delete-text-target-ranges.html: Added. * fast/events/before-input-events-prevent-default-in-textfield.html: * fast/events/before-input-replace-text-target-ranges-expected.txt: Added. * fast/events/before-input-replace-text-target-ranges.html: Added. * fast/events/input-events-fired-when-typing-expected.txt: * fast/events/input-events-fired-when-typing.html: * js/dom/global-constructors-attributes-expected.txt: * platform/ios-simulator/TestExpectations: * platform/mac-wk1/js/dom/global-constructors-attributes-expected.txt: * platform/mac-yosemite/js/dom/global-constructors-attributes-expected.txt: * platform/mac/js/dom/global-constructors-attributes-expected.txt: Canonical link: https://commits.webkit.org/181550@main git-svn-id: https://svn.webkit.org/repository/webkit/trunk@207670 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent eb7837f commit bb4a1bd

43 files changed

Lines changed: 708 additions & 60 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

LayoutTests/ChangeLog

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1+
2016-10-21 Wenson Hsieh <wenson_hsieh@apple.com>
2+
3+
Implement InputEvent.getTargetRanges() for the input events spec
4+
https://bugs.webkit.org/show_bug.cgi?id=162947
5+
<rdar://problem/28853079>
6+
7+
Reviewed by Darin Adler.
8+
9+
Adds 3 new layout tests and tweaks some existing unit tests. See WebCore ChangeLog entry for more details.
10+
Tests verify the result of getTargetRanges() when breaking out of a list, deleting backwards and forwards at
11+
all text granularities, deleting selected text, and spell checking (candidate text replacement).
12+
13+
* fast/events/before-input-delete-empty-list-target-ranges-expected.txt: Added.
14+
* fast/events/before-input-delete-empty-list-target-ranges.html: Added.
15+
* fast/events/before-input-delete-text-target-ranges-expected.txt: Added.
16+
* fast/events/before-input-delete-text-target-ranges.html: Added.
17+
* fast/events/before-input-events-prevent-default-in-textfield.html:
18+
* fast/events/before-input-replace-text-target-ranges-expected.txt: Added.
19+
* fast/events/before-input-replace-text-target-ranges.html: Added.
20+
* fast/events/input-events-fired-when-typing-expected.txt:
21+
* fast/events/input-events-fired-when-typing.html:
22+
* js/dom/global-constructors-attributes-expected.txt:
23+
* platform/ios-simulator/TestExpectations:
24+
* platform/mac-wk1/js/dom/global-constructors-attributes-expected.txt:
25+
* platform/mac-yosemite/js/dom/global-constructors-attributes-expected.txt:
26+
* platform/mac/js/dom/global-constructors-attributes-expected.txt:
27+
128
2016-10-21 Javier Fernandez <jfernandez@igalia.com>
229

330
[css-grid] Content Alignment broken with indefinite sized grid container
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
To manually test this, delete the empty list element and observe the output.
2+
3+
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4+
5+
6+
PASS event.getTargetRanges().length is 1
7+
PASS range.startContainer.nodeName is '#text'
8+
PASS range.startContainer.textContent is 'foo'
9+
PASS range.endContainer is item
10+
PASS range.startOffset is 3
11+
PASS range.endOffset is 0
12+
PASS successfullyParsed is true
13+
14+
TEST COMPLETE
15+
foo
16+
17+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="../../resources/js-test-pre.js"></script>
5+
</head>
6+
<body>
7+
<div id="editable" contenteditable onbeforeinput=beforeinput(event)>foo<div><ul><li id="item"><br></li></ul></div></div>
8+
<script type="text/javascript">
9+
description("To manually test this, delete the empty list element and observe the output.");
10+
11+
editable.focus();
12+
getSelection().setPosition(item);
13+
14+
if (window.internals)
15+
internals.settings.setInputEventsEnabled(true);
16+
17+
if (window.testRunner)
18+
testRunner.execCommand("deleteBackward");
19+
20+
function beforeinput(event)
21+
{
22+
shouldBe("event.getTargetRanges().length", "1");
23+
for (let range of event.getTargetRanges()) {
24+
window.range = range;
25+
shouldBe("range.startContainer.nodeName", "'#text'");
26+
shouldBe("range.startContainer.textContent", "'foo'");
27+
shouldBe("range.endContainer", "item");
28+
shouldBe("range.startOffset", "3");
29+
shouldBe("range.endOffset", "0");
30+
}
31+
event.preventDefault();
32+
}
33+
</script>
34+
<script src="../../resources/js-test-post.js"></script>
35+
</body>
36+
</html>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
To manually test this, try deleting backwards/forwards at various text granularities and observe the output.
2+
3+
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4+
5+
6+
PASS event.inputType.startsWith('delete') is true
7+
PASS deletionRange.startContainer is deletionRange.endContainer
8+
Deleting text in range: [0, 1]
9+
PASS event.inputType.startsWith('delete') is true
10+
PASS deletionRange.startContainer is deletionRange.endContainer
11+
Deleting text in range: [3, 4]
12+
PASS event.inputType.startsWith('delete') is true
13+
PASS deletionRange.startContainer is deletionRange.endContainer
14+
Deleting text in range: [2, 3]
15+
PASS event.inputType.startsWith('delete') is true
16+
PASS deletionRange.startContainer is deletionRange.endContainer
17+
Deleting text in range: [16, 17]
18+
PASS event.inputType.startsWith('delete') is true
19+
PASS deletionRange.startContainer is deletionRange.endContainer
20+
Deleting text in range: [0, 17]
21+
PASS event.inputType.startsWith('delete') is true
22+
PASS deletionRange.startContainer is deletionRange.endContainer
23+
Deleting text in range: [4, 7]
24+
PASS event.inputType.startsWith('delete') is true
25+
PASS deletionRange.startContainer is deletionRange.endContainer
26+
Deleting text in range: [7, 10]
27+
PASS event.inputType.startsWith('delete') is true
28+
PASS deletionRange.startContainer is deletionRange.endContainer
29+
Deleting text in range: [0, 10]
30+
PASS successfullyParsed is true
31+
32+
TEST COMPLETE
33+
foo barbaz garply
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="../../resources/js-test-pre.js"></script>
5+
</head>
6+
<body>
7+
<div id="editable" contenteditable onbeforeinput=beforeinput(event)>foo barbaz garply</div>
8+
<script type="text/javascript">
9+
description("To manually test this, try deleting backwards/forwards at various text granularities and observe the output.");
10+
11+
editable.focus();
12+
13+
if (window.internals)
14+
internals.settings.setInputEventsEnabled(true);
15+
16+
if (window.testRunner) {
17+
select(0, 0);
18+
testRunner.execCommand("deleteForward");
19+
20+
select(3, 3);
21+
testRunner.execCommand("deleteForward");
22+
testRunner.execCommand("deleteBackward");
23+
24+
select(17, 17);
25+
testRunner.execCommand("deleteBackward");
26+
testRunner.execCommand("deleteToBeginningOfLine");
27+
28+
select(7, 7);
29+
testRunner.execCommand("deleteWordBackward");
30+
testRunner.execCommand("deleteWordForward");
31+
32+
select(0, 10);
33+
testRunner.execCommand("deleteBackward");
34+
}
35+
36+
function beforeinput(event)
37+
{
38+
shouldBeTrue("event.inputType.startsWith('delete')");
39+
40+
window.deletionRange = event.getTargetRanges()[0];
41+
shouldBe("deletionRange.startContainer", "deletionRange.endContainer");
42+
debug(`Deleting text in range: [${deletionRange.startOffset}, ${deletionRange.endOffset}]`)
43+
event.preventDefault();
44+
}
45+
46+
function select(startOffset, endOffset)
47+
{
48+
let range = document.createRange();
49+
let textNode = editable.childNodes[0];
50+
51+
getSelection().removeAllRanges();
52+
range.setStart(textNode, startOffset);
53+
range.setEnd(textNode, endOffset);
54+
getSelection().addRange(range);
55+
}
56+
</script>
57+
<script src="../../resources/js-test-post.js"></script>
58+
</body>
59+
</html>

LayoutTests/fast/events/before-input-events-prevent-default-in-textfield.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
preventDefaultInputEvents = true;
2424

25-
eventSender.keyDown("delete");
25+
testRunner.execCommand("DeleteBackward");
2626
debug(`The final value is: ${input.value}`);
2727
}
2828

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
To manually test this, type "hllo" and trigger spell checking. Select a spell checking candidate.
2+
3+
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4+
5+
6+
PASS replacementRange.startOffset is 0
7+
PASS replacementRange.endOffset is 4
8+
PASS replacementRange.startContainer is editable.childNodes[0]
9+
PASS replacementRange.endContainer is editable.childNodes[0]
10+
PASS successfullyParsed is true
11+
12+
TEST COMPLETE
13+
hllo
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<script src="../../resources/js-test-pre.js"></script>
5+
</head>
6+
<body>
7+
<div id="editable" contenteditable onbeforeinput=beforeinput(event)></div>
8+
<script type="text/javascript">
9+
description("To manually test this, type \"hllo\" and trigger spell checking. Select a spell checking candidate.");
10+
11+
editable.focus();
12+
13+
if (window.eventSender && window.internals) {
14+
internals.settings.setInputEventsEnabled(true);
15+
eventSender.keyDown("h");
16+
eventSender.keyDown("l");
17+
eventSender.keyDown("l");
18+
eventSender.keyDown("o");
19+
internals.handleAcceptedCandidate("hello", 0, 4);
20+
}
21+
22+
function beforeinput(event)
23+
{
24+
if (event.inputType !== "insertReplacementText")
25+
return;
26+
27+
window.replacementRange = event.getTargetRanges()[0];
28+
shouldBe("replacementRange.startOffset", "0");
29+
shouldBe("replacementRange.endOffset", "4");
30+
shouldBe("replacementRange.startContainer", "editable.childNodes[0]");
31+
shouldBe("replacementRange.endContainer", "editable.childNodes[0]");
32+
event.preventDefault();
33+
}
34+
</script>
35+
<script src="../../resources/js-test-post.js"></script>
36+
</body>
37+
</html>

LayoutTests/fast/events/input-events-fired-when-typing-expected.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,31 @@ TEST COMPLETE
44
Fired `onbeforeinput`!
55
PASS event.__lookupGetter__('inputType') is defined.
66
PASS event.__lookupGetter__('data') is defined.
7-
PASS Object.getPrototypeOf(event) is InputEvent.prototype
7+
PASS event.getTargetRanges is defined.
88
PASS event.target.id is expectedTargetID
99
PASS event.bubbles is true
1010
PASS event.cancelable is true
1111
PASS event.composed is true
1212
Fired `oninput`!
1313
PASS event.__lookupGetter__('inputType') is defined.
1414
PASS event.__lookupGetter__('data') is defined.
15-
PASS Object.getPrototypeOf(event) is InputEvent.prototype
15+
PASS event.getTargetRanges is defined.
1616
PASS event.target.id is expectedTargetID
1717
PASS event.bubbles is true
1818
PASS event.cancelable is false
1919
PASS event.composed is true
2020
Fired `onbeforeinput`!
2121
PASS event.__lookupGetter__('inputType') is defined.
2222
PASS event.__lookupGetter__('data') is defined.
23-
PASS Object.getPrototypeOf(event) is InputEvent.prototype
23+
PASS event.getTargetRanges is defined.
2424
PASS event.target.id is expectedTargetID
2525
PASS event.bubbles is true
2626
PASS event.cancelable is true
2727
PASS event.composed is true
2828
Fired `oninput`!
2929
PASS event.__lookupGetter__('inputType') is defined.
3030
PASS event.__lookupGetter__('data') is defined.
31-
PASS Object.getPrototypeOf(event) is InputEvent.prototype
31+
PASS event.getTargetRanges is defined.
3232
PASS event.target.id is expectedTargetID
3333
PASS event.bubbles is true
3434
PASS event.cancelable is false

LayoutTests/fast/events/input-events-fired-when-typing.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
debug("Fired `oninput`!");
3737
shouldBeDefined("event.__lookupGetter__('inputType')");
3838
shouldBeDefined("event.__lookupGetter__('data')");
39-
shouldBe("Object.getPrototypeOf(event)", "InputEvent.prototype");
39+
shouldBeDefined("event.getTargetRanges");
4040
shouldBe("event.target.id", "expectedTargetID");
4141
shouldBe("event.bubbles", "true");
4242
shouldBe("event.cancelable", "false");
@@ -48,7 +48,7 @@
4848
debug("Fired `onbeforeinput`!");
4949
shouldBeDefined("event.__lookupGetter__('inputType')");
5050
shouldBeDefined("event.__lookupGetter__('data')");
51-
shouldBe("Object.getPrototypeOf(event)", "InputEvent.prototype");
51+
shouldBeDefined("event.getTargetRanges");
5252
shouldBe("event.target.id", "expectedTargetID");
5353
shouldBe("event.bubbles", "true");
5454
shouldBe("event.cancelable", "true");

0 commit comments

Comments
 (0)