aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/htmlscriptelement.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/htmlscriptelement.rs')
-rw-r--r--components/script/dom/htmlscriptelement.rs142
1 files changed, 135 insertions, 7 deletions
diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs
index b970596fbdd..9c20435f67a 100644
--- a/components/script/dom/htmlscriptelement.rs
+++ b/components/script/dom/htmlscriptelement.rs
@@ -14,13 +14,35 @@ use dom::document::Document;
use dom::element::{HTMLScriptElementTypeId, Element, AttributeHandlers};
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
-use dom::node::{Node, NodeHelpers, ElementNodeTypeId};
+use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
+use dom::window::WindowHelpers;
+use encoding::all::UTF_8;
+use encoding::types::{Encoding, DecodeReplace};
+use servo_net::resource_task::load_whole_resource;
use servo_util::str::{DOMString, HTML_SPACE_CHARACTERS, StaticStringVec};
+use std::cell::Cell;
+use url::UrlParser;
#[dom_struct]
pub struct HTMLScriptElement {
htmlelement: HTMLElement,
+
+ /// https://html.spec.whatwg.org/multipage/scripting.html#already-started
+ already_started: Cell<bool>,
+
+ /// https://html.spec.whatwg.org/multipage/scripting.html#parser-inserted
+ parser_inserted: Cell<bool>,
+
+ /// https://html.spec.whatwg.org/multipage/scripting.html#non-blocking
+ ///
+ /// (currently unused)
+ non_blocking: Cell<bool>,
+
+ /// https://html.spec.whatwg.org/multipage/scripting.html#ready-to-be-parser-executed
+ ///
+ /// (currently unused)
+ ready_to_be_parser_executed: Cell<bool>,
}
impl HTMLScriptElementDerived for EventTarget {
@@ -30,22 +52,30 @@ impl HTMLScriptElementDerived for EventTarget {
}
impl HTMLScriptElement {
- fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> HTMLScriptElement {
+ fn new_inherited(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>,
+ parser_inserted: bool) -> HTMLScriptElement {
HTMLScriptElement {
- htmlelement: HTMLElement::new_inherited(HTMLScriptElementTypeId, localName, prefix, document)
+ htmlelement: HTMLElement::new_inherited(HTMLScriptElementTypeId, localName, prefix, document),
+ already_started: Cell::new(false),
+ parser_inserted: Cell::new(parser_inserted),
+ non_blocking: Cell::new(!parser_inserted),
+ ready_to_be_parser_executed: Cell::new(false),
}
}
#[allow(unrooted_must_root)]
- pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>) -> Temporary<HTMLScriptElement> {
- let element = HTMLScriptElement::new_inherited(localName, prefix, document);
+ pub fn new(localName: DOMString, prefix: Option<DOMString>, document: JSRef<Document>,
+ parser_inserted: bool) -> Temporary<HTMLScriptElement> {
+ let element = HTMLScriptElement::new_inherited(localName, prefix, document, parser_inserted);
Node::reflect_node(box element, document, HTMLScriptElementBinding::Wrap)
}
}
pub trait HTMLScriptElementHelpers {
- /// Prepare a script (<http://www.whatwg.org/html/#prepare-a-script>),
- /// steps 6 and 7.
+ /// Prepare a script (<http://www.whatwg.org/html/#prepare-a-script>)
+ fn prepare(self);
+
+ /// Prepare a script, steps 6 and 7.
fn is_javascript(self) -> bool;
}
@@ -71,6 +101,104 @@ static SCRIPT_JS_MIMES: StaticStringVec = &[
];
impl<'a> HTMLScriptElementHelpers for JSRef<'a, HTMLScriptElement> {
+ fn prepare(self) {
+ // https://html.spec.whatwg.org/multipage/scripting.html#prepare-a-script
+ // Step 1.
+ if self.already_started.get() {
+ return;
+ }
+ // Step 2.
+ let was_parser_inserted = self.parser_inserted.get();
+ self.parser_inserted.set(false);
+
+ // Step 3.
+ let element: JSRef<Element> = ElementCast::from_ref(self);
+ if was_parser_inserted && element.has_attribute(&atom!("async")) {
+ self.non_blocking.set(true);
+ }
+ // Step 4.
+ let text = self.Text();
+ if text.len() == 0 && !element.has_attribute(&atom!("src")) {
+ return;
+ }
+ // Step 5.
+ let node: JSRef<Node> = NodeCast::from_ref(self);
+ if !node.is_in_doc() {
+ return;
+ }
+ // Step 6, 7.
+ if !self.is_javascript() {
+ return;
+ }
+ // Step 8.
+ if was_parser_inserted {
+ self.parser_inserted.set(true);
+ self.non_blocking.set(false);
+ }
+ // Step 9.
+ self.already_started.set(true);
+
+ // Step 10.
+ // TODO: If the element is flagged as "parser-inserted", but the element's node document is
+ // not the Document of the parser that created the element, then abort these steps.
+
+ // Step 11.
+ // TODO: If scripting is disabled for the script element, then the user agent must abort
+ // these steps at this point. The script is not executed.
+
+ // Step 12.
+ // TODO: If the script element has an `event` attribute and a `for` attribute, then run
+ // these substeps...
+
+ // Step 13.
+ // TODO: If the script element has a `charset` attribute, then let the script block's
+ // character encoding for this script element be the result of getting an encoding from the
+ // value of the `charset` attribute.
+
+ // Step 14 and 15.
+ // TODO: Add support for the `defer` and `async` attributes. (For now, we fetch all
+ // scripts synchronously and execute them immediately.)
+ let window = window_from_node(self).root();
+ let page = window.page();
+ let base_url = page.get_url();
+
+ let (source, url) = match element.get_attribute(ns!(""), &atom!("src")).root() {
+ Some(src) => {
+ if src.deref().Value().is_empty() {
+ // TODO: queue a task to fire a simple event named `error` at the element
+ return;
+ }
+ match UrlParser::new().base_url(&base_url).parse(src.deref().Value().as_slice()) {
+ Ok(url) => {
+ // TODO: Do a potentially CORS-enabled fetch with the mode being the current
+ // state of the element's `crossorigin` content attribute, the origin being
+ // the origin of the script element's node document, and the default origin
+ // behaviour set to taint.
+ match load_whole_resource(&page.resource_task, url) {
+ Ok((metadata, bytes)) => {
+ // TODO: use the charset from step 13.
+ let source = UTF_8.decode(bytes.as_slice(), DecodeReplace).unwrap();
+ (source, metadata.final_url)
+ }
+ Err(_) => {
+ error!("error loading script {}", src.deref().Value());
+ return;
+ }
+ }
+ }
+ Err(_) => {
+ // TODO: queue a task to fire a simple event named `error` at the element
+ error!("error parsing URL for script {}", src.deref().Value());
+ return;
+ }
+ }
+ }
+ None => (text, base_url)
+ };
+
+ window.evaluate_script_with_result(source.as_slice(), url.serialize().as_slice());
+ }
+
fn is_javascript(self) -> bool {
let element: JSRef<Element> = ElementCast::from_ref(self);
match element.get_attribute(ns!(""), &atom!("type")).root().map(|s| s.Value()) {