forked from mirrors/gecko-dev
Bug 1675883 - Use SetStartAndEndInLimiter() in SetSelectionInternal() r=masayuki
Differential Revision: https://phabricator.services.mozilla.com/D96503
This commit is contained in:
parent
cd031ba211
commit
21c2a81d5e
2 changed files with 153 additions and 29 deletions
|
|
@ -793,25 +793,6 @@ already_AddRefed<TextEditor> nsTextControlFrame::GetTextEditor() {
|
||||||
nsresult nsTextControlFrame::SetSelectionInternal(
|
nsresult nsTextControlFrame::SetSelectionInternal(
|
||||||
nsINode* aStartNode, uint32_t aStartOffset, nsINode* aEndNode,
|
nsINode* aStartNode, uint32_t aStartOffset, nsINode* aEndNode,
|
||||||
uint32_t aEndOffset, nsITextControlFrame::SelectionDirection aDirection) {
|
uint32_t aEndOffset, nsITextControlFrame::SelectionDirection aDirection) {
|
||||||
// Create a new range to represent the new selection.
|
|
||||||
// Note that we use a new range to avoid having to do
|
|
||||||
// isIncreasing checks to avoid possible errors.
|
|
||||||
|
|
||||||
// Be careful to use internal nsRange methods which do not check to make sure
|
|
||||||
// we have access to the node.
|
|
||||||
// XXXbz nsRange::SetStartAndEnd takes int32_t (and ranges generally work on
|
|
||||||
// int32_t), but we're passing uint32_t. The good news is that at this point
|
|
||||||
// our endpoints should really be within our length, so not really that big.
|
|
||||||
// And if they _are_ that big, SetStartAndEnd() will simply error out, which
|
|
||||||
// is not too bad for a case we don't expect to happen.
|
|
||||||
ErrorResult error;
|
|
||||||
RefPtr<nsRange> range =
|
|
||||||
nsRange::Create(aStartNode, aStartOffset, aEndNode, aEndOffset, error);
|
|
||||||
if (NS_WARN_IF(error.Failed())) {
|
|
||||||
return error.StealNSResult();
|
|
||||||
}
|
|
||||||
MOZ_ASSERT(range);
|
|
||||||
|
|
||||||
// Get the selection, clear it and add the new range to it!
|
// Get the selection, clear it and add the new range to it!
|
||||||
TextControlElement* textControlElement =
|
TextControlElement* textControlElement =
|
||||||
TextControlElement::FromNode(GetContent());
|
TextControlElement::FromNode(GetContent());
|
||||||
|
|
@ -831,16 +812,10 @@ nsresult nsTextControlFrame::SetSelectionInternal(
|
||||||
direction = (aDirection == eBackward) ? eDirPrevious : eDirNext;
|
direction = (aDirection == eBackward) ? eDirPrevious : eDirNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
selection->RemoveAllRanges(error);
|
ErrorResult error;
|
||||||
if (NS_WARN_IF(error.Failed())) {
|
selection->SetStartAndEndInLimiter(*aStartNode, aStartOffset, *aEndNode,
|
||||||
return error.StealNSResult();
|
aEndOffset, error);
|
||||||
}
|
MOZ_TRY(error.StealNSResult());
|
||||||
|
|
||||||
selection->AddRangeAndSelectFramesAndNotifyListeners(
|
|
||||||
*range, error); // NOTE: can destroy the world
|
|
||||||
if (NS_WARN_IF(error.Failed())) {
|
|
||||||
return error.StealNSResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
selection->SetDirection(direction);
|
selection->SetDirection(direction);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test selectionchange events from text controls</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<link rel="stylesheet" href="/fonts/ahem.css">
|
||||||
|
<style>
|
||||||
|
input,
|
||||||
|
textarea {
|
||||||
|
font: 16px/1 Ahem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<input id="input" value="XXXXXXXXXXXXXXXXXXX" width="200"><br>
|
||||||
|
<textarea id="textarea" width="200">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</textarea>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
class SelectionChangeCollector {
|
||||||
|
constructor(target) {
|
||||||
|
this.events = [];
|
||||||
|
target.addEventListener("selectionchange", ev => {
|
||||||
|
this.events.push(ev);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
clear() {
|
||||||
|
this.events.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
input: new SelectionChangeCollector(input),
|
||||||
|
textarea: new SelectionChangeCollector(textarea),
|
||||||
|
async initialize() {
|
||||||
|
input.blur();
|
||||||
|
textarea.blur();
|
||||||
|
input.selectionStart = input.selectionEnd = 0;
|
||||||
|
textarea.selectionStart = textarea.selectionEnd = 0;
|
||||||
|
await this.spin();
|
||||||
|
this.input.clear();
|
||||||
|
this.textarea.clear();
|
||||||
|
},
|
||||||
|
spin() {
|
||||||
|
return new Promise(setTimeout);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.selectionStart = 1;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 1);
|
||||||
|
}, "Modifying selectionStart value of the textarea element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.selectionEnd = 1;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 1);
|
||||||
|
}, "Modifying selectionEnd value of the textarea element");
|
||||||
|
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.setSelectionRange(0, 4);
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 1);
|
||||||
|
}, "Calling setSelectionRange on the textarea element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
input.selectionStart = 0;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.input.events.length, 0);
|
||||||
|
}, "Setting initial zero selectionStart value on the input element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
input.selectionEnd = 0;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.input.events.length, 0);
|
||||||
|
}, "Setting initial zero selectionEnd value on the input element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.selectionStart = 0;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 0);
|
||||||
|
}, "Setting initial zero selectionStart value on the textarea element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.selectionStart = 2;
|
||||||
|
textarea.selectionStart = 2;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 1);
|
||||||
|
}, "Setting the same selectionStart value on the textarea element twice");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.selectionEnd = 0;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 0);
|
||||||
|
}, "Setting initial zero selectionEnd value on the textarea element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.selectionEnd = 2;
|
||||||
|
textarea.selectionEnd = 2;
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 1);
|
||||||
|
}, "Setting the same selectionEnd value on the textarea element twice");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.setSelectionRange(0, 0);
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 0);
|
||||||
|
}, "Setting initial zero selection range on the textarea element");
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
await data.initialize();
|
||||||
|
|
||||||
|
textarea.setSelectionRange(3, 3);
|
||||||
|
textarea.setSelectionRange(3, 3);
|
||||||
|
|
||||||
|
await data.spin();
|
||||||
|
assert_equals(data.textarea.events.length, 1);
|
||||||
|
}, "Setting the same selection range on the textarea element twice");
|
||||||
|
</script>
|
||||||
Loading…
Reference in a new issue