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
vCard/JSON extraction #19443
vCard/JSON extraction #19443
Changes from all commits
eb2c7e0
015ef37
43aeb7c
f306835
0530512
f939632
3d68d2a
a4ed961
4628943
cbfc666
146dd58
9284187
dd4dc70
43650c2
19408a0
79d140d
aab6900
35468f8
8cafd64
87d1efa
c580c3f
3cd9731
d0cb12e
0ae2d08
7131823
a3e5b9f
0e5023d
37f70c6
543de1c
a781bba
04a043d
c740aab
File filter...
Jump to…
Large diffs are not rendered by default.
| @@ -99,6 +99,7 @@ use ipc_channel::ipc::{self, IpcSender}; | ||
| use js::jsapi::{JSContext, JSRuntime}; | ||
| use js::jsapi::JS_GetRuntime; | ||
| use metrics::{InteractiveFlag, InteractiveMetrics, InteractiveWindow, ProfilerMetadataFactory, ProgressiveWebMetric}; | ||
| use microdata; | ||
| use msg::constellation_msg::{BrowsingContextId, Key, KeyModifiers, KeyState, TopLevelBrowsingContextId}; | ||
| use net_traits::{FetchResponseMsg, IpcSend, ReferrerPolicy}; | ||
| use net_traits::CookieSource::NonHTTP; | ||
| @@ -1710,6 +1711,14 @@ impl Document { | ||
|
|
||
| // Step 12. | ||
| // TODO: completely loaded. | ||
|
|
||
| // Step 13. | ||
CJ8664
Author
|
||
| let htmlelement = self.get_html_element(); | ||
| let result = microdata::parse(self, htmlelement.unwrap().upcast::<Node>()); | ||
| if let Some(data) = result { | ||
| let event = ScriptMsg::SendMicrodata(data); | ||
| self.send_to_constellation(event); | ||
| } | ||
| } | ||
|
|
||
| // https://html.spec.whatwg.org/multipage/#pending-parsing-blocking-script | ||
| @@ -3947,7 +3956,7 @@ impl DocumentMethods for Document { | ||
| } | ||
|
|
||
| fn update_with_current_time_ms(marker: &Cell<u64>) { | ||
| if marker.get() == Default::default() { | ||
| if marker.get() == 0 { | ||
| let time = time::get_time(); | ||
| let current_time_ms = time.sec * 1000 + time.nsec as i64 / 1000000; | ||
| marker.set(current_time_ms as u64); | ||
| @@ -0,0 +1,158 @@ | ||
| /* This Source Code Form is subject to the terms of the Mozilla Public | ||
| * 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::DocumentBinding::DocumentMethods; | ||
| use dom::bindings::codegen::Bindings::ElementBinding::ElementBinding::ElementMethods; | ||
| use dom::bindings::inheritance::Castable; | ||
| use dom::bindings::root::DomRoot; | ||
| use dom::document::Document; | ||
| use dom::element::Element; | ||
| use dom::htmlelement::HTMLElement; | ||
| use dom::node::Node; | ||
| use script_traits::Microdata; | ||
| use std::borrow::Cow; | ||
| use std::collections::HashMap; | ||
|
|
||
| pub fn parse(doc: &Document, node: &Node) -> Option<Microdata> { | ||
| let serialized_vcard = parse_vcard(doc); | ||
| let serialized_json = parse_json(node); | ||
| if !serialized_vcard.is_empty() { | ||
| return Some(Microdata::VCardData(serialized_vcard.to_owned())); | ||
| } else if !serialized_vcard.is_empty() { | ||
CJ8664
Author
|
||
| return Some(Microdata::JSONData(serialized_json.to_owned())); | ||
| } else { | ||
| return None | ||
| } | ||
| } | ||
|
|
||
| pub fn parse_vcard(doc: &Document) -> String { | ||
| let ele = doc.upcast::<Node>(); | ||
| let mut start_vcard = false; | ||
| let mut result: String = String::new(); | ||
| let mut master_map: HashMap<String, HashMap<String, String>> = HashMap::new(); | ||
| let mut master_key: String = String::new(); | ||
|
|
||
| result += "BEGIN:VCARD\nPROFILE:VCARD\nVERSION:4.0\nSOURCE:"; | ||
| result += doc.url().as_str(); | ||
|
|
||
| let title = doc.Title(); | ||
| if !title.is_empty() && !title.trim().is_empty() { | ||
| result += "\nNAME:"; | ||
| result += title.trim(); | ||
| } | ||
|
|
||
| result += "\n"; | ||
|
|
||
| for element in ele.traverse_preorder().filter_map(DomRoot::downcast::<Element>) { | ||
| if element.is::<HTMLElement>() { | ||
| if element.has_attribute(&local_name!("itemtype")) { | ||
| let mut atoms = element.get_tokenlist_attribute(&local_name!("itemtype"), ); | ||
| if !atoms.is_empty() { | ||
| let val = atoms.remove(0); | ||
| if val.trim() == "http://microformats.org/profile/hcard" { | ||
| if !start_vcard { | ||
| start_vcard = true; | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if start_vcard { | ||
| let mut atoms = element.get_tokenlist_attribute(&local_name!("itemprop"), ); | ||
| if !atoms.is_empty() { | ||
| let temp_key = atoms.remove(0); | ||
| if element.has_attribute(&local_name!("itemscope")) { | ||
| master_key = String::from(temp_key.trim()).to_owned(); | ||
| let dup_master_key = Cow::Borrowed(&master_key); | ||
| master_map.entry(dup_master_key.to_string()).or_insert(HashMap::new()); | ||
| } else { | ||
| let temp = String::from(temp_key.trim()).to_owned(); | ||
| let dup_key = Cow::Borrowed(&temp); | ||
| let data = String::from(element.GetInnerHTML().unwrap()); | ||
| let dup_master_key = Cow::Borrowed(&master_key); | ||
| let temp_map = master_map.entry(dup_master_key.to_string()).or_insert(HashMap::new()); | ||
| temp_map.insert(dup_key.to_string(), String::from(data)); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| let vcard_parts = ["n", "org", "tel", "adr"]; | ||
| for info_type in vcard_parts.iter() { | ||
| let detail_map_val = master_map.get(*info_type); | ||
| if detail_map_val.is_none() { | ||
| continue; | ||
| } | ||
| let detail_map = detail_map_val.unwrap(); | ||
| match *info_type { | ||
| "n" => { | ||
| let mut n_value: String = String::new(); | ||
|
|
||
| let name_parts = ["family-name", "given-name", | ||
| "additional-name", "honorific-prefix", "honorific-suffix"]; | ||
| for part in name_parts.iter() { | ||
| if detail_map.contains_key(*part) { | ||
| n_value += format!("{};", detail_map.get(*part).unwrap()).as_str(); | ||
| } | ||
| } | ||
| n_value.pop(); | ||
|
|
||
| result += format!("{}:{}\n", info_type.to_ascii_uppercase(), n_value).as_str(); | ||
| }, | ||
| "org" => { | ||
| let mut org_value: String = String::new(); | ||
|
|
||
| let org_parts = ["organization-name", "organization-unit"]; | ||
| for part in org_parts.iter() { | ||
| if detail_map.contains_key(*part) { | ||
| org_value += format!("{};", detail_map.get(*part).unwrap()).as_str(); | ||
| } | ||
| } | ||
| org_value.pop(); | ||
|
|
||
| result += format!("{}:{}\n", info_type.to_ascii_uppercase(), org_value).as_str(); | ||
| }, | ||
| "tel" => { | ||
| let mut tel_value: String = String::new(); | ||
|
|
||
| let tel_parts = ["value"]; | ||
| for part in tel_parts.iter() { | ||
| if detail_map.contains_key(*part) { | ||
| tel_value += format!("{};", detail_map.get(*part).unwrap()).as_str(); | ||
| } | ||
| } | ||
| tel_value.pop(); | ||
|
|
||
| result += format!("{}:{}\n", info_type.to_ascii_uppercase(), tel_value).as_str(); | ||
| }, | ||
| "adr" => { | ||
| let mut adr_value: String = String::new(); | ||
|
|
||
| let adr_parts = ["street-address", "locality", "region", "postal-code", | ||
| "country-name", "post-office-box", "extended-address"]; | ||
| for part in adr_parts.iter() { | ||
| if detail_map.contains_key(*part) { | ||
| adr_value += format!("{};", detail_map.get(*part).unwrap()).as_str(); | ||
| } | ||
| } | ||
| adr_value.pop(); | ||
|
|
||
| result += format!("{}:{}\n", info_type.to_ascii_uppercase(), adr_value).as_str(); | ||
| }, | ||
| _ => {}, | ||
| } | ||
| } | ||
| result += "END:VCARD"; | ||
| if start_vcard { | ||
| return result; | ||
| } else { | ||
| return "".to_string(); | ||
| } | ||
| } | ||
|
|
||
| pub fn parse_json(node: &Node) -> String { | ||
| // TODO Write the logic for JSON Parsing | ||
| return "".to_string(); | ||
| } | ||
The comments here refer to actual step numbers defined in the HTML specification. We should not add ones for steps that do not exist :)