Skip to content

Commit 47198e4

Browse files
fix node === node in html dom
1 parent 6525f4f commit 47198e4

File tree

1 file changed

+94
-22
lines changed

1 file changed

+94
-22
lines changed

src/modules/htmldom/mod.rs

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use quickjs_runtime::jsutils::JsError;
3131
use quickjs_runtime::quickjsrealmadapter::QuickJsRealmAdapter;
3232
use quickjs_runtime::quickjsvalueadapter::QuickJsValueAdapter;
3333
use std::cell::RefCell;
34+
use std::collections::HashMap;
35+
use std::hash::{Hash, Hasher};
3436

3537
// https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
3638
// https://developer.mozilla.org/en-US/docs/Web/API/Element
@@ -216,8 +218,35 @@ struct StyleObj {
216218
element: NodeRef,
217219
}
218220

221+
#[derive(Clone)]
222+
struct NodeRefWrapper(NodeRef);
223+
224+
impl Hash for NodeRefWrapper {
225+
fn hash<H: Hasher>(&self, state: &mut H) {
226+
let ptr = std::rc::Rc::as_ptr(&self.0 .0);
227+
ptr.hash(state);
228+
}
229+
}
230+
231+
impl PartialEq for NodeRefWrapper {
232+
fn eq(&self, other: &Self) -> bool {
233+
let one: &NodeRef = &self.0;
234+
let two: &NodeRef = &other.0;
235+
one.eq(two)
236+
}
237+
}
238+
239+
impl Eq for NodeRefWrapper {}
240+
241+
impl NodeRefWrapper {
242+
fn clone_node(&self) -> NodeRef {
243+
self.0.clone()
244+
}
245+
}
246+
219247
thread_local! {
220248
static NODES: RefCell<AutoIdMap<NodeRef>> = RefCell::new(AutoIdMap::new());
249+
static NODE_VALUE_BY_NODEREF: RefCell<HashMap<NodeRefWrapper, QuickJsValueAdapter>> = RefCell::new(HashMap::new());
221250
static NODELISTS: RefCell<AutoIdMap<NodeList>> = RefCell::new(AutoIdMap::new());
222251
static ELEMENTLISTS: RefCell<AutoIdMap<ElementList>> = RefCell::new(AutoIdMap::new());
223252
static SELECTELEMENTLISTS: RefCell<AutoIdMap<SelectElementList >> = RefCell::new(AutoIdMap::new());
@@ -285,11 +314,34 @@ fn register_node(
285314
// remove on finalize (dont decrement refcount :))
286315
// reuse here to create a new JsValueAdapter (and then increment refcount)
287316

288-
let id = NODES.with(|rc| {
289-
let map = &mut *rc.borrow_mut();
290-
map.insert(node)
291-
});
292-
realm.instantiate_proxy_with_id(&["greco", "htmldom"], "Node", id)
317+
let node_ref_wrapper = NodeRefWrapper(node);
318+
319+
NODE_VALUE_BY_NODEREF.with(|rc| {
320+
let node_ref_map = &mut *rc.borrow_mut();
321+
if let Some(value) = node_ref_map.get(&node_ref_wrapper) {
322+
Ok(value.clone())
323+
} else {
324+
let id = NODES.with(|rc| {
325+
let map = &mut *rc.borrow_mut();
326+
map.insert(node_ref_wrapper.clone_node())
327+
});
328+
329+
let mut node_value_adapter =
330+
realm.instantiate_proxy_with_id(&["greco", "htmldom"], "Node", id)?;
331+
332+
let value_without_incr = QuickJsValueAdapter::new(
333+
realm.context,
334+
*node_value_adapter.borrow_value_mut(),
335+
false,
336+
false,
337+
"register_node clone",
338+
);
339+
340+
node_ref_map.insert(node_ref_wrapper, value_without_incr);
341+
342+
Ok(node_value_adapter)
343+
}
344+
})
293345
}
294346

295347
fn register_node_list(
@@ -406,10 +458,15 @@ fn init_node_proxy(realm: &QuickJsRealmAdapter) -> Result<QuickJsValueAdapter, J
406458
.name("Node")
407459
.event_target()
408460
.finalizer(|_rt, _realm, id| {
409-
NODES.with(|rc| {
461+
let node = NODES.with(|rc| {
410462
let map = &mut rc.borrow_mut();
411-
map.remove(&id);
412-
})
463+
map.remove(&id)
464+
});
465+
let node_ref_wrapper = NodeRefWrapper(node);
466+
NODE_VALUE_BY_NODEREF.with(|rc| {
467+
let map = &mut *rc.borrow_mut();
468+
map.remove(&node_ref_wrapper);
469+
});
413470
})
414471
.getter("dataset", |_rt, realm, id| {
415472
with_node(id, |node| {
@@ -1557,26 +1614,25 @@ pub mod tests {
15571614
use crate::init_greco_rt;
15581615
use futures::executor::block_on;
15591616
use quickjs_runtime::builder::QuickJsRuntimeBuilder;
1617+
use std::collections::HashMap;
15601618

15611619
use quickjs_runtime::jsutils::Script;
15621620
use quickjs_runtime::values::JsValueFacade;
15631621

15641622
#[test]
15651623
fn test() {
1566-
/*
1567-
panic::set_hook(Box::new(|panic_info| {
1568-
let backtrace = Backtrace::new();
1569-
log::error!(
1570-
"thread panic occurred: {}\nbacktrace: {:?}",
1571-
panic_info,
1572-
backtrace
1573-
);
1574-
}));
1575-
1576-
simple_logging::log_to_file("grecort.log", LevelFilter::max())
1577-
.ok()
1578-
.expect("could not init logger");
1579-
*/
1624+
std::panic::set_hook(Box::new(|panic_info| {
1625+
let backtrace = backtrace::Backtrace::new();
1626+
log::error!(
1627+
"thread panic occurred: {}\nbacktrace: {:?}",
1628+
panic_info,
1629+
backtrace
1630+
);
1631+
}));
1632+
1633+
simple_logging::log_to_file("grecort.log", log::LevelFilter::max())
1634+
.ok()
1635+
.expect("could not init logger");
15801636

15811637
let rtb = QuickJsRuntimeBuilder::new();
15821638
let rt = init_greco_rt(rtb).build();
@@ -1590,6 +1646,10 @@ pub mod tests {
15901646
let res = "";
15911647
15921648
let helloNode = doc.getElementById("helloId");
1649+
let helloNode2 = doc.getElementById("helloId").firstChild.parentElement;
1650+
1651+
console.log("i want true! ", helloNode === helloNode2);
1652+
15931653
helloNode.textContent = "hi there";
15941654
15951655
const svg = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
@@ -1679,5 +1739,17 @@ pub mod tests {
16791739
}
16801740
}
16811741
}
1742+
1743+
let l = crate::modules::htmldom::NODE_VALUE_BY_NODEREF.with(|rc| {
1744+
let map = &*rc.borrow();
1745+
map.len()
1746+
});
1747+
assert_eq!(l, 0);
1748+
1749+
let l = crate::modules::htmldom::NODES.with(|rc| {
1750+
let map = &*rc.borrow();
1751+
map.len()
1752+
});
1753+
assert_eq!(l, 0);
16821754
}
16831755
}

0 commit comments

Comments
 (0)