Skip to content

Commit

Permalink
Extract common text control selection code
Browse files Browse the repository at this point in the history
The API for text control selection is the same for both <input> and
<textarea>:

https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#textFieldSelection

Before this change, they had similar but not identical implementations
with duplicate code. Now there is a common TextControl trait which
contains the implementation used by both. As a result, some previously
failing tests now pass.
  • Loading branch information
jonleighton committed Nov 18, 2017
1 parent f290cac commit 6beda3c
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 91 deletions.
50 changes: 15 additions & 35 deletions components/script/dom/htmlinputelement.rs
Expand Up @@ -31,6 +31,7 @@ use dom::mouseevent::MouseEvent;
use dom::node::{Node, NodeDamage, UnbindContext};
use dom::node::{document_from_node, window_from_node};
use dom::nodelist::NodeList;
use dom::textcontrol::TextControl;
use dom::validation::Validatable;
use dom::validitystate::ValidationFlags;
use dom::virtualmethods::VirtualMethods;
Expand Down Expand Up @@ -292,6 +293,12 @@ impl LayoutHTMLInputElementHelpers for LayoutDom<HTMLInputElement> {
}
}

impl TextControl for HTMLInputElement {
fn textinput(&self) -> &DomRefCell<TextInput<ScriptToConstellationChan>> {
&self.textinput
}
}

impl HTMLInputElementMethods for HTMLInputElement {
// https://html.spec.whatwg.org/multipage/#dom-input-accept
make_getter!(Accept, "accept");
Expand Down Expand Up @@ -567,42 +574,39 @@ impl HTMLInputElementMethods for HTMLInputElement {
}
}

// https://html.spec.whatwg.org/multipage/#dom-input-selectionstart
// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn SelectionStart(&self) -> u32 {
self.textinput.borrow().get_selection_start()
self.dom_selection_start()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn SetSelectionStart(&self, start: u32) {
self.set_selection_range(start, self.SelectionEnd(), self.selection_direction());
self.set_dom_selection_start(start);
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend
fn SelectionEnd(&self) -> u32 {
self.textinput.borrow().get_absolute_insertion_point() as u32
self.dom_selection_end()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend
fn SetSelectionEnd(&self, end: u32) {
self.set_selection_range(self.SelectionStart(), end, self.selection_direction());
self.set_dom_selection_end(end)
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn SelectionDirection(&self) -> DOMString {
DOMString::from(self.textinput.borrow().selection_direction)
self.dom_selection_direction()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn SetSelectionDirection(&self, direction: DOMString) {
self.textinput.borrow_mut().selection_direction = SelectionDirection::from(direction);
self.set_dom_selection_direction(direction);
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange
fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) {
// Step 4
let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d));

self.set_selection_range(start, end, direction);
self.set_dom_selection_range(start, end, direction);
}

// Select the files based on filepaths passed in,
Expand Down Expand Up @@ -875,30 +879,6 @@ impl HTMLInputElement {
_ => ()
}
}

fn selection_direction(&self) -> SelectionDirection {
self.textinput.borrow().selection_direction
}

// https://html.spec.whatwg.org/multipage/#set-the-selection-range
fn set_selection_range(&self, start: u32, end: u32, direction: SelectionDirection) {
// Step 5
self.textinput.borrow_mut().selection_direction = direction;

// Step 3
self.textinput.borrow_mut().set_selection_range(start, end);

// Step 6
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window);

self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}

impl VirtualMethods for HTMLInputElement {
Expand Down
55 changes: 24 additions & 31 deletions components/script/dom/htmltextareaelement.rs
Expand Up @@ -23,6 +23,7 @@ use dom::keyboardevent::KeyboardEvent;
use dom::node::{ChildrenMutation, Node, NodeDamage, UnbindContext};
use dom::node::{document_from_node, window_from_node};
use dom::nodelist::NodeList;
use dom::textcontrol::TextControl;
use dom::validation::Validatable;
use dom::virtualmethods::VirtualMethods;
use dom_struct::dom_struct;
Expand Down Expand Up @@ -140,6 +141,12 @@ impl HTMLTextAreaElement {
}
}

impl TextControl for HTMLTextAreaElement {
fn textinput(&self) -> &DomRefCell<TextInput<ScriptToConstellationChan>> {
&self.textinput
}
}

impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
// TODO A few of these attributes have default values and additional
// constraints
Expand Down Expand Up @@ -237,53 +244,39 @@ impl HTMLTextAreaElementMethods for HTMLTextAreaElement {
self.upcast::<HTMLElement>().labels()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn SetSelectionDirection(&self, direction: DOMString) {
self.textinput.borrow_mut().selection_direction = SelectionDirection::from(direction);
// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn SelectionStart(&self) -> u32 {
self.dom_selection_start()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn SelectionDirection(&self) -> DOMString {
DOMString::from(self.textinput.borrow().selection_direction)
// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn SetSelectionStart(&self, start: u32) {
self.set_dom_selection_start(start);
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend
fn SetSelectionEnd(&self, end: u32) {
let selection_start = self.SelectionStart();
self.textinput.borrow_mut().set_selection_range(selection_start, end);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
fn SelectionEnd(&self) -> u32 {
self.dom_selection_end()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend
fn SelectionEnd(&self) -> u32 {
self.textinput.borrow().get_absolute_insertion_point() as u32
fn SetSelectionEnd(&self, end: u32) {
self.set_dom_selection_end(end);
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn SetSelectionStart(&self, start: u32) {
let selection_end = self.SelectionEnd();
self.textinput.borrow_mut().set_selection_range(start, selection_end);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn SelectionDirection(&self) -> DOMString {
self.dom_selection_direction()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn SelectionStart(&self) -> u32 {
self.textinput.borrow().get_selection_start()
// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn SetSelectionDirection(&self, direction: DOMString) {
self.set_dom_selection_direction(direction);
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange
fn SetSelectionRange(&self, start: u32, end: u32, direction: Option<DOMString>) {
let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d));
self.textinput.borrow_mut().selection_direction = direction;
self.textinput.borrow_mut().set_selection_range(start, end);
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window);
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
self.set_dom_selection_range(start, end, direction);
}
}

Expand Down
1 change: 1 addition & 0 deletions components/script/dom/mod.rs
Expand Up @@ -439,6 +439,7 @@ pub mod testrunner;
pub mod testworklet;
pub mod testworkletglobalscope;
pub mod text;
pub mod textcontrol;
pub mod textdecoder;
pub mod textencoder;
pub mod touch;
Expand Down
78 changes: 78 additions & 0 deletions components/script/dom/textcontrol.rs
@@ -0,0 +1,78 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DomRefCell;
use dom::bindings::conversions::DerivedFrom;
use dom::bindings::str::DOMString;
use dom::event::{EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::node::{Node, NodeDamage, window_from_node};
use script_traits::ScriptToConstellationChan;
use textinput::{SelectionDirection, TextInput};

pub trait TextControl: DerivedFrom<EventTarget> + DerivedFrom<Node> {
fn textinput(&self) -> &DomRefCell<TextInput<ScriptToConstellationChan>>;

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn dom_selection_start(&self) -> u32 {
self.textinput().borrow().get_selection_start()
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionstart
fn set_dom_selection_start(&self, start: u32) {
self.set_selection_range(start, self.dom_selection_end(), self.selection_direction());
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend
fn dom_selection_end(&self) -> u32 {
self.textinput().borrow().get_absolute_insertion_point() as u32
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectionend
fn set_dom_selection_end(&self, end: u32) {
self.set_selection_range(self.dom_selection_start(), end, self.selection_direction());
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn dom_selection_direction(&self) -> DOMString {
DOMString::from(self.selection_direction())
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-selectiondirection
fn set_dom_selection_direction(&self, direction: DOMString) {
self.textinput().borrow_mut().selection_direction = SelectionDirection::from(direction);
}

// https://html.spec.whatwg.org/multipage/#dom-textarea/input-setselectionrange
fn set_dom_selection_range(&self, start: u32, end: u32, direction: Option<DOMString>) {
// Step 4
let direction = direction.map_or(SelectionDirection::None, |d| SelectionDirection::from(d));

self.set_selection_range(start, end, direction);
}

fn selection_direction(&self) -> SelectionDirection {
self.textinput().borrow().selection_direction
}

// https://html.spec.whatwg.org/multipage/#set-the-selection-range
fn set_selection_range(&self, start: u32, end: u32, direction: SelectionDirection) {
// Step 5
self.textinput().borrow_mut().selection_direction = direction;

// Step 3
self.textinput().borrow_mut().set_selection_range(start, end);

// Step 6
let window = window_from_node(self);
let _ = window.user_interaction_task_source().queue_event(
&self.upcast::<EventTarget>(),
atom!("select"),
EventBubbles::Bubbles,
EventCancelable::NotCancelable,
&window);

self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
}
}
@@ -1,6 +1,5 @@
[selection-start-end.html]
type: testharness
expected: TIMEOUT
[Setting selectionStart to a value larger than selectionEnd should increase selectionEnd]
expected: FAIL

Expand All @@ -22,30 +21,6 @@
[Initial .value set on textarea-not-appended-prefocused should set selectionStart to end of value]
expected: FAIL

[onselect should fire when selectionStart is changed on textarea-appended]
expected: NOTRUN

[onselect should fire when selectionStart is changed on textarea-not-appended]
expected: NOTRUN

[onselect should fire when selectionStart is changed on textarea-appended-prefocused]
expected: NOTRUN

[onselect should fire when selectionStart is changed on textarea-not-appended-prefocused]
expected: NOTRUN

[onselect should fire when selectionEnd is changed on textarea-appended]
expected: NOTRUN

[onselect should fire when selectionEnd is changed on textarea-not-appended]
expected: NOTRUN

[onselect should fire when selectionEnd is changed on textarea-appended-prefocused]
expected: NOTRUN

[onselect should fire when selectionEnd is changed on textarea-not-appended-prefocused]
expected: NOTRUN

[Initial .value set on textarea-appended should set selectionEnd to end of value]
expected: FAIL

Expand Down

0 comments on commit 6beda3c

Please sign in to comment.