Bug 1343037 part 13. Implement nsTextEditorState::SetSelectionEnd. r=ehsan

This introduces three behavior changes:

1)  Before this change, in cached mode, we did not enforce the "start <= end"
    invariant.
2)  Before this change, in cached mode, we did not fire "select" events on
    selectionEnd changes.
3)  Changes the IDL type of HTMLInputElement's selectionEnd attribute to
    "unsigned long" to match the spec and HTMLTextareaElement.

MozReview-Commit-ID: J3Gkhr8VnbS
This commit is contained in:
Boris Zbarsky 2017-03-09 14:44:05 -05:00
Родитель badbeff5ec
Коммит e0ef9813e4
7 изменённых файлов: 72 добавлений и 67 удалений

Просмотреть файл

@ -6459,22 +6459,22 @@ HTMLInputElement::SetSelectionStart(const Nullable<uint32_t>& aSelectionStart,
state->SetSelectionStart(aSelectionStart, aRv);
}
Nullable<int32_t>
Nullable<uint32_t>
HTMLInputElement::GetSelectionEnd(ErrorResult& aRv)
{
if (!SupportsTextSelection()) {
return Nullable<int32_t>();
return Nullable<uint32_t>();
}
int32_t selEnd = GetSelectionEndIgnoringType(aRv);
uint32_t selEnd = GetSelectionEndIgnoringType(aRv);
if (aRv.Failed()) {
return Nullable<int32_t>();
return Nullable<uint32_t>();
}
return Nullable<int32_t>(selEnd);
return Nullable<uint32_t>(selEnd);
}
int32_t
uint32_t
HTMLInputElement::GetSelectionEndIgnoringType(ErrorResult& aRv)
{
int32_t selEnd, selStart;
@ -6483,7 +6483,7 @@ HTMLInputElement::GetSelectionEndIgnoringType(ErrorResult& aRv)
}
void
HTMLInputElement::SetSelectionEnd(const Nullable<int32_t>& aSelectionEnd,
HTMLInputElement::SetSelectionEnd(const Nullable<uint32_t>& aSelectionEnd,
ErrorResult& aRv)
{
if (!SupportsTextSelection()) {
@ -6491,35 +6491,9 @@ HTMLInputElement::SetSelectionEnd(const Nullable<int32_t>& aSelectionEnd,
return;
}
int32_t selEnd = 0;
if (!aSelectionEnd.IsNull()) {
selEnd = aSelectionEnd.Value();
}
nsTextEditorState* state = GetEditorState();
if (state && state->IsSelectionCached()) {
state->GetSelectionProperties().SetEnd(selEnd);
return;
}
nsAutoString direction;
GetSelectionDirection(direction, aRv);
if (aRv.Failed()) {
return;
}
int32_t start, end;
GetSelectionRange(&start, &end, aRv);
if (aRv.Failed()) {
return;
}
end = selEnd;
if (start > end) {
start = end;
}
aRv = SetSelectionRange(start, end, direction);
MOZ_ASSERT(state, "SupportsTextSelection() returned true!");
state->SetSelectionEnd(aSelectionEnd, aRv);
}
NS_IMETHODIMP

Просмотреть файл

@ -247,7 +247,7 @@ public:
// Methods for nsFormFillController so it can do selection operations on input
// types the HTML spec doesn't support them on, like "email".
uint32_t GetSelectionStartIgnoringType(ErrorResult& aRv);
int32_t GetSelectionEndIgnoringType(ErrorResult& aRv);
uint32_t GetSelectionEndIgnoringType(ErrorResult& aRv);
void GetDisplayFileName(nsAString& aFileName) const;
@ -720,8 +720,8 @@ public:
Nullable<uint32_t> GetSelectionStart(ErrorResult& aRv);
void SetSelectionStart(const Nullable<uint32_t>& aValue, ErrorResult& aRv);
Nullable<int32_t> GetSelectionEnd(ErrorResult& aRv);
void SetSelectionEnd(const Nullable<int32_t>& aValue, ErrorResult& aRv);
Nullable<uint32_t> GetSelectionEnd(ErrorResult& aRv);
void SetSelectionEnd(const Nullable<uint32_t>& aValue, ErrorResult& aRv);
void GetSelectionDirection(nsAString& aValue, ErrorResult& aRv);
void SetSelectionDirection(const nsAString& aValue, ErrorResult& aRv);

Просмотреть файл

@ -725,34 +725,7 @@ void
HTMLTextAreaElement::SetSelectionEnd(const Nullable<uint32_t>& aSelectionEnd,
ErrorResult& aError)
{
int32_t selEnd = 0;
if (!aSelectionEnd.IsNull()) {
selEnd = aSelectionEnd.Value();
}
if (mState.IsSelectionCached()) {
mState.GetSelectionProperties().SetEnd(selEnd);
return;
}
nsAutoString direction;
GetSelectionDirection(direction, aError);
if (aError.Failed()) {
return;
}
int32_t start, end;
GetSelectionRange(&start, &end, aError);
if (aError.Failed()) {
return;
}
end = selEnd;
if (start > end) {
start = end;
}
nsresult rv = SetSelectionRange(start, end, direction);
if (NS_FAILED(rv)) {
aError.Throw(rv);
}
mState.SetSelectionEnd(aSelectionEnd, aError);
}
void

Просмотреть файл

@ -1737,6 +1737,31 @@ nsTextEditorState::SetSelectionStart(const mozilla::dom::Nullable<uint32_t>& aSt
SetSelectionRange(start, end, dir, aRv);
}
void
nsTextEditorState::SetSelectionEnd(const mozilla::dom::Nullable<uint32_t>& aEnd,
ErrorResult& aRv)
{
int32_t end = 0;
if (!aEnd.IsNull()) {
// XXXbz This will do the wrong thing for input values that are out of the
// int32_t range...
end = aEnd.Value();
}
int32_t start, ignored;
GetSelectionRange(&start, &ignored, aRv);
if (aRv.Failed()) {
return;
}
nsITextControlFrame::SelectionDirection dir = GetSelectionDirection(aRv);
if (aRv.Failed()) {
return;
}
SetSelectionRange(start, end, dir, aRv);
}
HTMLInputElement*
nsTextEditorState::GetParentNumberControl(nsFrame* aFrame) const
{

Просмотреть файл

@ -304,6 +304,12 @@ public:
void SetSelectionStart(const mozilla::dom::Nullable<uint32_t>& aStart,
mozilla::ErrorResult& aRv);
// Set the selection end. This basically implements the
// https://html.spec.whatwg.org/multipage/forms.html#dom-textarea/input-selectionend
// setter.
void SetSelectionEnd(const mozilla::dom::Nullable<uint32_t>& aEnd,
mozilla::ErrorResult& aRv);
void UpdateEditableState(bool aNotify) {
if (mRootNode) {
mRootNode->UpdateEditableState(aNotify);

Просмотреть файл

@ -119,7 +119,7 @@ interface HTMLInputElement : HTMLElement {
[Throws]
attribute unsigned long? selectionStart;
[Throws]
attribute long? selectionEnd;
attribute unsigned long? selectionEnd;
[Throws]
attribute DOMString? selectionDirection;
[Throws]

Просмотреть файл

@ -53,6 +53,19 @@
}
}, "onselect should fire when selectionStart is changed");
test(function() {
for (let el of createTestElements(testValue)) {
assert_equals(el.selectionEnd, testValue.length,
`Initial .value set on ${el.id} should set selectionEnd to end of value`);
var t = async_test(`onselect should fire when selectionEnd is changed on ${el.id}`);
el.onselect = t.step_func_done(function(e) {
assert_equals(e.type, "select");
el.remove();
});
el.selectionEnd = 2;
}
}, "onselect should fire when selectionEnd is changed");
test(function() {
for (let el of createTestElements(testValue)) {
assert_equals(el.selectionStart, testValue.length,
@ -65,4 +78,18 @@
el.remove();
}
}, "Setting selectionStart to a value larger than selectionEnd should increase selectionEnd");
test(function() {
for (let el of createTestElements(testValue)) {
assert_equals(el.selectionStart, testValue.length,
`Initial .value set on ${el.id} should set selectionStart to end of value`);
assert_equals(el.selectionEnd, testValue.length,
`Initial .value set on ${el.id} should set selectionEnd to end of value`);
el.selectionStart = 8;
el.selectionEnd = 5;
assert_equals(el.selectionStart, 5, `selectionStart on ${el.id}`);
assert_equals(el.selectionEnd, 5, `selectionEnd on ${el.id}`);
el.remove();
}
}, "Setting selectionEnd to a value smaller than selectionStart should decrease selectionStart");
</script>