Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements basic form resetting #4133

Merged
merged 12 commits into from Dec 16, 2014
@@ -562,6 +562,13 @@ impl<'le> TElement<'le> for LayoutElement<'le> {
}
}

#[inline]
fn get_indeterminate_state(self) -> bool {
unsafe {
self.element.get_indeterminate_state_for_layout()
}
}

#[inline]
fn has_class(self, name: &Atom) -> bool {
unsafe {
@@ -35,7 +35,7 @@ use dom::event::Event;
use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers};
use dom::htmlbodyelement::{HTMLBodyElement, HTMLBodyElementHelpers};
use dom::htmlcollection::HTMLCollection;
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers};
use dom::htmlinputelement::{HTMLInputElement, RawLayoutHTMLInputElementHelpers, HTMLInputElementHelpers};
use dom::htmlserializer::serialize;
use dom::htmltableelement::{HTMLTableElement, HTMLTableElementHelpers};
use dom::htmltablecellelement::{HTMLTableCellElement, HTMLTableCellElementHelpers};
@@ -211,6 +211,7 @@ pub trait RawLayoutElementHelpers {
unsafe fn get_integer_attribute_for_layout(&self, integer_attribute: IntegerAttribute)
-> Option<i32>;
unsafe fn get_checked_state_for_layout(&self) -> bool;
unsafe fn get_indeterminate_state_for_layout(&self) -> bool;
unsafe fn get_unsigned_integer_attribute_for_layout(&self, attribute: UnsignedIntegerAttribute)
-> Option<u32>;
unsafe fn get_simple_color_attribute_for_layout(&self, attribute: SimpleColorAttribute)
@@ -337,6 +338,18 @@ impl RawLayoutElementHelpers for Element {
this.get_checked_state_for_layout()
}

#[inline]
#[allow(unrooted_must_root)]
unsafe fn get_indeterminate_state_for_layout(&self) -> bool {
// TODO progress elements can also be matched with :indeterminate
if !self.is_htmlinputelement() {
return false
}
let this: &HTMLInputElement = mem::transmute(self);
this.get_indeterminate_state_for_layout()
}


unsafe fn get_unsigned_integer_attribute_for_layout(&self,
attribute: UnsignedIntegerAttribute)
-> Option<u32> {
@@ -1274,6 +1287,12 @@ impl<'a> style::TElement<'a> for JSRef<'a, Element> {
None => false,
}
}
fn get_indeterminate_state(self) -> bool {
match HTMLInputElementCast::to_ref(self) {
Some(input) => input.get_indeterminate_state(),
None => false,
}
}
fn has_class(self, name: &Atom) -> bool {
// FIXME(zwarich): Remove this when UFCS lands and there is a better way
// of disambiguating methods.
@@ -2,23 +2,26 @@
* 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::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods;
use dom::bindings::codegen::Bindings::HTMLFormElementBinding;
use dom::bindings::codegen::Bindings::HTMLFormElementBinding::HTMLFormElementMethods;
use dom::bindings::codegen::Bindings::HTMLInputElementBinding::HTMLInputElementMethods;
use dom::bindings::codegen::InheritTypes::{EventTargetCast, HTMLFormElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::HTMLInputElementCast;
use dom::bindings::codegen::InheritTypes::{HTMLInputElementCast, HTMLTextAreaElementCast, HTMLFormElementCast};
use dom::bindings::global::Window;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::{Document, DocumentHelpers};
use dom::element::{Element, AttributeHandlers, HTMLFormElementTypeId, HTMLTextAreaElementTypeId, HTMLDataListElementTypeId};
use dom::element::{HTMLInputElementTypeId, HTMLButtonElementTypeId, HTMLObjectElementTypeId, HTMLSelectElementTypeId};
use dom::element::{HTMLOutputElementTypeId};
use dom::event::{Event, EventHelpers, Bubbles, Cancelable};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::htmlinputelement::HTMLInputElement;
use dom::htmltextareaelement::HTMLTextAreaElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, document_from_node, window_from_node};
use hyper::method::Post;
use servo_msg::constellation_msg::LoadData;
@@ -29,9 +32,12 @@ use url::UrlParser;
use url::form_urlencoded::serialize;
use string_cache::Atom;

use std::cell::Cell;

#[dom_struct]
pub struct HTMLFormElement {
htmlelement: HTMLElement,
marked_for_reset: Cell<bool>,
}

impl HTMLFormElementDerived for EventTarget {
@@ -43,7 +49,8 @@ impl HTMLFormElementDerived for EventTarget {
impl HTMLFormElement {
fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLFormElement {
HTMLFormElement {
htmlelement: HTMLElement::new_inherited(HTMLFormElementTypeId, localName, prefix, document)
htmlelement: HTMLElement::new_inherited(HTMLFormElementTypeId, localName, prefix, document),
marked_for_reset: Cell::new(false),
}
}

@@ -117,18 +124,30 @@ impl<'a> HTMLFormElementMethods for JSRef<'a, HTMLFormElement> {
fn Submit(self) {
self.submit(FromFormSubmitMethod, FormElement(self));
}

// https://html.spec.whatwg.org/multipage/forms.html#dom-form-reset
fn Reset(self) {
self.reset(FromFormResetMethod);
}
}

pub enum SubmittedFrom {
FromFormSubmitMethod,
NotFromFormSubmitMethod
}

pub enum ResetFrom {
FromFormResetMethod,
NotFromFormResetMethod
}

pub trait HTMLFormElementHelpers {
// https://html.spec.whatwg.org/multipage/forms.html#concept-form-submit
fn submit(self, submit_method_flag: SubmittedFrom, submitter: FormSubmitter);
// https://html.spec.whatwg.org/multipage/forms.html#constructing-the-form-data-set
fn get_form_dataset(self, submitter: Option<FormSubmitter>) -> Vec<FormDatum>;
// https://html.spec.whatwg.org/multipage/forms.html#dom-form-reset
fn reset(self, submit_method_flag: ResetFrom);
}

impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> {
@@ -316,6 +335,59 @@ impl<'a> HTMLFormElementHelpers for JSRef<'a, HTMLFormElement> {
};
ret
}

fn reset(self, _reset_method_flag: ResetFrom) {
// https://html.spec.whatwg.org/multipage/forms.html#locked-for-reset
if self.marked_for_reset.get() {
return;
} else {
self.marked_for_reset.set(true);
}

let win = window_from_node(self).root();
let event = Event::new(Window(*win),
"reset".to_string(),
Bubbles, Cancelable).root();
let target: JSRef<EventTarget> = EventTargetCast::from_ref(self);
target.DispatchEvent(*event).ok();
if event.DefaultPrevented() {
return;
}

let node: JSRef<Node> = NodeCast::from_ref(self);

// TODO: This is an incorrect way of getting controls owned
// by the form, but good enough until html5ever lands
for child in node.traverse_preorder() {
match child.type_id() {
ElementNodeTypeId(HTMLInputElementTypeId) => {
let input: JSRef<HTMLInputElement> = HTMLInputElementCast::to_ref(child)
.unwrap();
input.reset()
}
// TODO HTMLKeygenElement unimplemented
//ElementNodeTypeID(HTMLKeygenElementTypeId) => {
// // Unimplemented
// {}
//}
ElementNodeTypeId(HTMLSelectElementTypeId) => {
// Unimplemented
{}
}
ElementNodeTypeId(HTMLTextAreaElementTypeId) => {
let textarea: JSRef<HTMLTextAreaElement> = HTMLTextAreaElementCast::to_ref(child)
.unwrap();
textarea.reset()
}
ElementNodeTypeId(HTMLOutputElementTypeId) => {
// Unimplemented
{}
}
_ => {}
}
};
self.marked_for_reset.set(false);
}
}

impl Reflectable for HTMLFormElement {
@@ -412,7 +484,30 @@ impl<'a> FormSubmitter<'a> {
}

pub trait FormControl<'a> : Copy {
fn form_owner(self) -> Option<Temporary<HTMLFormElement>>;
// FIXME: This is wrong (https://github.com/servo/servo/issues/3553)
// but we need html5ever to do it correctly
fn form_owner(self) -> Option<Temporary<HTMLFormElement>> {
// https://html.spec.whatwg.org/multipage/forms.html#reset-the-form-owner
let elem = self.to_element();
let owner = elem.get_string_attribute(&atom!("form"));
if !owner.is_empty() {
let doc = document_from_node(elem).root();
let owner = doc.GetElementById(owner).root();
match owner {
Some(o) => {
let maybe_form: Option<JSRef<HTMLFormElement>> = HTMLFormElementCast::to_ref(*o);
if maybe_form.is_some() {
return maybe_form.map(Temporary::from_rooted);
}
},
_ => ()
}
}
let node: JSRef<Node> = NodeCast::from_ref(elem);
node.ancestors().filter_map(|a| HTMLFormElementCast::to_ref(a)).next()
.map(Temporary::from_rooted)
}

fn get_form_attribute(self,
attr: &Atom,
input: |Self| -> DOMString,
@@ -426,4 +521,5 @@ pub trait FormControl<'a> : Copy {
fn to_element(self) -> JSRef<'a, Element>;
// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-mutable
fn mutable(self) -> bool;
fn reset(self);
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.