mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Implements multi line text input for TextArea
This commit is contained in:
parent
fd65b5f438
commit
29241699fd
6 changed files with 115 additions and 11 deletions
|
@ -49,6 +49,7 @@ use script::dom::element::{HTMLObjectElementTypeId, HTMLInputElementTypeId};
|
|||
use script::dom::element::{HTMLTableColElementTypeId, HTMLTableDataCellElementTypeId};
|
||||
use script::dom::element::{HTMLTableElementTypeId, HTMLTableHeaderCellElementTypeId};
|
||||
use script::dom::element::{HTMLTableRowElementTypeId, HTMLTableSectionElementTypeId};
|
||||
use script::dom::element::HTMLTextAreaElementTypeId;
|
||||
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
|
||||
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId};
|
||||
use script::dom::node::{TextNodeTypeId};
|
||||
|
@ -273,7 +274,8 @@ impl<'a> FlowConstructor<'a> {
|
|||
TableColumnFragment(TableColumnFragmentInfo::new(node))
|
||||
}
|
||||
Some(ElementNodeTypeId(HTMLTableDataCellElementTypeId)) |
|
||||
Some(ElementNodeTypeId(HTMLTableHeaderCellElementTypeId)) => TableCellFragment,
|
||||
Some(ElementNodeTypeId(HTMLTableHeaderCellElementTypeId)) |
|
||||
Some(ElementNodeTypeId(HTMLTextAreaElementTypeId)) => TableCellFragment,
|
||||
Some(ElementNodeTypeId(HTMLTableRowElementTypeId)) |
|
||||
Some(ElementNodeTypeId(HTMLTableSectionElementTypeId)) => TableRowFragment,
|
||||
Some(TextNodeTypeId) => UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)),
|
||||
|
@ -487,7 +489,16 @@ impl<'a> FlowConstructor<'a> {
|
|||
// Special case: If this is generated content, then we need to initialize the accumulator
|
||||
// with the fragment corresponding to that content.
|
||||
if node.get_pseudo_element_type() != Normal ||
|
||||
node.type_id() == Some(ElementNodeTypeId(HTMLInputElementTypeId)) {
|
||||
node.type_id() == Some(ElementNodeTypeId(HTMLInputElementTypeId)) ||
|
||||
node.type_id() == Some(ElementNodeTypeId(HTMLTextAreaElementTypeId)) {
|
||||
// A TextArea's text contents are displayed through the input text
|
||||
// box, so don't construct them.
|
||||
// TODO Maybe this belongs somewhere else?
|
||||
if node.type_id() == Some(ElementNodeTypeId(HTMLTextAreaElementTypeId)) {
|
||||
for kid in node.children() {
|
||||
kid.set_flow_construction_result(NoConstructionResult)
|
||||
}
|
||||
}
|
||||
let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::new(node));
|
||||
let fragment = Fragment::new_from_specific_info(node, fragment_info);
|
||||
inline_fragment_accumulator.fragments.push_back(fragment);
|
||||
|
|
|
@ -39,13 +39,14 @@ use util::{PrivateLayoutData};
|
|||
use gfx::display_list::OpaqueNode;
|
||||
use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast};
|
||||
use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementCast, HTMLInputElementCast};
|
||||
use script::dom::bindings::codegen::InheritTypes::{NodeCast, TextCast};
|
||||
use script::dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementCast, NodeCast, TextCast};
|
||||
use script::dom::bindings::js::JS;
|
||||
use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId};
|
||||
use script::dom::element::{HTMLLinkElementTypeId, LayoutElementHelpers, RawLayoutElementHelpers};
|
||||
use script::dom::htmliframeelement::HTMLIFrameElement;
|
||||
use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
|
||||
use script::dom::htmlinputelement::LayoutHTMLInputElementHelpers;
|
||||
use script::dom::htmltextareaelement::LayoutHTMLTextAreaElementHelpers;
|
||||
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId};
|
||||
use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, SharedLayoutData};
|
||||
use script::dom::node::{HAS_CHANGED, IS_DIRTY, HAS_DIRTY_SIBLINGS, HAS_DIRTY_DESCENDANTS};
|
||||
|
@ -188,7 +189,10 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> {
|
|||
Some(text) => (*text.unsafe_get()).characterdata().data_for_layout().to_string(),
|
||||
None => match HTMLInputElementCast::to_js(self.get_jsmanaged()) {
|
||||
Some(input) => input.get_value_for_layout(),
|
||||
None => panic!("not text!")
|
||||
None => match HTMLTextAreaElementCast::to_js(self.get_jsmanaged()) {
|
||||
Some(area) => area.get_value_for_layout(),
|
||||
None => panic!("not text!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,18 +4,24 @@
|
|||
|
||||
use dom::attr::Attr;
|
||||
use dom::attr::AttrHelpers;
|
||||
use dom::bindings::cell::DOMRefCell;
|
||||
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
|
||||
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding;
|
||||
use dom::bindings::codegen::Bindings::HTMLTextAreaElementBinding::HTMLTextAreaElementMethods;
|
||||
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, NodeCast};
|
||||
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
|
||||
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast, NodeCast};
|
||||
use dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementDerived, HTMLFieldSetElementDerived};
|
||||
use dom::bindings::js::{JSRef, Temporary};
|
||||
use dom::bindings::codegen::InheritTypes::{KeyboardEventCast, TextDerived};
|
||||
use dom::bindings::js::{JS, JSRef, Temporary};
|
||||
use dom::bindings::utils::{Reflectable, Reflector};
|
||||
use dom::document::Document;
|
||||
use dom::document::{Document, DocumentHelpers};
|
||||
use dom::element::{AttributeHandlers, HTMLTextAreaElementTypeId};
|
||||
use dom::event::Event;
|
||||
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
|
||||
use dom::htmlelement::HTMLElement;
|
||||
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId};
|
||||
use dom::keyboardevent::KeyboardEvent;
|
||||
use dom::node::{DisabledStateHelpers, Node, NodeHelpers, ElementNodeTypeId, document_from_node};
|
||||
use textinput::{Multiple, TextInput, TriggerDefaultAction, DispatchInput, Nothing};
|
||||
use dom::virtualmethods::VirtualMethods;
|
||||
|
||||
use servo_util::str::DOMString;
|
||||
|
@ -24,6 +30,7 @@ use string_cache::Atom;
|
|||
#[dom_struct]
|
||||
pub struct HTMLTextAreaElement {
|
||||
htmlelement: HTMLElement,
|
||||
textinput: DOMRefCell<TextInput>,
|
||||
}
|
||||
|
||||
impl HTMLTextAreaElementDerived for EventTarget {
|
||||
|
@ -32,10 +39,22 @@ impl HTMLTextAreaElementDerived for EventTarget {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait LayoutHTMLTextAreaElementHelpers {
|
||||
unsafe fn get_value_for_layout(self) -> String;
|
||||
}
|
||||
|
||||
impl LayoutHTMLTextAreaElementHelpers for JS<HTMLTextAreaElement> {
|
||||
#[allow(unrooted_must_root)]
|
||||
unsafe fn get_value_for_layout(self) -> String {
|
||||
(*self.unsafe_get()).textinput.borrow_for_layout().get_content()
|
||||
}
|
||||
}
|
||||
|
||||
impl HTMLTextAreaElement {
|
||||
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLTextAreaElement {
|
||||
HTMLTextAreaElement {
|
||||
htmlelement: HTMLElement::new_inherited(HTMLTextAreaElementTypeId, localName, prefix, document)
|
||||
htmlelement: HTMLElement::new_inherited(HTMLTextAreaElementTypeId, localName, prefix, document),
|
||||
textinput: DOMRefCell::new(TextInput::new(Multiple, "".to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +127,28 @@ impl<'a> HTMLTextAreaElementMethods for JSRef<'a, HTMLTextAreaElement> {
|
|||
let node: JSRef<Node> = NodeCast::from_ref(self);
|
||||
node.SetTextContent(Some(value))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-value
|
||||
fn Value(self) -> DOMString {
|
||||
self.textinput.borrow().get_content()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-value
|
||||
fn SetValue(self, value: DOMString) {
|
||||
self.textinput.borrow_mut().set_content(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait HTMLTextAreaElementHelpers {
|
||||
fn force_relayout(self);
|
||||
}
|
||||
|
||||
impl<'a> HTMLTextAreaElementHelpers for JSRef<'a, HTMLTextAreaElement> {
|
||||
fn force_relayout(self) {
|
||||
let doc = document_from_node(self).root();
|
||||
let node: JSRef<Node> = NodeCast::from_ref(self);
|
||||
doc.content_changed(node)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> {
|
||||
|
@ -172,6 +213,47 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLTextAreaElement> {
|
|||
node.check_disabled_attribute();
|
||||
}
|
||||
}
|
||||
|
||||
fn child_inserted(&self, child: JSRef<Node>) {
|
||||
match self.super_type() {
|
||||
Some(s) => {
|
||||
s.child_inserted(child);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if child.is_text() {
|
||||
self.SetValue(child.GetTextContent().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
// copied and modified from htmlinputelement.rs
|
||||
fn handle_event(&self, event: JSRef<Event>) {
|
||||
match self.super_type() {
|
||||
Some(s) => {
|
||||
s.handle_event(event);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
if "click" == event.Type().as_slice() && !event.DefaultPrevented() {
|
||||
//TODO: set the editing position for text inputs
|
||||
|
||||
let doc = document_from_node(*self).root();
|
||||
doc.request_focus(ElementCast::from_ref(*self));
|
||||
} else if "keydown" == event.Type().as_slice() && !event.DefaultPrevented() {
|
||||
let keyevent: Option<JSRef<KeyboardEvent>> = KeyboardEventCast::to_ref(event);
|
||||
keyevent.map(|event| {
|
||||
match self.textinput.borrow_mut().handle_keydown(event) {
|
||||
TriggerDefaultAction => (),
|
||||
DispatchInput => {
|
||||
self.force_relayout();
|
||||
}
|
||||
Nothing => (),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reflectable for HTMLTextAreaElement {
|
||||
|
|
|
@ -23,7 +23,7 @@ interface HTMLTextAreaElement : HTMLElement {
|
|||
|
||||
readonly attribute DOMString type;
|
||||
attribute DOMString defaultValue;
|
||||
//[TreatNullAs=EmptyString] attribute DOMString value;
|
||||
[TreatNullAs=EmptyString] attribute DOMString value;
|
||||
//readonly attribute unsigned long textLength;
|
||||
|
||||
//readonly attribute boolean willValidate;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
input, select { display: inline-block; }
|
||||
input, textarea, select { display: inline-block; }
|
||||
input { background: white; min-height: 1.0em; padding: 0em; padding-left: 0.25em; padding-right: 0.25em; border: solid lightgrey 1px; color: black; white-space: nowrap; }
|
||||
textarea { background: white; min-height: 1.0em; padding: 0em; padding-left: 0.25em; padding-right: 0.25em; border: solid lightgrey 1px; color: black; white-space: pre; }
|
||||
input[type="button"],
|
||||
input[type="submit"],
|
||||
input[type="reset"] { background: lightgrey; border-top: solid 1px #EEEEEE; border-left: solid 1px #CCCCCC; border-right: solid 1px #999999; border-bottom: solid 1px #999999; text-align: center; vertical-align: middle; color: black; width: 100%; }
|
||||
|
|
6
tests/html/textarea.html
Normal file
6
tests/html/textarea.html
Normal file
|
@ -0,0 +1,6 @@
|
|||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<textarea name="textarea">Write something here
|
||||
and maybe here</textarea>
|
||||
</body>
|
Loading…
Add table
Add a link
Reference in a new issue