diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 9c09940757a9..0402d31aaa50 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -6422,22 +6422,22 @@ HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart, SetSelectionRange(aSelectionStart, aSelectionEnd, direction, aRv); } -Nullable +Nullable HTMLInputElement::GetSelectionStart(ErrorResult& aRv) { if (!SupportsTextSelection()) { - return Nullable(); + return Nullable(); } - int32_t selStart = GetSelectionStartIgnoringType(aRv); + uint32_t selStart = GetSelectionStartIgnoringType(aRv); if (aRv.Failed()) { - return Nullable(); + return Nullable(); } - return Nullable(selStart); + return Nullable(selStart); } -int32_t +uint32_t HTMLInputElement::GetSelectionStartIgnoringType(ErrorResult& aRv) { int32_t selEnd, selStart; @@ -6446,7 +6446,7 @@ HTMLInputElement::GetSelectionStartIgnoringType(ErrorResult& aRv) } void -HTMLInputElement::SetSelectionStart(const Nullable& aSelectionStart, +HTMLInputElement::SetSelectionStart(const Nullable& aSelectionStart, ErrorResult& aRv) { if (!SupportsTextSelection()) { @@ -6454,35 +6454,9 @@ HTMLInputElement::SetSelectionStart(const Nullable& aSelectionStart, return; } - int32_t selStart = 0; - if (!aSelectionStart.IsNull()) { - selStart = aSelectionStart.Value(); - } - nsTextEditorState* state = GetEditorState(); - if (state && state->IsSelectionCached()) { - state->GetSelectionProperties().SetStart(selStart); - return; - } - - nsAutoString direction; - GetSelectionDirection(direction, aRv); - if (aRv.Failed()) { - return; - } - - int32_t start, end; - GetSelectionRange(&start, &end, aRv); - if (aRv.Failed()) { - return; - } - - start = selStart; - if (end < start) { - end = start; - } - - aRv = SetSelectionRange(start, end, direction); + MOZ_ASSERT(state, "SupportsTextSelection() returned true!"); + state->SetSelectionStart(aSelectionStart, aRv); } Nullable diff --git a/dom/html/HTMLInputElement.h b/dom/html/HTMLInputElement.h index e9c46e46a404..2691e6065dd7 100644 --- a/dom/html/HTMLInputElement.h +++ b/dom/html/HTMLInputElement.h @@ -246,7 +246,7 @@ public: // Methods for nsFormFillController so it can do selection operations on input // types the HTML spec doesn't support them on, like "email". - int32_t GetSelectionStartIgnoringType(ErrorResult& aRv); + uint32_t GetSelectionStartIgnoringType(ErrorResult& aRv); int32_t GetSelectionEndIgnoringType(ErrorResult& aRv); void GetDisplayFileName(nsAString& aFileName) const; @@ -717,8 +717,8 @@ public: // XPCOM Select() is OK - Nullable GetSelectionStart(ErrorResult& aRv); - void SetSelectionStart(const Nullable& aValue, ErrorResult& aRv); + Nullable GetSelectionStart(ErrorResult& aRv); + void SetSelectionStart(const Nullable& aValue, ErrorResult& aRv); Nullable GetSelectionEnd(ErrorResult& aRv); void SetSelectionEnd(const Nullable& aValue, ErrorResult& aRv); diff --git a/dom/html/HTMLTextAreaElement.cpp b/dom/html/HTMLTextAreaElement.cpp index 9ad6bf116a20..09e9af380b7e 100644 --- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -710,34 +710,7 @@ void HTMLTextAreaElement::SetSelectionStart(const Nullable& aSelectionStart, ErrorResult& aError) { - int32_t selStart = 0; - if (!aSelectionStart.IsNull()) { - selStart = aSelectionStart.Value(); - } - - if (mState.IsSelectionCached()) { - mState.GetSelectionProperties().SetStart(selStart); - return; - } - - nsAutoString direction; - GetSelectionDirection(direction, aError); - if (aError.Failed()) { - return; - } - int32_t start, end; - GetSelectionRange(&start, &end, aError); - if (aError.Failed()) { - return; - } - start = selStart; - if (end < start) { - end = start; - } - nsresult rv = SetSelectionRange(start, end, direction); - if (NS_FAILED(rv)) { - aError.Throw(rv); - } + mState.SetSelectionStart(aSelectionStart, aError); } Nullable diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index 1bdbe26f330a..8e51853fd4b6 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -1708,6 +1708,35 @@ nsTextEditorState::SetSelectionRange(int32_t aStart, int32_t aEnd, } } +void +nsTextEditorState::SetSelectionStart(const mozilla::dom::Nullable& aStart, + ErrorResult& aRv) +{ + int32_t start = 0; + if (!aStart.IsNull()) { + // XXXbz This will do the wrong thing for input values that are out of the + // int32_t range... + start = aStart.Value(); + } + + int32_t ignored, end; + GetSelectionRange(&ignored, &end, aRv); + if (aRv.Failed()) { + return; + } + + nsITextControlFrame::SelectionDirection dir = GetSelectionDirection(aRv); + if (aRv.Failed()) { + return; + } + + if (end < start) { + end = start; + } + + SetSelectionRange(start, end, dir, aRv); +} + HTMLInputElement* nsTextEditorState::GetParentNumberControl(nsFrame* aFrame) const { diff --git a/dom/html/nsTextEditorState.h b/dom/html/nsTextEditorState.h index 6d41b361fb2a..c26097490485 100644 --- a/dom/html/nsTextEditorState.h +++ b/dom/html/nsTextEditorState.h @@ -15,6 +15,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Maybe.h" #include "mozilla/WeakPtr.h" +#include "mozilla/dom/Nullable.h" class nsTextInputListener; class nsTextControlFrame; @@ -297,6 +298,12 @@ public: nsITextControlFrame::SelectionDirection aDirection, mozilla::ErrorResult& aRv); + // Set the selection start. This basically implements the + // https://html.spec.whatwg.org/multipage/forms.html#dom-textarea/input-selectionstart + // setter. + void SetSelectionStart(const mozilla::dom::Nullable& aStart, + mozilla::ErrorResult& aRv); + void UpdateEditableState(bool aNotify) { if (mRootNode) { mRootNode->UpdateEditableState(aNotify); diff --git a/dom/webidl/HTMLInputElement.webidl b/dom/webidl/HTMLInputElement.webidl index bdfc24ad6264..5f001e68739f 100644 --- a/dom/webidl/HTMLInputElement.webidl +++ b/dom/webidl/HTMLInputElement.webidl @@ -117,8 +117,7 @@ interface HTMLInputElement : HTMLElement { void select(); [Throws] - // TODO: unsigned vs signed - attribute long? selectionStart; + attribute unsigned long? selectionStart; [Throws] attribute long? selectionEnd; [Throws] diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index b77d3c4c02a4..d4debe9920c9 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -93542,6 +93542,12 @@ {} ] ], + "html/semantics/forms/textfieldselection/selection-start-end.html": [ + [ + "/html/semantics/forms/textfieldselection/selection-start-end.html", + {} + ] + ], "html/semantics/forms/textfieldselection/selection.html": [ [ "/html/semantics/forms/textfieldselection/selection.html", @@ -176663,12 +176669,16 @@ "39ecb031aca3655a06152f94a514981fe59ebbaf", "testharness" ], + "html/semantics/forms/textfieldselection/selection-start-end.html": [ + "1f3184b72aba5631d6db4379dfa98035ee047283", + "testharness" + ], "html/semantics/forms/textfieldselection/selection.html": [ - "d869799718137671a2eacc323aa26ea4364e845f", + "f7674721b84ec8fca0e5e40258447ce857b87784", "testharness" ], "html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html": [ - "0caf2b08ccc5a35578291af8f5adaf7de9537d66", + "3bbd350321f5ec9e0a8f3d47da4e11aaa3ad4d68", "testharness" ], "html/semantics/forms/textfieldselection/textfieldselection-setSelectionRange.html": [ diff --git a/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html b/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html new file mode 100644 index 000000000000..49b598ec8dfc --- /dev/null +++ b/testing/web-platform/tests/html/semantics/forms/textfieldselection/selection-start-end.html @@ -0,0 +1,68 @@ + + + + + +
+ diff --git a/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html b/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html index cb0afb17d734..4b586cc10785 100644 --- a/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html +++ b/testing/web-platform/tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html @@ -106,15 +106,23 @@ }, element.id + " setRangeText without argument throws a type error"); async_test(function() { - var q = false; - element.onselect = this.step_func_done(function(e) { - assert_true(q, "event should be queued"); - assert_true(e.isTrusted, "event is trusted"); - assert_true(e.bubbles, "event bubbles"); - assert_false(e.cancelable, "event is not cancelable"); - }); - element.setRangeText("foobar2", 0, 6); - q = true; + // At this point there are already "select" events queued up on + // "element". Give them time to fire; otherwise we can get spurious + // passes. + // + // This is unfortunately racy in that we might _still_ get spurious + // passes. I'm not sure how best to handle that. + setTimeout(this.step_func(function() { + var q = false; + element.onselect = this.step_func_done(function(e) { + assert_true(q, "event should be queued"); + assert_true(e.isTrusted, "event is trusted"); + assert_true(e.bubbles, "event bubbles"); + assert_false(e.cancelable, "event is not cancelable"); + }); + element.setRangeText("foobar2", 0, 6); + q = true; + }), 10); }, element.id + " setRangeText fires a select event"); })