mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #27 from Browsercore/characterdata
CharacterData properties and methods
This commit is contained in:
@@ -1,14 +1,79 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const jsruntime = @import("jsruntime");
|
||||||
|
const Case = jsruntime.test_utils.Case;
|
||||||
|
const checkCases = jsruntime.test_utils.checkCases;
|
||||||
const generate = @import("../generate.zig");
|
const generate = @import("../generate.zig");
|
||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
|
|
||||||
const Node = @import("node.zig").Node;
|
const Node = @import("node.zig").Node;
|
||||||
const Comment = @import("comment.zig").Comment;
|
const Comment = @import("comment.zig").Comment;
|
||||||
const Text = @import("text.zig").Text;
|
const Text = @import("text.zig").Text;
|
||||||
|
const HTMLElem = @import("../html/elements.zig");
|
||||||
|
|
||||||
pub const CharacterData = struct {
|
pub const CharacterData = struct {
|
||||||
pub const Self = parser.CharacterData;
|
pub const Self = parser.CharacterData;
|
||||||
pub const prototype = *Node;
|
pub const prototype = *Node;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
|
// JS funcs
|
||||||
|
// --------
|
||||||
|
|
||||||
|
// Read attributes
|
||||||
|
|
||||||
|
pub fn get_length(self: *parser.CharacterData) u32 {
|
||||||
|
return parser.characterDataLength(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_nextElementSibling(self: *parser.CharacterData) ?HTMLElem.Union {
|
||||||
|
const res = parser.nodeNextElementSibling(parser.characterDataToNode(self));
|
||||||
|
if (res == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return HTMLElem.toInterface(HTMLElem.Union, res.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_previousElementSibling(self: *parser.CharacterData) ?HTMLElem.Union {
|
||||||
|
const res = parser.nodePreviousElementSibling(parser.characterDataToNode(self));
|
||||||
|
if (res == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return HTMLElem.toInterface(HTMLElem.Union, res.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read/Write attributes
|
||||||
|
|
||||||
|
pub fn get_data(self: *parser.CharacterData) []const u8 {
|
||||||
|
return parser.characterDataData(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_data(self: *parser.CharacterData, data: []const u8) void {
|
||||||
|
return parser.characterDataSetData(self, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// JS methods
|
||||||
|
// ----------
|
||||||
|
|
||||||
|
pub fn _appendData(self: *parser.CharacterData, data: []const u8) void {
|
||||||
|
return parser.characterDataAppendData(self, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _deleteData(self: *parser.CharacterData, offset: u32, count: u32) void {
|
||||||
|
return parser.characterDataDeleteData(self, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _insertData(self: *parser.CharacterData, offset: u32, data: []const u8) void {
|
||||||
|
return parser.characterDataInsertData(self, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _replaceData(self: *parser.CharacterData, offset: u32, count: u32, data: []const u8) void {
|
||||||
|
return parser.characterDataReplaceData(self, offset, count, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _substringData(self: *parser.CharacterData, offset: u32, count: u32) []const u8 {
|
||||||
|
return parser.characterDataSubstringData(self, offset, count);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Types = generate.Tuple(.{
|
pub const Types = generate.Tuple(.{
|
||||||
@@ -18,3 +83,79 @@ pub const Types = generate.Tuple(.{
|
|||||||
const Generated = generate.Union.compile(Types);
|
const Generated = generate.Union.compile(Types);
|
||||||
pub const Union = Generated._union;
|
pub const Union = Generated._union;
|
||||||
pub const Tags = Generated._enum;
|
pub const Tags = Generated._enum;
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
// -----
|
||||||
|
|
||||||
|
pub fn testExecFn(
|
||||||
|
_: std.mem.Allocator,
|
||||||
|
js_env: *jsruntime.Env,
|
||||||
|
comptime _: []jsruntime.API,
|
||||||
|
) !void {
|
||||||
|
var get_data = [_]Case{
|
||||||
|
.{ .src = "let link = document.getElementById('link')", .ex = "undefined" },
|
||||||
|
.{ .src = "let cdata = link.firstChild", .ex = "undefined" },
|
||||||
|
.{ .src = "cdata.data", .ex = "OK" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &get_data);
|
||||||
|
|
||||||
|
var set_data = [_]Case{
|
||||||
|
.{ .src = "cdata.data = 'OK modified'", .ex = "OK modified" },
|
||||||
|
.{ .src = "cdata.data === 'OK modified'", .ex = "true" },
|
||||||
|
.{ .src = "cdata.data = 'OK'", .ex = "OK" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &set_data);
|
||||||
|
|
||||||
|
var get_length = [_]Case{
|
||||||
|
.{ .src = "cdata.length === 2", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &get_length);
|
||||||
|
|
||||||
|
var get_next_elem_sibling = [_]Case{
|
||||||
|
.{ .src = "cdata.nextElementSibling === null", .ex = "true" },
|
||||||
|
// create a next element
|
||||||
|
.{ .src = "let next = document.createElement('a')", .ex = "undefined" },
|
||||||
|
.{ .src = "link.appendChild(next, cdata) !== undefined", .ex = "true" },
|
||||||
|
.{ .src = "cdata.nextElementSibling.localName === 'a' ", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &get_next_elem_sibling);
|
||||||
|
|
||||||
|
var get_prev_elem_sibling = [_]Case{
|
||||||
|
.{ .src = "cdata.previousElementSibling === null", .ex = "true" },
|
||||||
|
// create a prev element
|
||||||
|
.{ .src = "let prev = document.createElement('div')", .ex = "undefined" },
|
||||||
|
.{ .src = "link.insertBefore(prev, cdata) !== undefined", .ex = "true" },
|
||||||
|
.{ .src = "cdata.previousElementSibling.localName === 'div' ", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &get_prev_elem_sibling);
|
||||||
|
|
||||||
|
var append_data = [_]Case{
|
||||||
|
.{ .src = "cdata.appendData(' modified')", .ex = "undefined" },
|
||||||
|
.{ .src = "cdata.data === 'OK modified' ", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &append_data);
|
||||||
|
|
||||||
|
var delete_data = [_]Case{
|
||||||
|
.{ .src = "cdata.deleteData('OK'.length, ' modified'.length)", .ex = "undefined" },
|
||||||
|
.{ .src = "cdata.data == 'OK'", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &delete_data);
|
||||||
|
|
||||||
|
var insert_data = [_]Case{
|
||||||
|
.{ .src = "cdata.insertData('OK'.length-1, 'modified')", .ex = "undefined" },
|
||||||
|
.{ .src = "cdata.data == 'OmodifiedK'", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &insert_data);
|
||||||
|
|
||||||
|
var replace_data = [_]Case{
|
||||||
|
.{ .src = "cdata.replaceData('OK'.length-1, 'modified'.length, 'replaced')", .ex = "undefined" },
|
||||||
|
.{ .src = "cdata.data == 'OreplacedK'", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &replace_data);
|
||||||
|
|
||||||
|
var substring_data = [_]Case{
|
||||||
|
.{ .src = "cdata.substringData('OK'.length-1, 'replaced'.length) == 'replaced'", .ex = "true" },
|
||||||
|
.{ .src = "cdata.substringData('OK'.length-1, 0) == ''", .ex = "true" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &substring_data);
|
||||||
|
}
|
||||||
|
|||||||
@@ -267,12 +267,42 @@ pub fn nodeNextSibling(node: *Node) ?*Node {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nodeNextElementSibling(node: *Node) ?*Element {
|
||||||
|
var n = node;
|
||||||
|
while (true) {
|
||||||
|
const res = nodeNextSibling(n);
|
||||||
|
if (res == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (nodeType(res.?) == .element) {
|
||||||
|
return @as(*Element, @ptrCast(res.?));
|
||||||
|
}
|
||||||
|
n = res.?;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn nodePreviousSibling(node: *Node) ?*Node {
|
pub fn nodePreviousSibling(node: *Node) ?*Node {
|
||||||
var res: ?*Node = undefined;
|
var res: ?*Node = undefined;
|
||||||
_ = nodeVtable(node).dom_node_get_previous_sibling.?(node, &res);
|
_ = nodeVtable(node).dom_node_get_previous_sibling.?(node, &res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn nodePreviousElementSibling(node: *Node) ?*Element {
|
||||||
|
var n = node;
|
||||||
|
while (true) {
|
||||||
|
const res = nodePreviousSibling(n);
|
||||||
|
if (res == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (nodeType(res.?) == .element) {
|
||||||
|
return @as(*Element, @ptrCast(res.?));
|
||||||
|
}
|
||||||
|
n = res.?;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn nodeParentNode(node: *Node) ?*Node {
|
pub fn nodeParentNode(node: *Node) ?*Node {
|
||||||
var res: ?*Node = undefined;
|
var res: ?*Node = undefined;
|
||||||
_ = nodeVtable(node).dom_node_get_parent_node.?(node, &res);
|
_ = nodeVtable(node).dom_node_get_parent_node.?(node, &res);
|
||||||
@@ -420,6 +450,56 @@ pub fn nodeReplaceChild(node: *Node, new_child: *Node, old_child: *Node) *Node {
|
|||||||
// CharacterData
|
// CharacterData
|
||||||
pub const CharacterData = c.dom_characterdata;
|
pub const CharacterData = c.dom_characterdata;
|
||||||
|
|
||||||
|
fn characterDataVtable(data: *CharacterData) c.dom_characterdata_vtable {
|
||||||
|
return getVtable(c.dom_characterdata_vtable, CharacterData, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn characterDataToNode(cdata: *CharacterData) *Node {
|
||||||
|
return @as(*Node, @ptrCast(cdata));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataData(cdata: *CharacterData) []const u8 {
|
||||||
|
var s: ?*String = undefined;
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_get_data.?(cdata, &s);
|
||||||
|
return stringToData(s.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataSetData(cdata: *CharacterData, data: []const u8) void {
|
||||||
|
const s = stringFromData(data);
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_set_data.?(cdata, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataLength(cdata: *CharacterData) u32 {
|
||||||
|
var n: u32 = undefined;
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_get_length.?(cdata, &n);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataAppendData(cdata: *CharacterData, data: []const u8) void {
|
||||||
|
const s = stringFromData(data);
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_append_data.?(cdata, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataDeleteData(cdata: *CharacterData, offset: u32, count: u32) void {
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_delete_data.?(cdata, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataInsertData(cdata: *CharacterData, offset: u32, data: []const u8) void {
|
||||||
|
const s = stringFromData(data);
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_insert_data.?(cdata, offset, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataReplaceData(cdata: *CharacterData, offset: u32, count: u32, data: []const u8) void {
|
||||||
|
const s = stringFromData(data);
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_replace_data.?(cdata, offset, count, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn characterDataSubstringData(cdata: *CharacterData, offset: u32, count: u32) []const u8 {
|
||||||
|
var s: ?*String = undefined;
|
||||||
|
_ = characterDataVtable(cdata).dom_characterdata_substring_data.?(cdata, offset, count, &s);
|
||||||
|
return stringToData(s.?);
|
||||||
|
}
|
||||||
|
|
||||||
// Text
|
// Text
|
||||||
pub const Text = c.dom_text;
|
pub const Text = c.dom_text;
|
||||||
|
|
||||||
|
|||||||
@@ -5,27 +5,49 @@ const generate = @import("generate.zig");
|
|||||||
|
|
||||||
const parser = @import("netsurf.zig");
|
const parser = @import("netsurf.zig");
|
||||||
const DOM = @import("dom.zig");
|
const DOM = @import("dom.zig");
|
||||||
|
|
||||||
const docTestExecFn = @import("html/document.zig").testExecFn;
|
const docTestExecFn = @import("html/document.zig").testExecFn;
|
||||||
const nodeTestExecFn = @import("dom/node.zig").testExecFn;
|
const nodeTestExecFn = @import("dom/node.zig").testExecFn;
|
||||||
|
const characterDataTestExecFn = @import("dom/character_data.zig").testExecFn;
|
||||||
|
|
||||||
var doc: *parser.DocumentHTML = undefined;
|
var doc: *parser.DocumentHTML = undefined;
|
||||||
|
|
||||||
fn testsExecFn(
|
fn testExecFn(
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
js_env: *jsruntime.Env,
|
js_env: *jsruntime.Env,
|
||||||
comptime apis: []jsruntime.API,
|
comptime apis: []jsruntime.API,
|
||||||
|
comptime execFn: jsruntime.ContextExecFn,
|
||||||
) !void {
|
) !void {
|
||||||
|
|
||||||
// start JS env
|
// start JS env
|
||||||
js_env.start(apis);
|
js_env.start(apis);
|
||||||
defer js_env.stop();
|
defer js_env.stop();
|
||||||
|
|
||||||
|
// document
|
||||||
|
doc = try parser.documentHTMLParseFromFileAlloc(std.testing.allocator, "test.html");
|
||||||
|
defer parser.documentHTMLClose(doc);
|
||||||
|
|
||||||
// add document object
|
// add document object
|
||||||
try js_env.addObject(apis, doc, "document");
|
try js_env.addObject(apis, doc, "document");
|
||||||
|
|
||||||
// run tests
|
// run test
|
||||||
try docTestExecFn(alloc, js_env, apis);
|
try execFn(alloc, js_env, apis);
|
||||||
try nodeTestExecFn(alloc, js_env, apis);
|
}
|
||||||
|
|
||||||
|
fn testsAllExecFn(
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
js_env: *jsruntime.Env,
|
||||||
|
comptime apis: []jsruntime.API,
|
||||||
|
) !void {
|
||||||
|
const testFns = [_]jsruntime.ContextExecFn{
|
||||||
|
docTestExecFn,
|
||||||
|
nodeTestExecFn,
|
||||||
|
characterDataTestExecFn,
|
||||||
|
};
|
||||||
|
|
||||||
|
inline for (testFns) |testFn| {
|
||||||
|
try testExecFn(alloc, js_env, apis, testFn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@@ -37,10 +59,6 @@ test {
|
|||||||
// generate APIs
|
// generate APIs
|
||||||
const apis = jsruntime.compile(DOM.Interfaces);
|
const apis = jsruntime.compile(DOM.Interfaces);
|
||||||
|
|
||||||
// document
|
|
||||||
doc = try parser.documentHTMLParseFromFileAlloc(std.testing.allocator, "test.html");
|
|
||||||
defer parser.documentHTMLClose(doc);
|
|
||||||
|
|
||||||
// create JS vm
|
// create JS vm
|
||||||
const vm = jsruntime.VM.init();
|
const vm = jsruntime.VM.init();
|
||||||
defer vm.deinit();
|
defer vm.deinit();
|
||||||
@@ -49,5 +67,5 @@ test {
|
|||||||
var arena_alloc = std.heap.ArenaAllocator.init(bench_alloc.allocator());
|
var arena_alloc = std.heap.ArenaAllocator.init(bench_alloc.allocator());
|
||||||
defer arena_alloc.deinit();
|
defer arena_alloc.deinit();
|
||||||
|
|
||||||
try jsruntime.loadEnv(&arena_alloc, testsExecFn, apis);
|
try jsruntime.loadEnv(&arena_alloc, testsAllExecFn, apis);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user