From 596e03e546ab1203a7c95865a1eeb8c64875f925 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 21 Mar 2015 04:30:35 +0530 Subject: [PATCH] Basic userscript support --- components/script/dom/htmlheadelement.rs | 52 ++++++++++++++++++++++-- components/script/dom/virtualmethods.rs | 6 +++ components/util/opts.rs | 5 +++ resources/user-agent-js/00.example.js | 5 +++ 4 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 resources/user-agent-js/00.example.js diff --git a/components/script/dom/htmlheadelement.rs b/components/script/dom/htmlheadelement.rs index 5b38078e34c..7f2a03c96d2 100644 --- a/components/script/dom/htmlheadelement.rs +++ b/components/script/dom/htmlheadelement.rs @@ -2,15 +2,24 @@ * 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::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::HTMLHeadElementBinding; -use dom::bindings::codegen::InheritTypes::HTMLHeadElementDerived; -use dom::bindings::js::{JSRef, Temporary}; +use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods; +use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; +use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLHeadElementDerived, NodeCast}; +use dom::bindings::js::{JSRef, OptionalRootable, Temporary, RootedReference}; use dom::document::Document; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::element::ElementTypeId; +use dom::element::AttributeHandlers; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; -use dom::node::{Node, NodeTypeId}; +use dom::node::{Node, NodeHelpers, NodeTypeId}; +use dom::virtualmethods::VirtualMethods; use util::str::DOMString; +use util::opts; +use util::resource_files::resources_dir_path; +use std::borrow::ToOwned; +use std::fs::read_dir; #[dom_struct] pub struct HTMLHeadElement { @@ -37,3 +46,40 @@ impl HTMLHeadElement { } } +impl<'a> VirtualMethods for JSRef<'a, HTMLHeadElement> { + fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> { + let htmlelement: &JSRef = HTMLElementCast::from_borrowed_ref(self); + Some(htmlelement as &VirtualMethods) + } + fn bind_to_tree(&self, tree_in_doc: bool) { + if !opts::get().userscripts { + return; + } + + let node: &JSRef = NodeCast::from_borrowed_ref(self); + let first_child = node.GetFirstChild().root(); + let doc = node.owner_doc().root(); + let doc = doc.r(); + + let mut path = resources_dir_path(); + path.push("user-agent-js"); + let mut files = match read_dir(&path) { + Ok(d) => d.filter_map(|e| e.ok()).map(|e| e.path()).collect::>(), + Err(_) => return + }; + + files.sort(); + + for file in files { + let name = match file.into_os_string().into_string() { + Ok(ref s) if s.ends_with(".js") => "file://".to_owned() + &s[..], + _ => continue + }; + let new_script = doc.CreateElement("script".to_owned()).unwrap().root(); + let new_script = new_script.r(); + new_script.set_string_attribute(&atom!("src"), name); + let new_script_node: &JSRef = NodeCast::from_borrowed_ref(&new_script); + node.InsertBefore(*new_script_node, first_child.r()); + } + } +} diff --git a/components/script/dom/virtualmethods.rs b/components/script/dom/virtualmethods.rs index a3e53f42bd3..05bd23307a2 100644 --- a/components/script/dom/virtualmethods.rs +++ b/components/script/dom/virtualmethods.rs @@ -11,6 +11,7 @@ use dom::bindings::codegen::InheritTypes::HTMLButtonElementCast; use dom::bindings::codegen::InheritTypes::HTMLCanvasElementCast; use dom::bindings::codegen::InheritTypes::HTMLElementCast; use dom::bindings::codegen::InheritTypes::HTMLFieldSetElementCast; +use dom::bindings::codegen::InheritTypes::HTMLHeadElementCast; use dom::bindings::codegen::InheritTypes::HTMLIFrameElementCast; use dom::bindings::codegen::InheritTypes::HTMLImageElementCast; use dom::bindings::codegen::InheritTypes::HTMLInputElementCast; @@ -39,6 +40,7 @@ use dom::htmlbuttonelement::HTMLButtonElement; use dom::htmlcanvaselement::HTMLCanvasElement; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::htmlfieldsetelement::HTMLFieldSetElement; +use dom::htmlheadelement::HTMLHeadElement; use dom::htmliframeelement::HTMLIFrameElement; use dom::htmlimageelement::HTMLImageElement; use dom::htmlinputelement::HTMLInputElement; @@ -162,6 +164,10 @@ pub fn vtable_for<'a>(node: &'a JSRef<'a, Node>) -> &'a (VirtualMethods + 'a) { let element: &'a JSRef<'a, HTMLFieldSetElement> = HTMLFieldSetElementCast::to_borrowed_ref(node).unwrap(); element as &'a (VirtualMethods + 'a) } + NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLHeadElement)) => { + let element: &'a JSRef<'a, HTMLHeadElement> = HTMLHeadElementCast::to_borrowed_ref(node).unwrap(); + element as &'a (VirtualMethods + 'a) + } NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement)) => { let element: &'a JSRef<'a, HTMLImageElement> = HTMLImageElementCast::to_borrowed_ref(node).unwrap(); element as &'a (VirtualMethods + 'a) diff --git a/components/util/opts.rs b/components/util/opts.rs index 19198cc84da..9cc16b97302 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -59,6 +59,7 @@ pub struct Opts { pub nonincremental_layout: bool, pub nossl: bool, + pub userscripts: bool, pub output_file: Option, pub headless: bool, @@ -180,6 +181,7 @@ pub fn default_opts() -> Opts { layout_threads: 1, nonincremental_layout: false, nossl: false, + userscripts: false, output_file: None, headless: true, hard_fail: true, @@ -220,6 +222,7 @@ pub fn from_cmdline_args(args: &[String]) -> bool { getopts::optopt("y", "layout-threads", "Number of threads to use for layout", "1"), getopts::optflag("i", "nonincremental-layout", "Enable to turn off incremental layout."), getopts::optflag("", "no-ssl", "Disables ssl certificate verification."), + getopts::optflag("", "userscripts", "Uses userscripts in resources/user-agent-js"), getopts::optflag("z", "headless", "Headless mode"), getopts::optflag("f", "hard-fail", "Exit on task failure instead of displaying about:failure"), getopts::optflagopt("", "devtools", "Start remote devtools server on port", "6000"), @@ -296,6 +299,7 @@ pub fn from_cmdline_args(args: &[String]) -> bool { let nonincremental_layout = opt_match.opt_present("i"); let nossl = opt_match.opt_present("no-ssl"); + let userscripts = opt_match.opt_present("userscripts"); let mut bubble_inline_sizes_separately = debug_options.contains(&"bubble-widths"); let trace_layout = debug_options.contains(&"trace-layout"); @@ -331,6 +335,7 @@ pub fn from_cmdline_args(args: &[String]) -> bool { layout_threads: layout_threads, nonincremental_layout: nonincremental_layout, nossl: nossl, + userscripts: userscripts, output_file: opt_match.opt_str("o"), headless: opt_match.opt_present("z"), hard_fail: opt_match.opt_present("f"), diff --git a/resources/user-agent-js/00.example.js b/resources/user-agent-js/00.example.js new file mode 100644 index 00000000000..c024b0f6a48 --- /dev/null +++ b/resources/user-agent-js/00.example.js @@ -0,0 +1,5 @@ +// Keep files in this directory which you would like executed before +// any other script when servo is run with `--userscripts` +// Files are sorted alphabetically. When committing polyfills +// order them with numbers, e.g. `01.innerhtml.js` will be executed before +// `05.jquery.js`