fix: implement CharacterData DOM API for jQuery DataTables compatibility (#73)
jQuery DataTables references the standard CharacterData interface which was undefined in obscura's DOM environment, causing ReferenceError and empty page renders. - Add CharacterData class extending Node with data/length/substringData/ appendData/insertData/deleteData/replaceData - Make Text and Comment extend CharacterData instead of Node - Update _wrap() to create proper Text/Comment instances by nodeType - Add create_comment_node op for Document.createComment() - Fix set_text_content to handle Comment node mutations Fixes #72 Co-authored-by: KuaaMU <[email protected]>
This commit is contained in:
1 parent
34205e50d1
commit
86a868bfd6
2 files changed
+64
-9
No files matched your search
Vendored
+57
-7
@@ -345,6 +345,56 @@ class Node {
|
|||||||
isSameNode(other) { return other && this._nid === other._nid; }
|
isSameNode(other) { return other && this._nid === other._nid; }
|
||||||
addEventListener() {} removeEventListener() {} dispatchEvent() { return true; }
|
addEventListener() {} removeEventListener() {} dispatchEvent() { return true; }
|
||||||
}
|
}
|
||||||
|
class CharacterData extends Node {
|
||||||
|
get data() {
|
||||||
|
return _domParse("text_content", this._nid) ?? "";
|
||||||
|
}
|
||||||
|
set data(v) {
|
||||||
|
_dom("set_text_content", this._nid, String(v ?? ""));
|
||||||
|
}
|
||||||
|
get length() { return this.data.length; }
|
||||||
|
substringData(offset, count) {
|
||||||
|
return this.data.substring(offset, offset + count);
|
||||||
|
}
|
||||||
|
appendData(s) { this.data += s; }
|
||||||
|
insertData(offset, s) {
|
||||||
|
const d = this.data;
|
||||||
|
this.data = d.slice(0, offset) + s + d.slice(offset);
|
||||||
|
}
|
||||||
|
deleteData(offset, count) {
|
||||||
|
const d = this.data;
|
||||||
|
this.data = d.slice(0, offset) + d.slice(offset + count);
|
||||||
|
}
|
||||||
|
replaceData(offset, count, s) {
|
||||||
|
const d = this.data;
|
||||||
|
this.data = d.slice(0, offset) + s + d.slice(offset + count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Text extends CharacterData {
|
||||||
|
get nodeName() { return "#text"; }
|
||||||
|
get nodeType() { return 3; }
|
||||||
|
get wholeText() { return this.data; }
|
||||||
|
splitText(offset) {
|
||||||
|
const d = this.data;
|
||||||
|
const tail = d.substring(offset);
|
||||||
|
this.data = d.substring(0, offset);
|
||||||
|
const newNid = +_dom("create_text_node", tail);
|
||||||
|
const parent = this.parentNode;
|
||||||
|
if (parent) {
|
||||||
|
const ref = this.nextSibling;
|
||||||
|
parent.insertBefore(_wrap(newNid), ref);
|
||||||
|
}
|
||||||
|
return _wrap(newNid);
|
||||||
|
}
|
||||||
|
cloneNode() { return document.createTextNode(this.data); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Comment extends CharacterData {
|
||||||
|
get nodeName() { return "#comment"; }
|
||||||
|
get nodeType() { return 8; }
|
||||||
|
cloneNode() { return document.createComment(this.data); }
|
||||||
|
}
|
||||||
|
|
||||||
class Element extends Node {
|
class Element extends Node {
|
||||||
constructor(nid) {
|
constructor(nid) {
|
||||||
@@ -764,11 +814,8 @@ class Document extends Node {
|
|||||||
}
|
}
|
||||||
createTextNode(t) { return _wrap(+_dom("create_text_node", String(t))); }
|
createTextNode(t) { return _wrap(+_dom("create_text_node", String(t))); }
|
||||||
createComment(t) {
|
createComment(t) {
|
||||||
const nid = +_dom("create_text_node", "");
|
const nid = +_dom("create_comment_node", String(t ?? ""));
|
||||||
const n = new Node(nid);
|
const n = new Comment(nid);
|
||||||
n._isComment = true;
|
|
||||||
Object.defineProperty(n, "nodeType", { value: 8, writable: false, configurable: true });
|
|
||||||
Object.defineProperty(n, "nodeName", { value: "#comment", writable: false, configurable: true });
|
|
||||||
_cache.set(nid, n);
|
_cache.set(nid, n);
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -971,6 +1018,8 @@ function _wrap(nid) {
|
|||||||
const t = +_dom("node_type", nid);
|
const t = +_dom("node_type", nid);
|
||||||
let n;
|
let n;
|
||||||
if (t === 1) n = new Element(nid);
|
if (t === 1) n = new Element(nid);
|
||||||
|
else if (t === 3) n = new Text(nid);
|
||||||
|
else if (t === 8) n = new Comment(nid);
|
||||||
else if (t === 9) n = new Document(nid);
|
else if (t === 9) n = new Document(nid);
|
||||||
else n = new Node(nid);
|
else n = new Node(nid);
|
||||||
_cache.set(nid, n);
|
_cache.set(nid, n);
|
||||||
@@ -1987,8 +2036,9 @@ globalThis.HTMLDetailsElement = Element;
|
|||||||
globalThis.HTMLDialogElement = Element;
|
globalThis.HTMLDialogElement = Element;
|
||||||
globalThis.SVGElement = Element;
|
globalThis.SVGElement = Element;
|
||||||
globalThis.SVGSVGElement = Element;
|
globalThis.SVGSVGElement = Element;
|
||||||
globalThis.Text = Node;
|
globalThis.CharacterData = CharacterData;
|
||||||
globalThis.Comment = Node;
|
globalThis.Text = Text;
|
||||||
|
globalThis.Comment = Comment;
|
||||||
globalThis.DocumentFragment = DocumentFragment;
|
globalThis.DocumentFragment = DocumentFragment;
|
||||||
globalThis.DocumentType = DocumentType;
|
globalThis.DocumentType = DocumentType;
|
||||||
globalThis.Node = Node;
|
globalThis.Node = Node;
|
||||||
|
|||||||
@@ -228,8 +228,10 @@ fn op_dom(state: &OpState, #[string] cmd: String, #[string] arg1: String, #[stri
|
|||||||
"set_text_content" => {
|
"set_text_content" => {
|
||||||
let nid = arg1.parse::<u32>().unwrap_or(0);
|
let nid = arg1.parse::<u32>().unwrap_or(0);
|
||||||
dom.with_node_mut(NodeId::new(nid), |n| {
|
dom.with_node_mut(NodeId::new(nid), |n| {
|
||||||
if let NodeData::Text { contents } = &mut n.data {
|
match &mut n.data {
|
||||||
*contents = arg2.clone();
|
NodeData::Text { contents } => { *contents = arg2.clone(); }
|
||||||
|
NodeData::Comment { contents } => { *contents = arg2.clone(); }
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
"true".into()
|
"true".into()
|
||||||
@@ -246,6 +248,9 @@ fn op_dom(state: &OpState, #[string] cmd: String, #[string] arg1: String, #[stri
|
|||||||
"create_text_node" => {
|
"create_text_node" => {
|
||||||
dom.new_node(NodeData::Text { contents: arg1.clone() }).index().to_string()
|
dom.new_node(NodeData::Text { contents: arg1.clone() }).index().to_string()
|
||||||
}
|
}
|
||||||
|
"create_comment_node" => {
|
||||||
|
dom.new_node(NodeData::Comment { contents: arg1.clone() }).index().to_string()
|
||||||
|
}
|
||||||
"element_children" => {
|
"element_children" => {
|
||||||
let nid = arg1.parse::<u32>().unwrap_or(0);
|
let nid = arg1.parse::<u32>().unwrap_or(0);
|
||||||
let ids: Vec<i32> = dom.children(NodeId::new(nid)).iter()
|
let ids: Vec<i32> = dom.children(NodeId::new(nid)).iter()
|
||||||
|
|||||||
Reference in new issue
Block a user