Auto merge of #9887 - schuster:HTMLHyperlinkElementUtils, r=jdm

Implement HTMLHyperlinkElementUtils for HTMLAnchorElement

Fixes #7857

Origin is omitted since it's still not available in rust-url, but since the previous PR also left it out, I'm assuming that's okay.

Please let me know if there are any style issues. There might be more concise ways to do the pattern matching that I don't know about, I guessed at the indentation style in one or two places.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.svg" height="40" alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/9887)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-03-25 11:36:35 +05:30
commit 9a8d62286c
26 changed files with 369 additions and 1606 deletions

View file

@ -5,6 +5,7 @@
use dom::activation::Activatable;
use dom::attr::AttrValue;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::HTMLAnchorElementBinding;
use dom::bindings::codegen::Bindings::HTMLAnchorElementBinding::HTMLAnchorElementMethods;
@ -12,6 +13,7 @@ use dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::str::USVString;
use dom::document::Document;
use dom::domtokenlist::DOMTokenList;
use dom::element::Element;
@ -21,16 +23,19 @@ use dom::htmlelement::HTMLElement;
use dom::htmlimageelement::HTMLImageElement;
use dom::mouseevent::MouseEvent;
use dom::node::{Node, document_from_node, window_from_node};
use dom::urlhelper::UrlHelper;
use dom::virtualmethods::VirtualMethods;
use num::ToPrimitive;
use std::default::Default;
use string_cache::Atom;
use url::{Url, UrlParser};
use util::str::DOMString;
#[dom_struct]
pub struct HTMLAnchorElement {
htmlelement: HTMLElement,
rel_list: MutNullableHeap<JS<DOMTokenList>>,
url: DOMRefCell<Option<Url>>,
}
impl HTMLAnchorElement {
@ -41,6 +46,7 @@ impl HTMLAnchorElement {
htmlelement:
HTMLElement::new_inherited(localName, prefix, document),
rel_list: Default::default(),
url: DOMRefCell::new(None),
}
}
@ -51,6 +57,37 @@ impl HTMLAnchorElement {
let element = HTMLAnchorElement::new_inherited(localName, prefix, document);
Node::reflect_node(box element, document, HTMLAnchorElementBinding::Wrap)
}
// https://html.spec.whatwg.org/multipage/#concept-hyperlink-url-set
fn set_url(&self) {
let attribute = self.upcast::<Element>().get_attribute(&ns!(), &atom!("href"));
*self.url.borrow_mut() = attribute.and_then(|attribute| {
let document = document_from_node(self);
let mut parser = UrlParser::new();
parser.base_url(document.url());
parser.parse(&attribute.value()).ok()
});
}
// https://html.spec.whatwg.org/multipage/#reinitialise-url
fn reinitialize_url(&self) {
// Step 1.
match *self.url.borrow() {
None => return,
Some(ref url) if url.scheme == "blob" &&
url.non_relative_scheme_data().is_some() => return,
_ => (),
}
// Step 2.
self.set_url();
}
// https://html.spec.whatwg.org/multipage/#update-href
fn update_href(&self) {
self.upcast::<Element>().set_string_attribute(&atom!("href"),
self.url.borrow().as_ref().unwrap().serialize().into());
}
}
impl VirtualMethods for HTMLAnchorElement {
@ -107,6 +144,312 @@ impl HTMLAnchorElementMethods for HTMLAnchorElement {
// https://html.spec.whatwg.org/multipage/#dom-a-shape
make_setter!(SetShape, "shape");
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-hash
fn Hash(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 3.
None => USVString(String::new()),
Some(ref url) => {
// Steps 3-4.
UrlHelper::Hash(url)
}
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-hash
fn SetHash(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.scheme == "javascript" { return; }
// Steps 4-5.
UrlHelper::SetHash(url, value);
// Step 6.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-host
fn Host(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 3.
None => USVString(String::new()),
Some(ref url) => {
if url.host().is_none() {
USVString(String::new())
} else {
// Steps 4-5.
UrlHelper::Host(url)
}
}
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-host
fn SetHost(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.non_relative_scheme_data().is_some() {
return;
}
// Step 4.
UrlHelper::SetHost(url, value);
// Step 5.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-hostname
fn Hostname(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 3.
None => USVString(String::new()),
Some(ref url) => {
// Step 4.
UrlHelper::Hostname(url)
}
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-hostname
fn SetHostname(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.non_relative_scheme_data().is_some() {
return;
}
// Step 4.
UrlHelper::SetHostname(url, value);
// Step 5.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-href
fn Href(&self) -> USVString {
// Step 1.
self.reinitialize_url();
USVString(match *self.url.borrow() {
None => {
match self.upcast::<Element>().get_attribute(&ns!(), &atom!("href")) {
// Step 3.
None => String::new(),
// Step 4.
Some(attribute) => (**attribute.value()).to_owned(),
}
},
// Step 5.
Some(ref url) => url.serialize(),
})
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-href
fn SetHref(&self, value: USVString) {
self.upcast::<Element>().set_string_attribute(&atom!("href"),
DOMString::from_string(value.0));
self.set_url();
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-password
fn Password(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 3.
None => USVString(String::new()),
// Steps 3-4.
Some(ref url) => UrlHelper::Password(url)
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-password
fn SetPassword(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.host().is_none() || url.non_relative_scheme_data().is_some() {
return;
}
// Step 4.
UrlHelper::SetPassword(url, value);
// Step 5.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-pathname
fn Pathname(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 3.
None => USVString(String::new()),
// Steps 4-5.
Some(ref url) => UrlHelper::Pathname(url)
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-pathname
fn SetPathname(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.non_relative_scheme_data().is_some() { return; }
// Step 5.
UrlHelper::SetPathname(url, value);
// Step 6.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-port
fn Port(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 3.
None => USVString(String::new()),
// Step 4.
Some(ref url) => UrlHelper::Port(url)
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-port
fn SetPort(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.host().is_none() ||
url.non_relative_scheme_data().is_some() ||
url.scheme == "file" {
return;
}
// Step 4.
UrlHelper::SetPort(url, value);
// Step 5.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-protocol
fn Protocol(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 2.
None => USVString(":".to_owned()),
// Step 3.
Some(ref url) => UrlHelper::Protocol(url)
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-protocol
fn SetProtocol(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 2.
if let Some(url) = self.url.borrow_mut().as_mut() {
// Step 3.
UrlHelper::SetProtocol(url, value);
// Step 4.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-search
fn Search(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 2.
None => USVString(String::new()),
// Step 3.
Some(ref url) => UrlHelper::Search(url)
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-search
fn SetSearch(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
// Steps 4-5.
// TODO add this element's node document character encoding as
// encoding override (as described in the spec)
UrlHelper::SetSearch(url, value);
// Step 6.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-username
fn Username(&self) -> USVString {
// Step 1.
self.reinitialize_url();
match *self.url.borrow() {
// Step 2.
None => USVString(String::new()),
// Step 3.
Some(ref url) => UrlHelper::Username(url)
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-username
fn SetUsername(&self, value: USVString) {
// Step 1.
self.reinitialize_url();
// Step 3.
if let Some(url) = self.url.borrow_mut().as_mut() {
if url.host().is_none() || url.non_relative_scheme_data().is_some() {
return;
}
// Step 4.
UrlHelper::SetUsername(url, value);
// Step 5.
self.update_href();
}
}
// https://html.spec.whatwg.org/multipage/#dom-hyperlink-href
fn Stringifier(&self) -> DOMString {
DOMString::from(self.Href().0)
}
}
impl Activatable for HTMLAnchorElement {

View file

@ -21,6 +21,7 @@ impl UrlHelper {
}
pub fn SetHash(url: &mut Url, value: USVString) {
url.fragment = Some(String::new());
let mut wrapper = UrlUtilsWrapper { url: url, parser: &UrlParser::new() };
let _ = wrapper.set_fragment(&value.0);
}
@ -101,6 +102,9 @@ impl UrlHelper {
}
pub fn SetPathname(url: &mut Url, value: USVString) {
if let Some(path) = url.path_mut() {
path.clear();
}
let mut wrapper = UrlUtilsWrapper { url: url, parser: &UrlParser::new() };
let _ = wrapper.set_path(&value.0);
}
@ -149,6 +153,7 @@ impl UrlHelper {
}
pub fn SetSearch(url: &mut Url, value: USVString) {
url.query = Some(String::new());
let mut wrapper = UrlUtilsWrapper { url: url, parser: &UrlParser::new() };
let _ = wrapper.set_query(&value.0);
}

View file

@ -26,7 +26,7 @@ interface HTMLAnchorElement : HTMLElement {
// also has obsolete members
};
//HTMLAnchorElement implements HTMLHyperlinkElementUtils;
HTMLAnchorElement implements HTMLHyperlinkElementUtils;
// https://html.spec.whatwg.org/multipage/#HTMLAnchorElement-partial
partial interface HTMLAnchorElement {

View file

@ -4,17 +4,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// https://html.spec.whatwg.org/multipage/#htmlhyperlinkelementutils
//[NoInterfaceObject/*, Exposed=Window*/]
//interface HTMLHyperlinkElementUtils {
[NoInterfaceObject/*, Exposed=Window*/]
interface HTMLHyperlinkElementUtils {
// stringifier attribute USVString href;
attribute USVString href;
// attribute USVString origin;
// attribute USVString protocol;
// attribute USVString username;
// attribute USVString password;
// attribute USVString host;
// attribute USVString hostname;
// attribute USVString port;
// attribute USVString pathname;
// attribute USVString search;
// attribute USVString hash;
//};
attribute USVString protocol;
attribute USVString username;
attribute USVString password;
attribute USVString host;
attribute USVString hostname;
attribute USVString port;
attribute USVString pathname;
attribute USVString search;
attribute USVString hash;
// Adding a separate stringifier method until
// https://github.com/servo/servo/issues/7590 adds attribute stringifier
// support.
stringifier;
};