mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-04-01 18:06:46 +00:00
Compare commits
17 Commits
pandasurf
...
custom_ele
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7f209b70a | ||
|
|
9b35736be3 | ||
|
|
9f54cb35f4 | ||
|
|
329bffb127 | ||
|
|
e2542f41b5 | ||
|
|
efc7b9d4a5 | ||
|
|
72915760c4 | ||
|
|
e9d7a946c5 | ||
|
|
714e5e0456 | ||
|
|
26e8642aca | ||
|
|
68dfb4ee86 | ||
|
|
f1ff789334 | ||
|
|
1f45d5b8e4 | ||
|
|
c20052f314 | ||
|
|
c28d87d59c | ||
|
|
237ddcba9a | ||
|
|
eadb5b6461 |
@@ -605,6 +605,7 @@ pub const Parser = struct {
|
|||||||
.after, .backdrop, .before, .cue, .first_letter => return .{ .pseudo_element = pseudo_class },
|
.after, .backdrop, .before, .cue, .first_letter => return .{ .pseudo_element = pseudo_class },
|
||||||
.first_line, .grammar_error, .marker, .placeholder => return .{ .pseudo_element = pseudo_class },
|
.first_line, .grammar_error, .marker, .placeholder => return .{ .pseudo_element = pseudo_class },
|
||||||
.selection, .spelling_error => return .{ .pseudo_element = pseudo_class },
|
.selection, .spelling_error => return .{ .pseudo_element = pseudo_class },
|
||||||
|
.modal => return .{ .pseudo_element = pseudo_class },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ pub const PseudoClass = enum {
|
|||||||
placeholder,
|
placeholder,
|
||||||
selection,
|
selection,
|
||||||
spelling_error,
|
spelling_error,
|
||||||
|
modal,
|
||||||
|
|
||||||
pub const Error = error{
|
pub const Error = error{
|
||||||
InvalidPseudoClass,
|
InvalidPseudoClass,
|
||||||
@@ -154,6 +155,7 @@ pub const PseudoClass = enum {
|
|||||||
if (std.ascii.eqlIgnoreCase(s, "placeholder")) return .placeholder;
|
if (std.ascii.eqlIgnoreCase(s, "placeholder")) return .placeholder;
|
||||||
if (std.ascii.eqlIgnoreCase(s, "selection")) return .selection;
|
if (std.ascii.eqlIgnoreCase(s, "selection")) return .selection;
|
||||||
if (std.ascii.eqlIgnoreCase(s, "spelling-error")) return .spelling_error;
|
if (std.ascii.eqlIgnoreCase(s, "spelling-error")) return .spelling_error;
|
||||||
|
if (std.ascii.eqlIgnoreCase(s, "modal")) return .modal;
|
||||||
return Error.InvalidPseudoClass;
|
return Error.InvalidPseudoClass;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ pub const CSSStyleDeclaration = struct {
|
|||||||
return self.order.items.len;
|
return self.order.items.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_parentRule() ?CSSRule {
|
pub fn get_parentRule(_: *const CSSStyleDeclaration) ?CSSRule {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const log = @import("../../log.zig");
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
const Page = @import("../page.zig").Page;
|
const Page = @import("../page.zig").Page;
|
||||||
|
|
||||||
@@ -120,9 +121,18 @@ pub const Document = struct {
|
|||||||
return try Element.toInterface(e);
|
return try Element.toInterface(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _createElement(self: *parser.Document, tag_name: []const u8) !ElementUnion {
|
const CreateElementResult = union(enum) {
|
||||||
|
element: ElementUnion,
|
||||||
|
custom: Env.JsObject,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn _createElement(self: *parser.Document, tag_name: []const u8, page: *Page) !CreateElementResult {
|
||||||
|
if (try page.window.custom_elements.newInstance(tag_name)) |ce| {
|
||||||
|
return .{ .custom = ce };
|
||||||
|
}
|
||||||
|
|
||||||
const e = try parser.documentCreateElement(self, tag_name);
|
const e = try parser.documentCreateElement(self, tag_name);
|
||||||
return try Element.toInterface(e);
|
return .{ .element = try Element.toInterface(e) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _createElementNS(self: *parser.Document, ns: []const u8, tag_name: []const u8) !ElementUnion {
|
pub fn _createElementNS(self: *parser.Document, ns: []const u8, tag_name: []const u8) !ElementUnion {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const WebApis = struct {
|
|||||||
@import("xhr/xhr.zig").Interfaces,
|
@import("xhr/xhr.zig").Interfaces,
|
||||||
@import("xhr/form_data.zig").Interfaces,
|
@import("xhr/form_data.zig").Interfaces,
|
||||||
@import("xmlserializer/xmlserializer.zig").Interfaces,
|
@import("xmlserializer/xmlserializer.zig").Interfaces,
|
||||||
|
@import("webcomponents/webcomponents.zig").Interfaces,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const log = @import("../../log.zig");
|
||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
const generate = @import("../../runtime/generate.zig");
|
const generate = @import("../../runtime/generate.zig");
|
||||||
@@ -112,6 +113,10 @@ pub const HTMLElement = struct {
|
|||||||
pub const prototype = *Element;
|
pub const prototype = *Element;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_style(e: *parser.ElementHTML, page: *Page) !*CSSStyleDeclaration {
|
pub fn get_style(e: *parser.ElementHTML, page: *Page) !*CSSStyleDeclaration {
|
||||||
const state = try page.getOrCreateNodeState(@ptrCast(e));
|
const state = try page.getOrCreateNodeState(@ptrCast(e));
|
||||||
return &state.style;
|
return &state.style;
|
||||||
@@ -174,6 +179,10 @@ pub const HTMLMediaElement = struct {
|
|||||||
pub const Self = parser.MediaElement;
|
pub const Self = parser.MediaElement;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// HTML elements
|
// HTML elements
|
||||||
@@ -183,6 +192,10 @@ pub const HTMLUnknownElement = struct {
|
|||||||
pub const Self = parser.Unknown;
|
pub const Self = parser.Unknown;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/#the-a-element
|
// https://html.spec.whatwg.org/#the-a-element
|
||||||
@@ -191,6 +204,10 @@ pub const HTMLAnchorElement = struct {
|
|||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_target(self: *parser.Anchor) ![]const u8 {
|
pub fn get_target(self: *parser.Anchor) ![]const u8 {
|
||||||
return try parser.anchorGetTarget(self);
|
return try parser.anchorGetTarget(self);
|
||||||
}
|
}
|
||||||
@@ -428,144 +445,240 @@ pub const HTMLAppletElement = struct {
|
|||||||
pub const Self = parser.Applet;
|
pub const Self = parser.Applet;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLAreaElement = struct {
|
pub const HTMLAreaElement = struct {
|
||||||
pub const Self = parser.Area;
|
pub const Self = parser.Area;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLAudioElement = struct {
|
pub const HTMLAudioElement = struct {
|
||||||
pub const Self = parser.Audio;
|
pub const Self = parser.Audio;
|
||||||
pub const prototype = *HTMLMediaElement;
|
pub const prototype = *HTMLMediaElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLBRElement = struct {
|
pub const HTMLBRElement = struct {
|
||||||
pub const Self = parser.BR;
|
pub const Self = parser.BR;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLBaseElement = struct {
|
pub const HTMLBaseElement = struct {
|
||||||
pub const Self = parser.Base;
|
pub const Self = parser.Base;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLBodyElement = struct {
|
pub const HTMLBodyElement = struct {
|
||||||
pub const Self = parser.Body;
|
pub const Self = parser.Body;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLButtonElement = struct {
|
pub const HTMLButtonElement = struct {
|
||||||
pub const Self = parser.Button;
|
pub const Self = parser.Button;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLCanvasElement = struct {
|
pub const HTMLCanvasElement = struct {
|
||||||
pub const Self = parser.Canvas;
|
pub const Self = parser.Canvas;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLDListElement = struct {
|
pub const HTMLDListElement = struct {
|
||||||
pub const Self = parser.DList;
|
pub const Self = parser.DList;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLDataElement = struct {
|
pub const HTMLDataElement = struct {
|
||||||
pub const Self = parser.Data;
|
pub const Self = parser.Data;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLDataListElement = struct {
|
pub const HTMLDataListElement = struct {
|
||||||
pub const Self = parser.DataList;
|
pub const Self = parser.DataList;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLDialogElement = struct {
|
pub const HTMLDialogElement = struct {
|
||||||
pub const Self = parser.Dialog;
|
pub const Self = parser.Dialog;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLDirectoryElement = struct {
|
pub const HTMLDirectoryElement = struct {
|
||||||
pub const Self = parser.Directory;
|
pub const Self = parser.Directory;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLDivElement = struct {
|
pub const HTMLDivElement = struct {
|
||||||
pub const Self = parser.Div;
|
pub const Self = parser.Div;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLEmbedElement = struct {
|
pub const HTMLEmbedElement = struct {
|
||||||
pub const Self = parser.Embed;
|
pub const Self = parser.Embed;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLFieldSetElement = struct {
|
pub const HTMLFieldSetElement = struct {
|
||||||
pub const Self = parser.FieldSet;
|
pub const Self = parser.FieldSet;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLFontElement = struct {
|
pub const HTMLFontElement = struct {
|
||||||
pub const Self = parser.Font;
|
pub const Self = parser.Font;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLFrameElement = struct {
|
pub const HTMLFrameElement = struct {
|
||||||
pub const Self = parser.Frame;
|
pub const Self = parser.Frame;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLFrameSetElement = struct {
|
pub const HTMLFrameSetElement = struct {
|
||||||
pub const Self = parser.FrameSet;
|
pub const Self = parser.FrameSet;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLHRElement = struct {
|
pub const HTMLHRElement = struct {
|
||||||
pub const Self = parser.HR;
|
pub const Self = parser.HR;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLHeadElement = struct {
|
pub const HTMLHeadElement = struct {
|
||||||
pub const Self = parser.Head;
|
pub const Self = parser.Head;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLHeadingElement = struct {
|
pub const HTMLHeadingElement = struct {
|
||||||
pub const Self = parser.Heading;
|
pub const Self = parser.Heading;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLHtmlElement = struct {
|
pub const HTMLHtmlElement = struct {
|
||||||
pub const Self = parser.Html;
|
pub const Self = parser.Html;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLIFrameElement = struct {
|
pub const HTMLIFrameElement = struct {
|
||||||
pub const Self = parser.IFrame;
|
pub const Self = parser.IFrame;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLImageElement = struct {
|
pub const HTMLImageElement = struct {
|
||||||
@@ -573,6 +686,10 @@ pub const HTMLImageElement = struct {
|
|||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_alt(self: *parser.Image) ![]const u8 {
|
pub fn get_alt(self: *parser.Image) ![]const u8 {
|
||||||
return try parser.imageGetAlt(self);
|
return try parser.imageGetAlt(self);
|
||||||
}
|
}
|
||||||
@@ -613,6 +730,7 @@ pub const HTMLImageElement = struct {
|
|||||||
pub const Factory = struct {
|
pub const Factory = struct {
|
||||||
pub const js_name = "Image";
|
pub const js_name = "Image";
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
pub const js_legacy_factory = true;
|
pub const js_legacy_factory = true;
|
||||||
pub const prototype = *HTMLImageElement;
|
pub const prototype = *HTMLImageElement;
|
||||||
|
|
||||||
@@ -631,6 +749,10 @@ pub const HTMLInputElement = struct {
|
|||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_defaultValue(self: *parser.Input) ![]const u8 {
|
pub fn get_defaultValue(self: *parser.Input) ![]const u8 {
|
||||||
return try parser.inputGetDefaultValue(self);
|
return try parser.inputGetDefaultValue(self);
|
||||||
}
|
}
|
||||||
@@ -719,114 +841,190 @@ pub const HTMLLIElement = struct {
|
|||||||
pub const Self = parser.LI;
|
pub const Self = parser.LI;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLLabelElement = struct {
|
pub const HTMLLabelElement = struct {
|
||||||
pub const Self = parser.Label;
|
pub const Self = parser.Label;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLLegendElement = struct {
|
pub const HTMLLegendElement = struct {
|
||||||
pub const Self = parser.Legend;
|
pub const Self = parser.Legend;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLLinkElement = struct {
|
pub const HTMLLinkElement = struct {
|
||||||
pub const Self = parser.Link;
|
pub const Self = parser.Link;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLMapElement = struct {
|
pub const HTMLMapElement = struct {
|
||||||
pub const Self = parser.Map;
|
pub const Self = parser.Map;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLMetaElement = struct {
|
pub const HTMLMetaElement = struct {
|
||||||
pub const Self = parser.Meta;
|
pub const Self = parser.Meta;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLMeterElement = struct {
|
pub const HTMLMeterElement = struct {
|
||||||
pub const Self = parser.Meter;
|
pub const Self = parser.Meter;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLModElement = struct {
|
pub const HTMLModElement = struct {
|
||||||
pub const Self = parser.Mod;
|
pub const Self = parser.Mod;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLOListElement = struct {
|
pub const HTMLOListElement = struct {
|
||||||
pub const Self = parser.OList;
|
pub const Self = parser.OList;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLObjectElement = struct {
|
pub const HTMLObjectElement = struct {
|
||||||
pub const Self = parser.Object;
|
pub const Self = parser.Object;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLOptGroupElement = struct {
|
pub const HTMLOptGroupElement = struct {
|
||||||
pub const Self = parser.OptGroup;
|
pub const Self = parser.OptGroup;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLOptionElement = struct {
|
pub const HTMLOptionElement = struct {
|
||||||
pub const Self = parser.Option;
|
pub const Self = parser.Option;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLOutputElement = struct {
|
pub const HTMLOutputElement = struct {
|
||||||
pub const Self = parser.Output;
|
pub const Self = parser.Output;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLParagraphElement = struct {
|
pub const HTMLParagraphElement = struct {
|
||||||
pub const Self = parser.Paragraph;
|
pub const Self = parser.Paragraph;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLParamElement = struct {
|
pub const HTMLParamElement = struct {
|
||||||
pub const Self = parser.Param;
|
pub const Self = parser.Param;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLPictureElement = struct {
|
pub const HTMLPictureElement = struct {
|
||||||
pub const Self = parser.Picture;
|
pub const Self = parser.Picture;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLPreElement = struct {
|
pub const HTMLPreElement = struct {
|
||||||
pub const Self = parser.Pre;
|
pub const Self = parser.Pre;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLProgressElement = struct {
|
pub const HTMLProgressElement = struct {
|
||||||
pub const Self = parser.Progress;
|
pub const Self = parser.Progress;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLQuoteElement = struct {
|
pub const HTMLQuoteElement = struct {
|
||||||
pub const Self = parser.Quote;
|
pub const Self = parser.Quote;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/#the-script-element
|
// https://html.spec.whatwg.org/#the-script-element
|
||||||
@@ -835,6 +1033,10 @@ pub const HTMLScriptElement = struct {
|
|||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_src(self: *parser.Script) !?[]const u8 {
|
pub fn get_src(self: *parser.Script) !?[]const u8 {
|
||||||
return try parser.elementGetAttribute(
|
return try parser.elementGetAttribute(
|
||||||
parser.scriptToElt(self),
|
parser.scriptToElt(self),
|
||||||
@@ -969,101 +1171,166 @@ pub const HTMLSourceElement = struct {
|
|||||||
pub const Self = parser.Source;
|
pub const Self = parser.Source;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLSpanElement = struct {
|
pub const HTMLSpanElement = struct {
|
||||||
pub const Self = parser.Span;
|
pub const Self = parser.Span;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLStyleElement = struct {
|
pub const HTMLStyleElement = struct {
|
||||||
pub const Self = parser.Style;
|
pub const Self = parser.Style;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTableElement = struct {
|
pub const HTMLTableElement = struct {
|
||||||
pub const Self = parser.Table;
|
pub const Self = parser.Table;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTableCaptionElement = struct {
|
pub const HTMLTableCaptionElement = struct {
|
||||||
pub const Self = parser.TableCaption;
|
pub const Self = parser.TableCaption;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTableCellElement = struct {
|
pub const HTMLTableCellElement = struct {
|
||||||
pub const Self = parser.TableCell;
|
pub const Self = parser.TableCell;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTableColElement = struct {
|
pub const HTMLTableColElement = struct {
|
||||||
pub const Self = parser.TableCol;
|
pub const Self = parser.TableCol;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTableRowElement = struct {
|
pub const HTMLTableRowElement = struct {
|
||||||
pub const Self = parser.TableRow;
|
pub const Self = parser.TableRow;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTableSectionElement = struct {
|
pub const HTMLTableSectionElement = struct {
|
||||||
pub const Self = parser.TableSection;
|
pub const Self = parser.TableSection;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTemplateElement = struct {
|
pub const HTMLTemplateElement = struct {
|
||||||
pub const Self = parser.Template;
|
pub const Self = parser.Template;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTextAreaElement = struct {
|
pub const HTMLTextAreaElement = struct {
|
||||||
pub const Self = parser.TextArea;
|
pub const Self = parser.TextArea;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTimeElement = struct {
|
pub const HTMLTimeElement = struct {
|
||||||
pub const Self = parser.Time;
|
pub const Self = parser.Time;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTitleElement = struct {
|
pub const HTMLTitleElement = struct {
|
||||||
pub const Self = parser.Title;
|
pub const Self = parser.Title;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLTrackElement = struct {
|
pub const HTMLTrackElement = struct {
|
||||||
pub const Self = parser.Track;
|
pub const Self = parser.Track;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLUListElement = struct {
|
pub const HTMLUListElement = struct {
|
||||||
pub const Self = parser.UList;
|
pub const Self = parser.UList;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLVideoElement = struct {
|
pub const HTMLVideoElement = struct {
|
||||||
pub const Self = parser.Video;
|
pub const Self = parser.Video;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const subtype = .node;
|
pub const subtype = .node;
|
||||||
|
|
||||||
|
pub fn constructor(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
return constructHtmlElement(page, js_this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn toInterface(comptime T: type, e: *parser.Element) !T {
|
pub fn toInterface(comptime T: type, e: *parser.Element) !T {
|
||||||
const elem: *align(@alignOf(*parser.Element)) parser.Element = @alignCast(e);
|
const elem: *align(@alignOf(*parser.Element)) parser.Element = @alignCast(e);
|
||||||
const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem)));
|
const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem)));
|
||||||
|
|
||||||
return switch (tag) {
|
return switch (tag) {
|
||||||
.abbr, .acronym, .address, .article, .aside, .b, .basefont, .bdi, .bdo, .bgsound, .big, .center, .cite, .code, .dd, .details, .dfn, .dt, .em, .figcaption, .figure, .footer, .header, .hgroup, .i, .isindex, .keygen, .kbd, .main, .mark, .marquee, .menu, .menuitem, .nav, .nobr, .noframes, .noscript, .rp, .rt, .ruby, .s, .samp, .section, .small, .spacer, .strike, .strong, .sub, .summary, .sup, .tt, .u, .wbr, ._var => .{ .HTMLElement = @as(*parser.ElementHTML, @ptrCast(elem)) },
|
.abbr, .acronym, .address, .article, .aside, .b, .basefont, .bdi, .bdo, .bgsound, .big, .center, .cite, .code, .dd, .details, .dfn, .dt, .em, .figcaption, .figure, .footer, .header, .hgroup, .i, .isindex, .keygen, .kbd, .main, .mark, .marquee, .menu, .menuitem, .nav, .nobr, .noframes, .noscript, .rp, .rt, .ruby, .s, .samp, .section, .small, .spacer, .strike, .strong, .sub, .summary, .sup, .tt, .u, .wbr, ._var => .{ .HTMLElement = @as(*parser.ElementHTML, @ptrCast(elem)) },
|
||||||
.a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(elem)) },
|
.a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(elem)) },
|
||||||
@@ -1135,6 +1402,16 @@ pub fn toInterface(comptime T: type, e: *parser.Element) !T {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn constructHtmlElement(page: *Page, js_this: Env.JsThis) !*parser.Element {
|
||||||
|
const constructor_name = try js_this.constructorName(page.call_arena);
|
||||||
|
if (!page.window.custom_elements.lookup.contains(constructor_name)) {
|
||||||
|
return error.IllegalContructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const el = try parser.documentCreateElement(@ptrCast(page.window.document), constructor_name);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
|
||||||
const testing = @import("../../testing.zig");
|
const testing = @import("../../testing.zig");
|
||||||
test "Browser.HTML.Element" {
|
test "Browser.HTML.Element" {
|
||||||
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
|
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ const EventTarget = @import("../dom/event_target.zig").EventTarget;
|
|||||||
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
|
||||||
const Performance = @import("performance.zig").Performance;
|
const Performance = @import("performance.zig").Performance;
|
||||||
const CSSStyleDeclaration = @import("../cssom/css_style_declaration.zig").CSSStyleDeclaration;
|
const CSSStyleDeclaration = @import("../cssom/css_style_declaration.zig").CSSStyleDeclaration;
|
||||||
|
const CustomElementRegistry = @import("../webcomponents/custom_element_registry.zig").CustomElementRegistry;
|
||||||
|
|
||||||
const storage = @import("../storage/storage.zig");
|
const storage = @import("../storage/storage.zig");
|
||||||
|
|
||||||
@@ -58,6 +59,7 @@ pub const Window = struct {
|
|||||||
console: Console = .{},
|
console: Console = .{},
|
||||||
navigator: Navigator = .{},
|
navigator: Navigator = .{},
|
||||||
performance: Performance,
|
performance: Performance,
|
||||||
|
custom_elements: CustomElementRegistry = .{},
|
||||||
|
|
||||||
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window {
|
pub fn create(target: ?[]const u8, navigator: ?Navigator) !Window {
|
||||||
var fbs = std.io.fixedBufferStream("");
|
var fbs = std.io.fixedBufferStream("");
|
||||||
@@ -163,6 +165,10 @@ pub const Window = struct {
|
|||||||
return &self.performance;
|
return &self.performance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_customElements(self: *Window) *CustomElementRegistry {
|
||||||
|
return &self.custom_elements;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn _requestAnimationFrame(self: *Window, cbk: Function, page: *Page) !u32 {
|
pub fn _requestAnimationFrame(self: *Window, cbk: Function, page: *Page) !u32 {
|
||||||
return self.createTimeout(cbk, 5, page, .{ .animation_frame = true });
|
return self.createTimeout(cbk, 5, page, .{ .animation_frame = true });
|
||||||
}
|
}
|
||||||
@@ -337,20 +343,15 @@ test "Browser.HTML.Window" {
|
|||||||
// Note however that we in this test do not wait as the request is just send to the browser
|
// Note however that we in this test do not wait as the request is just send to the browser
|
||||||
try runner.testCases(&.{
|
try runner.testCases(&.{
|
||||||
.{
|
.{
|
||||||
\\ let start;
|
\\ let start = 0;
|
||||||
\\ function step(timestamp) {
|
\\ function step(timestamp) {
|
||||||
\\ if (start === undefined) {
|
|
||||||
\\ start = timestamp;
|
\\ start = timestamp;
|
||||||
\\ }
|
\\ }
|
||||||
\\ const elapsed = timestamp - start;
|
|
||||||
\\ if (elapsed < 2000) {
|
|
||||||
\\ requestAnimationFrame(step);
|
|
||||||
\\ }
|
|
||||||
\\ }
|
|
||||||
,
|
,
|
||||||
null,
|
null,
|
||||||
},
|
},
|
||||||
.{ "requestAnimationFrame(step);", null }, // returned id is checked in the next test
|
.{ "requestAnimationFrame(step);", null }, // returned id is checked in the next test
|
||||||
|
.{ " start > 0", "true" },
|
||||||
}, .{});
|
}, .{});
|
||||||
|
|
||||||
// cancelAnimationFrame should be able to cancel a request with the given id
|
// cancelAnimationFrame should be able to cancel a request with the given id
|
||||||
|
|||||||
@@ -2189,12 +2189,12 @@ pub inline fn documentCreateAttributeNS(doc: *Document, ns: []const u8, qname: [
|
|||||||
return attr.?;
|
return attr.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn documentSetScriptAddedCallback(
|
pub fn documentSetElementAddedCallback(
|
||||||
doc: *Document,
|
doc: *Document,
|
||||||
ctx: *anyopaque,
|
ctx: *anyopaque,
|
||||||
callback: c.dom_script_added_callback,
|
callback: c.dom_element_added_callback,
|
||||||
) void {
|
) void {
|
||||||
c._dom_document_set_script_added_callback(doc, ctx, callback);
|
c._dom_document_set_element_added_callback(doc, ctx, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocumentHTML
|
// DocumentHTML
|
||||||
|
|||||||
@@ -297,16 +297,17 @@ pub const Page = struct {
|
|||||||
self.window.setStorageShelf(
|
self.window.setStorageShelf(
|
||||||
try self.session.storage_shed.getOrPut(try self.origin(self.arena)),
|
try self.session.storage_shed.getOrPut(try self.origin(self.arena)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// we want to be notified of any dynamically added script tags
|
||||||
|
// so that we can load the script. Or dynamically added custom elements
|
||||||
|
// for their lifecycle callbacks.
|
||||||
|
parser.documentSetElementAddedCallback(doc, self, elementAddedCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn processHTMLDoc(self: *Page) !void {
|
fn processHTMLDoc(self: *Page) !void {
|
||||||
const html_doc = self.window.document;
|
const html_doc = self.window.document;
|
||||||
const doc = parser.documentHTMLToDocument(html_doc);
|
const doc = parser.documentHTMLToDocument(html_doc);
|
||||||
|
|
||||||
// we want to be notified of any dynamically added script tags
|
|
||||||
// so that we can load the script
|
|
||||||
parser.documentSetScriptAddedCallback(doc, self, scriptAddedCallback);
|
|
||||||
|
|
||||||
const document_element = (try parser.documentGetDocumentElement(doc)) orelse return error.DocumentElementError;
|
const document_element = (try parser.documentGetDocumentElement(doc)) orelse return error.DocumentElementError;
|
||||||
_ = try parser.eventTargetAddEventListener(
|
_ = try parser.eventTargetAddEventListener(
|
||||||
parser.toEventTarget(parser.Element, document_element),
|
parser.toEventTarget(parser.Element, document_element),
|
||||||
@@ -352,8 +353,23 @@ pub const Page = struct {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const e = parser.nodeToElement(next.?);
|
const current = next.?;
|
||||||
|
|
||||||
|
const e = parser.nodeToElement(current);
|
||||||
const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(e)));
|
const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(e)));
|
||||||
|
|
||||||
|
// if (tag == .undef) {
|
||||||
|
// const tag_name = try parser.nodeLocalName(@ptrCast(e));
|
||||||
|
// const custom_elements = &self.window.custom_elements;
|
||||||
|
// if (custom_elements._get(tag_name)) |construct| {
|
||||||
|
// try construct.printFunc();
|
||||||
|
// // This is just here for testing for now.
|
||||||
|
// // var result: Env.Function.Result = undefined;
|
||||||
|
// // _ = try construct.newInstance(*parser.Element, &result);
|
||||||
|
// log.info(.browser, "Registered WebComponent Found", .{ .element_name = tag_name });
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
if (tag != .script) {
|
if (tag != .script) {
|
||||||
// ignore non-js script.
|
// ignore non-js script.
|
||||||
continue;
|
continue;
|
||||||
@@ -802,6 +818,43 @@ pub const Page = struct {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn elementAdded(self: *Page, element: *parser.Element) !void {
|
||||||
|
if (self.delayed_navigation) {
|
||||||
|
// if we're planning on navigating to another page, we can skip whatever
|
||||||
|
// this is.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(element)))) {
|
||||||
|
.script => {
|
||||||
|
var script = Script.init(element, self) catch |err| {
|
||||||
|
log.warn(.browser, "script added", .{ .err = err });
|
||||||
|
return;
|
||||||
|
} orelse return;
|
||||||
|
_ = self.evalScript(&script);
|
||||||
|
},
|
||||||
|
.undef => {
|
||||||
|
// a custom element
|
||||||
|
const js_obj = self.main_context.getJsObject(element) orelse return;
|
||||||
|
|
||||||
|
// @memory
|
||||||
|
// getFunction, and more generally Env.Function always create
|
||||||
|
// a Persisted Object. But, in cases like this, we don't need
|
||||||
|
// it to persist.
|
||||||
|
const func = (try js_obj.getFunction("connectedCallback")) orelse return;
|
||||||
|
|
||||||
|
var result: Env.Function.Result = undefined;
|
||||||
|
func.tryCallWithThis(void, js_obj, .{}, &result) catch {
|
||||||
|
log.warn(.user_script, "connected callback", .{
|
||||||
|
.err = result.exception,
|
||||||
|
.stack = result.stack,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const DelayedNavigation = struct {
|
const DelayedNavigation = struct {
|
||||||
@@ -1075,24 +1128,22 @@ fn timestamp() u32 {
|
|||||||
return @intCast(ts.sec);
|
return @intCast(ts.sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A callback from libdom whenever a script tag is added to the DOM.
|
// A callback from libdom whenever an html element is added to the DOM.
|
||||||
|
// Note that "added" could mean that it was removed from one parent and re-added
|
||||||
|
// to another, which is how MOST APIs implement "move" (corrently so).
|
||||||
|
//
|
||||||
|
// The only API which seems to actual "move" is Element.moveBefore, which we
|
||||||
|
// don't currently implement, but should support in general, and should handle
|
||||||
|
// specifically here.
|
||||||
// element is guaranteed to be a script element.
|
// element is guaranteed to be a script element.
|
||||||
// The script tag might not have a src. It might be any attribute, like
|
// The script tag might not have a src. It might have any attribute, like
|
||||||
// `nomodule`, `defer` and `async`. `Script.init` will return null on `nomodule`
|
// `nomodule`, `defer` and `async`. `Script.init` will return null on `nomodule`
|
||||||
// so that's handled. And because we're only executing the inline <script> tags
|
// so that's handled. And because we're only executing the inline <script> tags
|
||||||
// after the document is loaded, it's ok to execute any async and defer scripts
|
// after the document is loaded, it's ok to execute any async and defer scripts
|
||||||
// immediately.
|
// immediately.
|
||||||
pub export fn scriptAddedCallback(ctx: ?*anyopaque, element: ?*parser.Element) callconv(.C) void {
|
pub export fn elementAddedCallback(ctx: ?*anyopaque, element: ?*parser.Element) callconv(.C) void {
|
||||||
const self: *Page = @alignCast(@ptrCast(ctx.?));
|
const self: *Page = @alignCast(@ptrCast(ctx.?));
|
||||||
if (self.delayed_navigation) {
|
self.elementAdded(element.?) catch |err| {
|
||||||
// if we're planning on navigating to another page, don't run this script
|
log.warn(.browser, "element added callback", .{ .err = err });
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
var script = Script.init(element.?, self) catch |err| {
|
|
||||||
log.warn(.browser, "script added init error", .{ .err = err });
|
|
||||||
return;
|
|
||||||
} orelse return;
|
|
||||||
|
|
||||||
_ = self.evalScript(&script);
|
|
||||||
}
|
}
|
||||||
|
|||||||
115
src/browser/webcomponents/custom_element_registry.zig
Normal file
115
src/browser/webcomponents/custom_element_registry.zig
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const log = @import("../../log.zig");
|
||||||
|
const v8 = @import("v8");
|
||||||
|
|
||||||
|
const Env = @import("../env.zig").Env;
|
||||||
|
const Page = @import("../page.zig").Page;
|
||||||
|
|
||||||
|
pub const CustomElementRegistry = struct {
|
||||||
|
// tag_name -> Function
|
||||||
|
lookup: std.StringHashMapUnmanaged(Env.Function) = .empty,
|
||||||
|
|
||||||
|
pub fn _define(self: *CustomElementRegistry, tag_name: []const u8, fun: Env.Function, page: *Page) !void {
|
||||||
|
log.info(.browser, "define custom element", .{ .name = tag_name });
|
||||||
|
|
||||||
|
const arena = page.arena;
|
||||||
|
const gop = try self.lookup.getOrPut(arena, tag_name);
|
||||||
|
if (!gop.found_existing) {
|
||||||
|
errdefer _ = self.lookup.remove(tag_name);
|
||||||
|
const owned_tag_name = try arena.dupe(u8, tag_name);
|
||||||
|
gop.key_ptr.* = owned_tag_name;
|
||||||
|
}
|
||||||
|
gop.value_ptr.* = fun;
|
||||||
|
fun.setName(tag_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn _get(self: *CustomElementRegistry, name: []const u8) ?Env.Function {
|
||||||
|
return self.lookup.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn newInstance(self: *const CustomElementRegistry, tag_name: []const u8) !?Env.JsObject {
|
||||||
|
const func = self.lookup.get(tag_name) orelse return null;
|
||||||
|
|
||||||
|
var result: Env.Function.Result = undefined;
|
||||||
|
const js_obj = func.newInstance(&result) catch |err| {
|
||||||
|
log.fatal(.user_script, "newInstance error", .{
|
||||||
|
.err = result.exception,
|
||||||
|
.stack = result.stack,
|
||||||
|
.tag_name = tag_name,
|
||||||
|
.source = "createElement",
|
||||||
|
});
|
||||||
|
return err;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is associated with an HTML element, which, at the very least
|
||||||
|
// is going to be libdom node. It will outlive this call, and thus needs
|
||||||
|
// to be persisted.
|
||||||
|
return try js_obj.persist();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testing = @import("../../testing.zig");
|
||||||
|
|
||||||
|
test "Browser.CustomElementRegistry" {
|
||||||
|
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
|
||||||
|
defer runner.deinit();
|
||||||
|
try runner.testCases(&.{
|
||||||
|
// Basic registry access
|
||||||
|
.{ "typeof customElements", "object" },
|
||||||
|
.{ "customElements instanceof CustomElementRegistry", "true" },
|
||||||
|
|
||||||
|
// Define a simple custom element
|
||||||
|
.{
|
||||||
|
\\ class MyElement extends HTMLElement {
|
||||||
|
\\ constructor() {
|
||||||
|
\\ super();
|
||||||
|
\\ this.textContent = 'created';
|
||||||
|
\\ }
|
||||||
|
\\
|
||||||
|
\\ connectedCallback() {
|
||||||
|
\\ this.textContent = 'connected';
|
||||||
|
\\ }
|
||||||
|
\\ }
|
||||||
|
,
|
||||||
|
null,
|
||||||
|
},
|
||||||
|
.{ "customElements.define('my-element', MyElement)", "undefined" },
|
||||||
|
|
||||||
|
// Check if element is defined
|
||||||
|
.{ "customElements.get('my-element') === MyElement", "true" },
|
||||||
|
// .{ "customElements.get('non-existent')", "null" },
|
||||||
|
|
||||||
|
// Create element via document.createElement
|
||||||
|
.{ "let el = document.createElement('my-element')", "undefined" },
|
||||||
|
.{ "el instanceof MyElement", "true" },
|
||||||
|
.{ "el instanceof HTMLElement", "true" },
|
||||||
|
.{ "el.tagName", "MY-ELEMENT" },
|
||||||
|
.{ "el.textContent", "created" },
|
||||||
|
.{ "document.getElementsByTagName('body')[0].append(el)", null },
|
||||||
|
.{ "el.textContent", "connected" },
|
||||||
|
|
||||||
|
// Create element via HTML parsing
|
||||||
|
// .{ "document.body.innerHTML = '<my-element></my-element>'", "undefined" },
|
||||||
|
// .{ "let parsed = document.querySelector('my-element')", "undefined" },
|
||||||
|
// .{ "parsed instanceof MyElement", "true" },
|
||||||
|
// .{ "parsed.textContent", "Hello World" },
|
||||||
|
}, .{});
|
||||||
|
}
|
||||||
23
src/browser/webcomponents/webcomponents.zig
Normal file
23
src/browser/webcomponents/webcomponents.zig
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
||||||
|
//
|
||||||
|
// Francis Bouvier <francis@lightpanda.io>
|
||||||
|
// Pierre Tachoire <pierre@lightpanda.io>
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const CustomElementRegistry = @import("custom_element_registry.zig").CustomElementRegistry;
|
||||||
|
|
||||||
|
pub const Interfaces = .{
|
||||||
|
CustomElementRegistry,
|
||||||
|
};
|
||||||
@@ -115,17 +115,24 @@ const EntryIterable = iterator.Iterable(kv.EntryIterator, "FormDataEntryIterator
|
|||||||
// TODO: handle disabled fieldsets
|
// TODO: handle disabled fieldsets
|
||||||
fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page) !kv.List {
|
fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page) !kv.List {
|
||||||
const arena = page.arena;
|
const arena = page.arena;
|
||||||
const collection = try parser.formGetCollection(form);
|
|
||||||
const len = try parser.htmlCollectionGetLength(collection);
|
// Don't use libdom's formGetCollection (aka dom_html_form_element_get_elements)
|
||||||
|
// It doesn't work with dynamically added elements, because their form
|
||||||
|
// property doesn't get set. We should fix that.
|
||||||
|
// However, even once fixed, there are other form-collection features we
|
||||||
|
// probably want to implement (like disabled fieldsets), so we might want
|
||||||
|
// to stick with our own walker even if fix libdom to properly support
|
||||||
|
// dynamically added elements.
|
||||||
|
const node_list = try @import("../dom/css.zig").querySelectorAll(arena, @alignCast(@ptrCast(form)), "input,select,button,textarea");
|
||||||
|
const nodes = node_list.nodes.items;
|
||||||
|
|
||||||
var entries: kv.List = .{};
|
var entries: kv.List = .{};
|
||||||
try entries.ensureTotalCapacity(arena, len);
|
try entries.ensureTotalCapacity(arena, nodes.len);
|
||||||
|
|
||||||
var submitter_included = false;
|
var submitter_included = false;
|
||||||
const submitter_name_ = try getSubmitterName(submitter_);
|
const submitter_name_ = try getSubmitterName(submitter_);
|
||||||
|
|
||||||
for (0..len) |i| {
|
for (nodes) |node| {
|
||||||
const node = try parser.htmlCollectionItem(collection, @intCast(i));
|
|
||||||
const element = parser.nodeToElement(node);
|
const element = parser.nodeToElement(node);
|
||||||
|
|
||||||
// must have a name
|
// must have a name
|
||||||
@@ -181,10 +188,7 @@ fn collectForm(form: *parser.Form, submitter_: ?*parser.ElementHTML, page: *Page
|
|||||||
submitter_included = true;
|
submitter_included = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
else => {
|
else => unreachable,
|
||||||
log.warn(.web_api, "unsupported form element", .{ .tag = @tagName(tag) });
|
|
||||||
continue;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,6 +301,7 @@ test "Browser.FormData" {
|
|||||||
\\ <input type=submit name=s2 value=s2-v>
|
\\ <input type=submit name=s2 value=s2-v>
|
||||||
\\ <input type=image name=i1 value=i1-v>
|
\\ <input type=image name=i1 value=i1-v>
|
||||||
\\ </form>
|
\\ </form>
|
||||||
|
\\ <input type=text name=abc value=123 form=form1>
|
||||||
});
|
});
|
||||||
defer runner.deinit();
|
defer runner.deinit();
|
||||||
|
|
||||||
@@ -356,6 +361,8 @@ test "Browser.FormData" {
|
|||||||
|
|
||||||
try runner.testCases(&.{
|
try runner.testCases(&.{
|
||||||
.{ "let form1 = document.getElementById('form1')", null },
|
.{ "let form1 = document.getElementById('form1')", null },
|
||||||
|
.{ "let input = document.createElement('input');", null },
|
||||||
|
.{ "input.name = 'dyn'; input.value= 'dyn-v'; form1.appendChild(input);", null },
|
||||||
.{ "let submit1 = document.getElementById('s1')", null },
|
.{ "let submit1 = document.getElementById('s1')", null },
|
||||||
.{ "let f2 = new FormData(form1, submit1)", null },
|
.{ "let f2 = new FormData(form1, submit1)", null },
|
||||||
.{ "acc = '';", null },
|
.{ "acc = '';", null },
|
||||||
@@ -378,6 +385,7 @@ test "Browser.FormData" {
|
|||||||
\\mlt-2=water
|
\\mlt-2=water
|
||||||
\\mlt-2=tea
|
\\mlt-2=tea
|
||||||
\\s1=s1-v
|
\\s1=s1-v
|
||||||
|
\\dyn=dyn-v
|
||||||
},
|
},
|
||||||
}, .{});
|
}, .{});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ const json = std.json;
|
|||||||
const log = @import("../log.zig");
|
const log = @import("../log.zig");
|
||||||
const App = @import("../app.zig").App;
|
const App = @import("../app.zig").App;
|
||||||
const Env = @import("../browser/env.zig").Env;
|
const Env = @import("../browser/env.zig").Env;
|
||||||
const asUint = @import("../str/parser.zig").asUint;
|
|
||||||
const Browser = @import("../browser/browser.zig").Browser;
|
const Browser = @import("../browser/browser.zig").Browser;
|
||||||
const Session = @import("../browser/session.zig").Session;
|
const Session = @import("../browser/session.zig").Session;
|
||||||
const Page = @import("../browser/page.zig").Page;
|
const Page = @import("../browser/page.zig").Page;
|
||||||
@@ -182,41 +181,41 @@ pub fn CDPT(comptime TypeProvider: type) type {
|
|||||||
|
|
||||||
switch (domain.len) {
|
switch (domain.len) {
|
||||||
3 => switch (@as(u24, @bitCast(domain[0..3].*))) {
|
3 => switch (@as(u24, @bitCast(domain[0..3].*))) {
|
||||||
asUint("DOM") => return @import("domains/dom.zig").processMessage(command),
|
asUint(u24, "DOM") => return @import("domains/dom.zig").processMessage(command),
|
||||||
asUint("Log") => return @import("domains/log.zig").processMessage(command),
|
asUint(u24, "Log") => return @import("domains/log.zig").processMessage(command),
|
||||||
asUint("CSS") => return @import("domains/css.zig").processMessage(command),
|
asUint(u24, "CSS") => return @import("domains/css.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
4 => switch (@as(u32, @bitCast(domain[0..4].*))) {
|
4 => switch (@as(u32, @bitCast(domain[0..4].*))) {
|
||||||
asUint("Page") => return @import("domains/page.zig").processMessage(command),
|
asUint(u32, "Page") => return @import("domains/page.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
5 => switch (@as(u40, @bitCast(domain[0..5].*))) {
|
5 => switch (@as(u40, @bitCast(domain[0..5].*))) {
|
||||||
asUint("Fetch") => return @import("domains/fetch.zig").processMessage(command),
|
asUint(u40, "Fetch") => return @import("domains/fetch.zig").processMessage(command),
|
||||||
asUint("Input") => return @import("domains/input.zig").processMessage(command),
|
asUint(u40, "Input") => return @import("domains/input.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
6 => switch (@as(u48, @bitCast(domain[0..6].*))) {
|
6 => switch (@as(u48, @bitCast(domain[0..6].*))) {
|
||||||
asUint("Target") => return @import("domains/target.zig").processMessage(command),
|
asUint(u48, "Target") => return @import("domains/target.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
7 => switch (@as(u56, @bitCast(domain[0..7].*))) {
|
7 => switch (@as(u56, @bitCast(domain[0..7].*))) {
|
||||||
asUint("Browser") => return @import("domains/browser.zig").processMessage(command),
|
asUint(u56, "Browser") => return @import("domains/browser.zig").processMessage(command),
|
||||||
asUint("Runtime") => return @import("domains/runtime.zig").processMessage(command),
|
asUint(u56, "Runtime") => return @import("domains/runtime.zig").processMessage(command),
|
||||||
asUint("Network") => return @import("domains/network.zig").processMessage(command),
|
asUint(u56, "Network") => return @import("domains/network.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
8 => switch (@as(u64, @bitCast(domain[0..8].*))) {
|
8 => switch (@as(u64, @bitCast(domain[0..8].*))) {
|
||||||
asUint("Security") => return @import("domains/security.zig").processMessage(command),
|
asUint(u64, "Security") => return @import("domains/security.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
9 => switch (@as(u72, @bitCast(domain[0..9].*))) {
|
9 => switch (@as(u72, @bitCast(domain[0..9].*))) {
|
||||||
asUint("Emulation") => return @import("domains/emulation.zig").processMessage(command),
|
asUint(u72, "Emulation") => return @import("domains/emulation.zig").processMessage(command),
|
||||||
asUint("Inspector") => return @import("domains/inspector.zig").processMessage(command),
|
asUint(u72, "Inspector") => return @import("domains/inspector.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
11 => switch (@as(u88, @bitCast(domain[0..11].*))) {
|
11 => switch (@as(u88, @bitCast(domain[0..11].*))) {
|
||||||
asUint("Performance") => return @import("domains/performance.zig").processMessage(command),
|
asUint(u88, "Performance") => return @import("domains/performance.zig").processMessage(command),
|
||||||
else => {},
|
else => {},
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
@@ -696,6 +695,10 @@ const InputParams = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn asUint(comptime T: type, comptime string: []const u8) T {
|
||||||
|
return @bitCast(string[0..string.len].*);
|
||||||
|
}
|
||||||
|
|
||||||
const testing = @import("testing.zig");
|
const testing = @import("testing.zig");
|
||||||
test "cdp: invalid json" {
|
test "cdp: invalid json" {
|
||||||
var ctx = testing.context();
|
var ctx = testing.context();
|
||||||
|
|||||||
@@ -3170,7 +3170,7 @@ test "HttpClient: async tls no body" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test "HttpClient: async tls with body x" {
|
test "HttpClient: async tls with body" {
|
||||||
defer testing.reset();
|
defer testing.reset();
|
||||||
for (0..5) |_| {
|
for (0..5) |_| {
|
||||||
var client = try testClient();
|
var client = try testClient();
|
||||||
|
|||||||
27
src/log.zig
27
src/log.zig
@@ -146,6 +146,16 @@ fn logTo(comptime scope: Scope, level: Level, comptime msg: []const u8, data: an
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn logLogfmt(comptime scope: Scope, level: Level, comptime msg: []const u8, data: anytype, writer: anytype) !void {
|
fn logLogfmt(comptime scope: Scope, level: Level, comptime msg: []const u8, data: anytype, writer: anytype) !void {
|
||||||
|
try logLogFmtPrefix(scope, level, msg, writer);
|
||||||
|
inline for (@typeInfo(@TypeOf(data)).@"struct".fields) |f| {
|
||||||
|
const key = " " ++ f.name ++ "=";
|
||||||
|
try writer.writeAll(key);
|
||||||
|
try writeValue(.logfmt, @field(data, f.name), writer);
|
||||||
|
}
|
||||||
|
try writer.writeByte('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
fn logLogFmtPrefix(comptime scope: Scope, level: Level, comptime msg: []const u8, writer: anytype) !void {
|
||||||
try writer.writeAll("$time=");
|
try writer.writeAll("$time=");
|
||||||
try writer.print("{d}", .{timestamp()});
|
try writer.print("{d}", .{timestamp()});
|
||||||
|
|
||||||
@@ -164,15 +174,20 @@ fn logLogfmt(comptime scope: Scope, level: Level, comptime msg: []const u8, data
|
|||||||
break :blk prefix ++ "\"" ++ msg ++ "\"";
|
break :blk prefix ++ "\"" ++ msg ++ "\"";
|
||||||
};
|
};
|
||||||
try writer.writeAll(full_msg);
|
try writer.writeAll(full_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn logPretty(comptime scope: Scope, level: Level, comptime msg: []const u8, data: anytype, writer: anytype) !void {
|
||||||
|
try logPrettyPrefix(scope, level, msg, writer);
|
||||||
inline for (@typeInfo(@TypeOf(data)).@"struct".fields) |f| {
|
inline for (@typeInfo(@TypeOf(data)).@"struct".fields) |f| {
|
||||||
const key = " " ++ f.name ++ " = ";
|
const key = " " ++ f.name ++ " = ";
|
||||||
try writer.writeAll(key);
|
try writer.writeAll(key);
|
||||||
try writeValue(.logfmt, @field(data, f.name), writer);
|
try writeValue(.pretty, @field(data, f.name), writer);
|
||||||
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logPretty(comptime scope: Scope, level: Level, comptime msg: []const u8, data: anytype, writer: anytype) !void {
|
fn logPrettyPrefix(comptime scope: Scope, level: Level, comptime msg: []const u8, writer: anytype) !void {
|
||||||
if (scope == .console and level == .fatal and comptime std.mem.eql(u8, msg, "lightpanda")) {
|
if (scope == .console and level == .fatal and comptime std.mem.eql(u8, msg, "lightpanda")) {
|
||||||
try writer.writeAll("\x1b[0;104mWARN ");
|
try writer.writeAll("\x1b[0;104mWARN ");
|
||||||
} else {
|
} else {
|
||||||
@@ -201,14 +216,6 @@ fn logPretty(comptime scope: Scope, level: Level, comptime msg: []const u8, data
|
|||||||
try writer.print(" \x1b[0m[+{d}ms]", .{elapsed()});
|
try writer.print(" \x1b[0m[+{d}ms]", .{elapsed()});
|
||||||
try writer.writeByte('\n');
|
try writer.writeByte('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
inline for (@typeInfo(@TypeOf(data)).@"struct".fields) |f| {
|
|
||||||
const key = " " ++ f.name ++ " = ";
|
|
||||||
try writer.writeAll(key);
|
|
||||||
try writeValue(.pretty, @field(data, f.name), writer);
|
|
||||||
try writer.writeByte('\n');
|
|
||||||
}
|
|
||||||
try writer.writeByte('\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeValue(comptime format: Format, value: anytype, writer: anytype) !void {
|
pub fn writeValue(comptime format: Format, value: anytype, writer: anytype) !void {
|
||||||
|
|||||||
@@ -1158,7 +1158,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!js_value.isArray()) {
|
if (!js_value.isArray()) {
|
||||||
return error.InvalidArgument;
|
return .{ .invalid = {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can get tricky.
|
// This can get tricky.
|
||||||
@@ -1196,6 +1196,14 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
return .{ .invalid = {} };
|
return .{ .invalid = {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getJsObject(self: *JsContext, zig_value: *anyopaque) ?JsObject {
|
||||||
|
const po = self.identity_map.get(@intFromPtr(zig_value)) orelse return null;
|
||||||
|
return .{
|
||||||
|
.js_context = self,
|
||||||
|
.js_obj = po.castToObject(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Callback from V8, asking us to load a module. The "specifier" is
|
// Callback from V8, asking us to load a module. The "specifier" is
|
||||||
// the src of the module to load.
|
// the src of the module to load.
|
||||||
fn resolveModuleCallback(
|
fn resolveModuleCallback(
|
||||||
@@ -1257,6 +1265,16 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
exception: []const u8,
|
exception: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn getName(self: *const Function, allocator: Allocator) ![]const u8 {
|
||||||
|
const name = self.func.castToFunction().getName();
|
||||||
|
return valueToString(allocator, name, self.js_context.isolate, self.js_context.v8_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setName(self: *const Function, name: []const u8) void {
|
||||||
|
const v8_name = v8.String.initUtf8(self.js_context.isolate, name);
|
||||||
|
self.func.castToFunction().setName(v8_name);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn withThis(self: *const Function, value: anytype) !Function {
|
pub fn withThis(self: *const Function, value: anytype) !Function {
|
||||||
const this_obj = if (@TypeOf(value) == JsObject)
|
const this_obj = if (@TypeOf(value) == JsObject)
|
||||||
value.js_obj
|
value.js_obj
|
||||||
@@ -1271,6 +1289,33 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn newInstance(self: *const Function, result: *Result) !JsObject {
|
||||||
|
const context = self.js_context;
|
||||||
|
|
||||||
|
var try_catch: TryCatch = undefined;
|
||||||
|
try_catch.init(context);
|
||||||
|
defer try_catch.deinit();
|
||||||
|
|
||||||
|
// This creates a new instance using this Function as a constructor.
|
||||||
|
// This returns a generic Object
|
||||||
|
const js_obj = self.func.castToFunction().initInstance(context.v8_context, &.{}) orelse {
|
||||||
|
if (try_catch.hasCaught()) {
|
||||||
|
const allocator = context.call_arena;
|
||||||
|
result.stack = try_catch.stack(allocator) catch null;
|
||||||
|
result.exception = (try_catch.exception(allocator) catch "???") orelse "???";
|
||||||
|
} else {
|
||||||
|
result.stack = null;
|
||||||
|
result.exception = "???";
|
||||||
|
}
|
||||||
|
return error.JsConstructorFailed;
|
||||||
|
};
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.js_context = context,
|
||||||
|
.js_obj = js_obj,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn call(self: *const Function, comptime T: type, args: anytype) !T {
|
pub fn call(self: *const Function, comptime T: type, args: anytype) !T {
|
||||||
return self.callWithThis(T, self.getThis(), args);
|
return self.callWithThis(T, self.getThis(), args);
|
||||||
}
|
}
|
||||||
@@ -1450,6 +1495,11 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
.js_obj = array.castTo(v8.Object),
|
.js_obj = array.castTo(v8.Object),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn constructorName(self: JsObject, allocator: Allocator) ![]const u8 {
|
||||||
|
const str = try self.js_obj.getConstructorName();
|
||||||
|
return jsStringToZig(allocator, str, self.js_context.isolate);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This only exists so that we know whether a function wants the opaque
|
// This only exists so that we know whether a function wants the opaque
|
||||||
@@ -1472,6 +1522,10 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
pub fn set(self: JsThis, key: []const u8, value: anytype, opts: JsObject.SetOpts) !void {
|
pub fn set(self: JsThis, key: []const u8, value: anytype, opts: JsObject.SetOpts) !void {
|
||||||
return self.obj.set(key, value, opts);
|
return self.obj.set(key, value, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn constructorName(self: JsThis, allocator: Allocator) ![]const u8 {
|
||||||
|
return try self.obj.constructorName(allocator);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const TryCatch = struct {
|
pub const TryCatch = struct {
|
||||||
@@ -1784,7 +1838,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
// a constructor function, we'll return an error.
|
// a constructor function, we'll return an error.
|
||||||
if (@hasDecl(Struct, "constructor") == false) {
|
if (@hasDecl(Struct, "constructor") == false) {
|
||||||
const iso = caller.isolate;
|
const iso = caller.isolate;
|
||||||
const js_exception = iso.throwException(createException(iso, "illegal constructor"));
|
const js_exception = iso.throwException(createException(iso, "Illegal Constructor"));
|
||||||
info.getReturnValue().set(js_exception);
|
info.getReturnValue().set(js_exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1876,7 +1930,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
const named_function = comptime NamedFunction.init(Struct, "get_" ++ name);
|
const named_function = comptime NamedFunction.init(Struct, "get_" ++ name);
|
||||||
caller.getter(Struct, named_function, info) catch |err| {
|
caller.method(Struct, named_function, info) catch |err| {
|
||||||
caller.handleError(Struct, named_function, err, info);
|
caller.handleError(Struct, named_function, err, info);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1891,13 +1945,13 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
|
|||||||
const setter_callback = v8.FunctionTemplate.initCallback(isolate, struct {
|
const setter_callback = v8.FunctionTemplate.initCallback(isolate, struct {
|
||||||
fn callback(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
fn callback(raw_info: ?*const v8.C_FunctionCallbackInfo) callconv(.c) void {
|
||||||
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
const info = v8.FunctionCallbackInfo.initFromV8(raw_info);
|
||||||
|
std.debug.assert(info.length() == 1);
|
||||||
|
|
||||||
var caller = Caller(Self, State).init(info);
|
var caller = Caller(Self, State).init(info);
|
||||||
defer caller.deinit();
|
defer caller.deinit();
|
||||||
|
|
||||||
std.debug.assert(info.length() == 1);
|
|
||||||
const js_value = info.getArg(0);
|
|
||||||
const named_function = comptime NamedFunction.init(Struct, "set_" ++ name);
|
const named_function = comptime NamedFunction.init(Struct, "set_" ++ name);
|
||||||
caller.setter(Struct, named_function, js_value, info) catch |err| {
|
caller.method(Struct, named_function, info) catch |err| {
|
||||||
caller.handleError(Struct, named_function, err, info);
|
caller.handleError(Struct, named_function, err, info);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2424,66 +2478,6 @@ fn Caller(comptime E: type, comptime State: type) type {
|
|||||||
info.getReturnValue().set(try js_context.zigValueToJs(res));
|
info.getReturnValue().set(try js_context.zigValueToJs(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getter(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, info: v8.FunctionCallbackInfo) !void {
|
|
||||||
const js_context = self.js_context;
|
|
||||||
const func = @field(Struct, named_function.name);
|
|
||||||
const Getter = @TypeOf(func);
|
|
||||||
if (@typeInfo(Getter).@"fn".return_type == null) {
|
|
||||||
@compileError(@typeName(Struct) ++ " has a getter without a return type: " ++ @typeName(Getter));
|
|
||||||
}
|
|
||||||
|
|
||||||
var args: ParamterTypes(Getter) = undefined;
|
|
||||||
const arg_fields = @typeInfo(@TypeOf(args)).@"struct".fields;
|
|
||||||
switch (arg_fields.len) {
|
|
||||||
0 => {}, // getters _can_ be parameterless
|
|
||||||
1, 2 => {
|
|
||||||
const zig_instance = try E.typeTaggedAnyOpaque(named_function, *Receiver(Struct), info.getThis());
|
|
||||||
comptime assertSelfReceiver(Struct, named_function);
|
|
||||||
@field(args, "0") = zig_instance;
|
|
||||||
if (comptime arg_fields.len == 2) {
|
|
||||||
comptime assertIsStateArg(Struct, named_function, 1);
|
|
||||||
@field(args, "1") = js_context.state;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => @compileError(named_function.full_name + " has too many parmaters: " ++ @typeName(named_function.func)),
|
|
||||||
}
|
|
||||||
const res = @call(.auto, func, args);
|
|
||||||
info.getReturnValue().set(try js_context.zigValueToJs(res));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setter(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, js_value: v8.Value, info: v8.FunctionCallbackInfo) !void {
|
|
||||||
const js_context = self.js_context;
|
|
||||||
const func = @field(Struct, named_function.name);
|
|
||||||
comptime assertSelfReceiver(Struct, named_function);
|
|
||||||
|
|
||||||
const zig_instance = try E.typeTaggedAnyOpaque(named_function, *Receiver(Struct), info.getThis());
|
|
||||||
|
|
||||||
const Setter = @TypeOf(func);
|
|
||||||
var args: ParamterTypes(Setter) = undefined;
|
|
||||||
const arg_fields = @typeInfo(@TypeOf(args)).@"struct".fields;
|
|
||||||
switch (arg_fields.len) {
|
|
||||||
0 => unreachable, // assertSelfReceiver make sure of this
|
|
||||||
1 => @compileError(named_function.full_name ++ " only has 1 parameter"),
|
|
||||||
2, 3 => {
|
|
||||||
@field(args, "0") = zig_instance;
|
|
||||||
@field(args, "1") = try js_context.jsValueToZig(named_function, arg_fields[1].type, js_value);
|
|
||||||
if (comptime arg_fields.len == 3) {
|
|
||||||
comptime assertIsStateArg(Struct, named_function, 2);
|
|
||||||
@field(args, "2") = js_context.state;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => @compileError(named_function.full_name ++ " setter with more than 3 parameters, why?"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@typeInfo(Setter).@"fn".return_type) |return_type| {
|
|
||||||
if (@typeInfo(return_type) == .error_union) {
|
|
||||||
_ = try @call(.auto, func, args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ = @call(.auto, func, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn getIndex(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, idx: u32, info: v8.PropertyCallbackInfo) !u8 {
|
fn getIndex(self: *Self, comptime Struct: type, comptime named_function: NamedFunction, idx: u32, info: v8.PropertyCallbackInfo) !u8 {
|
||||||
const js_context = self.js_context;
|
const js_context = self.js_context;
|
||||||
const func = @field(Struct, named_function.name);
|
const func = @field(Struct, named_function.name);
|
||||||
@@ -2596,19 +2590,14 @@ fn Caller(comptime E: type, comptime State: type) type {
|
|||||||
|
|
||||||
if (comptime builtin.mode == .Debug and @hasDecl(@TypeOf(info), "length")) {
|
if (comptime builtin.mode == .Debug and @hasDecl(@TypeOf(info), "length")) {
|
||||||
if (log.enabled(.js, .warn)) {
|
if (log.enabled(.js, .warn)) {
|
||||||
const args_dump = self.serializeFunctionArgs(info) catch "failed to serialize args";
|
logFunctionCallError(self.call_arena, self.isolate, self.v8_context, err, named_function.full_name, info);
|
||||||
log.warn(.js, "function call error", .{
|
|
||||||
.name = named_function.full_name,
|
|
||||||
.err = err,
|
|
||||||
.args = args_dump,
|
|
||||||
.stack = stackForLogs(self.call_arena, isolate) catch |err1| @errorName(err1),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var js_err: ?v8.Value = switch (err) {
|
var js_err: ?v8.Value = switch (err) {
|
||||||
error.InvalidArgument => createTypeException(isolate, "invalid argument"),
|
error.InvalidArgument => createTypeException(isolate, "invalid argument"),
|
||||||
error.OutOfMemory => createException(isolate, "out of memory"),
|
error.OutOfMemory => createException(isolate, "out of memory"),
|
||||||
|
error.IllegalConstructor => createException(isolate, "Illegal Contructor"),
|
||||||
else => blk: {
|
else => blk: {
|
||||||
const func = @field(Struct, named_function.name);
|
const func = @field(Struct, named_function.name);
|
||||||
const return_type = @typeInfo(@TypeOf(func)).@"fn".return_type orelse {
|
const return_type = @typeInfo(@TypeOf(func)).@"fn".return_type orelse {
|
||||||
@@ -2670,6 +2659,7 @@ fn Caller(comptime E: type, comptime State: type) type {
|
|||||||
// Does the error we want to return belong to the custom exeception's ErrorSet
|
// Does the error we want to return belong to the custom exeception's ErrorSet
|
||||||
fn isErrorSetException(comptime Exception: type, err: anytype) bool {
|
fn isErrorSetException(comptime Exception: type, err: anytype) bool {
|
||||||
const Entry = std.meta.Tuple(&.{ []const u8, void });
|
const Entry = std.meta.Tuple(&.{ []const u8, void });
|
||||||
|
|
||||||
const error_set = @typeInfo(Exception.ErrorSet).error_set.?;
|
const error_set = @typeInfo(Exception.ErrorSet).error_set.?;
|
||||||
const entries = comptime blk: {
|
const entries = comptime blk: {
|
||||||
var kv: [error_set.len]Entry = undefined;
|
var kv: [error_set.len]Entry = undefined;
|
||||||
@@ -2721,8 +2711,8 @@ fn Caller(comptime E: type, comptime State: type) type {
|
|||||||
// a JS argument
|
// a JS argument
|
||||||
if (comptime isJsThis(params[params.len - 1].type.?)) {
|
if (comptime isJsThis(params[params.len - 1].type.?)) {
|
||||||
@field(args, std.fmt.comptimePrint("{d}", .{params.len - 1 + offset})) = .{ .obj = .{
|
@field(args, std.fmt.comptimePrint("{d}", .{params.len - 1 + offset})) = .{ .obj = .{
|
||||||
|
.js_context = js_context,
|
||||||
.js_obj = info.getThis(),
|
.js_obj = info.getThis(),
|
||||||
.executor = self.executor,
|
|
||||||
} };
|
} };
|
||||||
|
|
||||||
// AND the 2nd last parameter is state
|
// AND the 2nd last parameter is state
|
||||||
@@ -2808,28 +2798,6 @@ fn Caller(comptime E: type, comptime State: type) type {
|
|||||||
const Const_State = if (ti == .pointer) *const ti.pointer.child else State;
|
const Const_State = if (ti == .pointer) *const ti.pointer.child else State;
|
||||||
return T == State or T == Const_State;
|
return T == State or T == Const_State;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serializeFunctionArgs(self: *const Self, info: anytype) ![]const u8 {
|
|
||||||
const isolate = self.isolate;
|
|
||||||
const v8_context = self.v8_context;
|
|
||||||
const arena = self.call_arena;
|
|
||||||
const separator = log.separator();
|
|
||||||
const js_parameter_count = info.length();
|
|
||||||
|
|
||||||
var arr: std.ArrayListUnmanaged(u8) = .{};
|
|
||||||
for (0..js_parameter_count) |i| {
|
|
||||||
const js_value = info.getArg(@intCast(i));
|
|
||||||
const value_string = try valueToDetailString(arena, js_value, isolate, v8_context);
|
|
||||||
const value_type = try jsStringToZig(arena, try js_value.typeOf(isolate), isolate);
|
|
||||||
try std.fmt.format(arr.writer(arena), "{s}{d}: {s} ({s})", .{
|
|
||||||
separator,
|
|
||||||
i + 1,
|
|
||||||
value_string,
|
|
||||||
value_type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return arr.items;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3270,6 +3238,37 @@ const NamedFunction = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// This is extracted to speed up compilation. When left inlined in handleError,
|
||||||
|
// this can add as much as 10 seconds of compilation time.
|
||||||
|
fn logFunctionCallError(arena: Allocator, isolate: v8.Isolate, context: v8.Context, err: anyerror, function_name: []const u8, info: v8.FunctionCallbackInfo) void {
|
||||||
|
const args_dump = serializeFunctionArgs(arena, isolate, context, info) catch "failed to serialize args";
|
||||||
|
log.warn(.js, "function call error", .{
|
||||||
|
.name = function_name,
|
||||||
|
.err = err,
|
||||||
|
.args = args_dump,
|
||||||
|
.stack = stackForLogs(arena, isolate) catch |err1| @errorName(err1),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serializeFunctionArgs(arena: Allocator, isolate: v8.Isolate, context: v8.Context, info: v8.FunctionCallbackInfo) ![]const u8 {
|
||||||
|
const separator = log.separator();
|
||||||
|
const js_parameter_count = info.length();
|
||||||
|
|
||||||
|
var arr: std.ArrayListUnmanaged(u8) = .{};
|
||||||
|
for (0..js_parameter_count) |i| {
|
||||||
|
const js_value = info.getArg(@intCast(i));
|
||||||
|
const value_string = try valueToDetailString(arena, js_value, isolate, context);
|
||||||
|
const value_type = try jsStringToZig(arena, try js_value.typeOf(isolate), isolate);
|
||||||
|
try std.fmt.format(arr.writer(arena), "{s}{d}: {s} ({s})", .{
|
||||||
|
separator,
|
||||||
|
i + 1,
|
||||||
|
value_string,
|
||||||
|
value_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return arr.items;
|
||||||
|
}
|
||||||
|
|
||||||
// This is called from V8. Whenever the v8 inspector has to describe a value
|
// This is called from V8. Whenever the v8 inspector has to describe a value
|
||||||
// it'll call this function to gets its [optional] subtype - which, from V8's
|
// it'll call this function to gets its [optional] subtype - which, from V8's
|
||||||
// point of view, is an arbitrary string.
|
// point of view, is an arbitrary string.
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
// Copyright (C) 2023-2024 Lightpanda (Selecy SAS)
|
|
||||||
//
|
|
||||||
// Francis Bouvier <francis@lightpanda.io>
|
|
||||||
// Pierre Tachoire <pierre@lightpanda.io>
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Affero General Public License as
|
|
||||||
// published by the Free Software Foundation, either version 3 of the
|
|
||||||
// License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Affero General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// some utils to parser strings.
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub const Reader = struct {
|
|
||||||
pos: usize = 0,
|
|
||||||
data: []const u8,
|
|
||||||
|
|
||||||
pub fn until(self: *Reader, c: u8) []const u8 {
|
|
||||||
const pos = self.pos;
|
|
||||||
const data = self.data;
|
|
||||||
|
|
||||||
const index = std.mem.indexOfScalarPos(u8, data, pos, c) orelse data.len;
|
|
||||||
self.pos = index;
|
|
||||||
return data[pos..index];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tail(self: *Reader) []const u8 {
|
|
||||||
const pos = self.pos;
|
|
||||||
const data = self.data;
|
|
||||||
if (pos > data.len) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
self.pos = data.len;
|
|
||||||
return data[pos..];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn skip(self: *Reader) bool {
|
|
||||||
const pos = self.pos;
|
|
||||||
if (pos >= self.data.len) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.pos = pos + 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// converts a comptime-known string (i.e. null terminated) to an uint
|
|
||||||
pub fn asUint(comptime string: anytype) AsUintReturn(string) {
|
|
||||||
const byteLength = @bitSizeOf(@TypeOf(string.*)) / 8 - 1;
|
|
||||||
const expectedType = *const [byteLength:0]u8;
|
|
||||||
if (@TypeOf(string) != expectedType) {
|
|
||||||
@compileError("expected : " ++ @typeName(expectedType) ++
|
|
||||||
", got: " ++ @typeName(@TypeOf(string)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return @bitCast(@as(*const [byteLength]u8, string).*);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn AsUintReturn(comptime string: anytype) type {
|
|
||||||
return @Type(.{
|
|
||||||
.int = .{
|
|
||||||
.bits = @bitSizeOf(@TypeOf(string.*)) - 8, // (- 8) to exclude sentinel 0
|
|
||||||
.signedness = .unsigned,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const testing = std.testing;
|
|
||||||
test "parser.Reader: skip" {
|
|
||||||
var r = Reader{ .data = "foo" };
|
|
||||||
try testing.expectEqual(true, r.skip());
|
|
||||||
try testing.expectEqual(true, r.skip());
|
|
||||||
try testing.expectEqual(true, r.skip());
|
|
||||||
try testing.expectEqual(false, r.skip());
|
|
||||||
try testing.expectEqual(false, r.skip());
|
|
||||||
}
|
|
||||||
|
|
||||||
test "parser.Reader: tail" {
|
|
||||||
var r = Reader{ .data = "foo" };
|
|
||||||
try testing.expectEqualStrings("foo", r.tail());
|
|
||||||
try testing.expectEqualStrings("", r.tail());
|
|
||||||
try testing.expectEqualStrings("", r.tail());
|
|
||||||
}
|
|
||||||
|
|
||||||
test "parser.Reader: until" {
|
|
||||||
var r = Reader{ .data = "foo.bar.baz" };
|
|
||||||
try testing.expectEqualStrings("foo", r.until('.'));
|
|
||||||
_ = r.skip();
|
|
||||||
try testing.expectEqualStrings("bar", r.until('.'));
|
|
||||||
_ = r.skip();
|
|
||||||
try testing.expectEqualStrings("baz", r.until('.'));
|
|
||||||
|
|
||||||
r = Reader{ .data = "foo" };
|
|
||||||
try testing.expectEqualStrings("foo", r.until('.'));
|
|
||||||
try testing.expectEqualStrings("", r.tail());
|
|
||||||
|
|
||||||
r = Reader{ .data = "" };
|
|
||||||
try testing.expectEqualStrings("", r.until('.'));
|
|
||||||
try testing.expectEqualStrings("", r.tail());
|
|
||||||
}
|
|
||||||
|
|
||||||
test "parser: asUint" {
|
|
||||||
const ASCII_x = @as(u8, @bitCast([1]u8{'x'}));
|
|
||||||
const ASCII_ab = @as(u16, @bitCast([2]u8{ 'a', 'b' }));
|
|
||||||
const ASCII_xyz = @as(u24, @bitCast([3]u8{ 'x', 'y', 'z' }));
|
|
||||||
const ASCII_abcd = @as(u32, @bitCast([4]u8{ 'a', 'b', 'c', 'd' }));
|
|
||||||
|
|
||||||
try testing.expectEqual(ASCII_x, asUint("x"));
|
|
||||||
try testing.expectEqual(ASCII_ab, asUint("ab"));
|
|
||||||
try testing.expectEqual(ASCII_xyz, asUint("xyz"));
|
|
||||||
try testing.expectEqual(ASCII_abcd, asUint("abcd"));
|
|
||||||
|
|
||||||
try testing.expectEqual(u8, @TypeOf(asUint("x")));
|
|
||||||
try testing.expectEqual(u16, @TypeOf(asUint("ab")));
|
|
||||||
try testing.expectEqual(u24, @TypeOf(asUint("xyz")));
|
|
||||||
try testing.expectEqual(u32, @TypeOf(asUint("abcd")));
|
|
||||||
}
|
|
||||||
2
vendor/netsurf/libdom
vendored
2
vendor/netsurf/libdom
vendored
Submodule vendor/netsurf/libdom updated: 614187b0aa...73d1bc9f23
Reference in New Issue
Block a user