diff --git a/src/browser/html/elements.zig b/src/browser/html/elements.zig
index 785c3fda..969b3635 100644
--- a/src/browser/html/elements.zig
+++ b/src/browser/html/elements.zig
@@ -1109,77 +1109,80 @@ pub const HTMLVideoElement = struct {
};
pub fn toInterface(comptime T: type, e: *parser.Element) !T {
- const elem: *align(@alignOf(*parser.Element)) parser.Element = @alignCast(e);
- const tag = try parser.elementHTMLGetTagType(@as(*parser.ElementHTML, @ptrCast(elem)));
+ const tagname = try parser.elementGetTagName(e) orelse {
+ // in case of null tagname, return an uknonwn HTMLElement.
+ return .{ .HTMLUnknownElement = @as(*parser.Unknown, @ptrCast(e)) };
+ };
+ const tag = try parser.Tag.fromString(tagname);
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)) },
- .a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(elem)) },
- .applet => .{ .HTMLAppletElement = @as(*parser.Applet, @ptrCast(elem)) },
- .area => .{ .HTMLAreaElement = @as(*parser.Area, @ptrCast(elem)) },
- .audio => .{ .HTMLAudioElement = @as(*parser.Audio, @ptrCast(elem)) },
- .base => .{ .HTMLBaseElement = @as(*parser.Base, @ptrCast(elem)) },
- .body => .{ .HTMLBodyElement = @as(*parser.Body, @ptrCast(elem)) },
- .br => .{ .HTMLBRElement = @as(*parser.BR, @ptrCast(elem)) },
- .button => .{ .HTMLButtonElement = @as(*parser.Button, @ptrCast(elem)) },
- .canvas => .{ .HTMLCanvasElement = @as(*parser.Canvas, @ptrCast(elem)) },
- .dl => .{ .HTMLDListElement = @as(*parser.DList, @ptrCast(elem)) },
- .data => .{ .HTMLDataElement = @as(*parser.Data, @ptrCast(elem)) },
- .datalist => .{ .HTMLDataListElement = @as(*parser.DataList, @ptrCast(elem)) },
- .dialog => .{ .HTMLDialogElement = @as(*parser.Dialog, @ptrCast(elem)) },
- .dir => .{ .HTMLDirectoryElement = @as(*parser.Directory, @ptrCast(elem)) },
- .div => .{ .HTMLDivElement = @as(*parser.Div, @ptrCast(elem)) },
- .embed => .{ .HTMLEmbedElement = @as(*parser.Embed, @ptrCast(elem)) },
- .fieldset => .{ .HTMLFieldSetElement = @as(*parser.FieldSet, @ptrCast(elem)) },
- .font => .{ .HTMLFontElement = @as(*parser.Font, @ptrCast(elem)) },
- .form => .{ .HTMLFormElement = @as(*parser.Form, @ptrCast(elem)) },
- .frame => .{ .HTMLFrameElement = @as(*parser.Frame, @ptrCast(elem)) },
- .frameset => .{ .HTMLFrameSetElement = @as(*parser.FrameSet, @ptrCast(elem)) },
- .hr => .{ .HTMLHRElement = @as(*parser.HR, @ptrCast(elem)) },
- .head => .{ .HTMLHeadElement = @as(*parser.Head, @ptrCast(elem)) },
- .h1, .h2, .h3, .h4, .h5, .h6 => .{ .HTMLHeadingElement = @as(*parser.Heading, @ptrCast(elem)) },
- .html => .{ .HTMLHtmlElement = @as(*parser.Html, @ptrCast(elem)) },
- .iframe => .{ .HTMLIFrameElement = @as(*parser.IFrame, @ptrCast(elem)) },
- .img => .{ .HTMLImageElement = @as(*parser.Image, @ptrCast(elem)) },
- .input => .{ .HTMLInputElement = @as(*parser.Input, @ptrCast(elem)) },
- .li => .{ .HTMLLIElement = @as(*parser.LI, @ptrCast(elem)) },
- .label => .{ .HTMLLabelElement = @as(*parser.Label, @ptrCast(elem)) },
- .legend => .{ .HTMLLegendElement = @as(*parser.Legend, @ptrCast(elem)) },
- .link => .{ .HTMLLinkElement = @as(*parser.Link, @ptrCast(elem)) },
- .map => .{ .HTMLMapElement = @as(*parser.Map, @ptrCast(elem)) },
- .meta => .{ .HTMLMetaElement = @as(*parser.Meta, @ptrCast(elem)) },
- .meter => .{ .HTMLMeterElement = @as(*parser.Meter, @ptrCast(elem)) },
- .ins, .del => .{ .HTMLModElement = @as(*parser.Mod, @ptrCast(elem)) },
- .ol => .{ .HTMLOListElement = @as(*parser.OList, @ptrCast(elem)) },
- .object => .{ .HTMLObjectElement = @as(*parser.Object, @ptrCast(elem)) },
- .optgroup => .{ .HTMLOptGroupElement = @as(*parser.OptGroup, @ptrCast(elem)) },
- .option => .{ .HTMLOptionElement = @as(*parser.Option, @ptrCast(elem)) },
- .output => .{ .HTMLOutputElement = @as(*parser.Output, @ptrCast(elem)) },
- .p => .{ .HTMLParagraphElement = @as(*parser.Paragraph, @ptrCast(elem)) },
- .param => .{ .HTMLParamElement = @as(*parser.Param, @ptrCast(elem)) },
- .picture => .{ .HTMLPictureElement = @as(*parser.Picture, @ptrCast(elem)) },
- .pre => .{ .HTMLPreElement = @as(*parser.Pre, @ptrCast(elem)) },
- .progress => .{ .HTMLProgressElement = @as(*parser.Progress, @ptrCast(elem)) },
- .blockquote, .q => .{ .HTMLQuoteElement = @as(*parser.Quote, @ptrCast(elem)) },
- .script => .{ .HTMLScriptElement = @as(*parser.Script, @ptrCast(elem)) },
- .select => .{ .HTMLSelectElement = @as(*parser.Select, @ptrCast(elem)) },
- .source => .{ .HTMLSourceElement = @as(*parser.Source, @ptrCast(elem)) },
- .span => .{ .HTMLSpanElement = @as(*parser.Span, @ptrCast(elem)) },
- .style => .{ .HTMLStyleElement = @as(*parser.Style, @ptrCast(elem)) },
- .table => .{ .HTMLTableElement = @as(*parser.Table, @ptrCast(elem)) },
- .caption => .{ .HTMLTableCaptionElement = @as(*parser.TableCaption, @ptrCast(elem)) },
- .th, .td => .{ .HTMLTableCellElement = @as(*parser.TableCell, @ptrCast(elem)) },
- .col, .colgroup => .{ .HTMLTableColElement = @as(*parser.TableCol, @ptrCast(elem)) },
- .tr => .{ .HTMLTableRowElement = @as(*parser.TableRow, @ptrCast(elem)) },
- .thead, .tbody, .tfoot => .{ .HTMLTableSectionElement = @as(*parser.TableSection, @ptrCast(elem)) },
- .template => .{ .HTMLTemplateElement = @as(*parser.Template, @ptrCast(elem)) },
- .textarea => .{ .HTMLTextAreaElement = @as(*parser.TextArea, @ptrCast(elem)) },
- .time => .{ .HTMLTimeElement = @as(*parser.Time, @ptrCast(elem)) },
- .title => .{ .HTMLTitleElement = @as(*parser.Title, @ptrCast(elem)) },
- .track => .{ .HTMLTrackElement = @as(*parser.Track, @ptrCast(elem)) },
- .ul => .{ .HTMLUListElement = @as(*parser.UList, @ptrCast(elem)) },
- .video => .{ .HTMLVideoElement = @as(*parser.Video, @ptrCast(elem)) },
- .undef => .{ .HTMLUnknownElement = @as(*parser.Unknown, @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(e)) },
+ .a => .{ .HTMLAnchorElement = @as(*parser.Anchor, @ptrCast(e)) },
+ .applet => .{ .HTMLAppletElement = @as(*parser.Applet, @ptrCast(e)) },
+ .area => .{ .HTMLAreaElement = @as(*parser.Area, @ptrCast(e)) },
+ .audio => .{ .HTMLAudioElement = @as(*parser.Audio, @ptrCast(e)) },
+ .base => .{ .HTMLBaseElement = @as(*parser.Base, @ptrCast(e)) },
+ .body => .{ .HTMLBodyElement = @as(*parser.Body, @ptrCast(e)) },
+ .br => .{ .HTMLBRElement = @as(*parser.BR, @ptrCast(e)) },
+ .button => .{ .HTMLButtonElement = @as(*parser.Button, @ptrCast(e)) },
+ .canvas => .{ .HTMLCanvasElement = @as(*parser.Canvas, @ptrCast(e)) },
+ .dl => .{ .HTMLDListElement = @as(*parser.DList, @ptrCast(e)) },
+ .data => .{ .HTMLDataElement = @as(*parser.Data, @ptrCast(e)) },
+ .datalist => .{ .HTMLDataListElement = @as(*parser.DataList, @ptrCast(e)) },
+ .dialog => .{ .HTMLDialogElement = @as(*parser.Dialog, @ptrCast(e)) },
+ .dir => .{ .HTMLDirectoryElement = @as(*parser.Directory, @ptrCast(e)) },
+ .div => .{ .HTMLDivElement = @as(*parser.Div, @ptrCast(e)) },
+ .embed => .{ .HTMLEmbedElement = @as(*parser.Embed, @ptrCast(e)) },
+ .fieldset => .{ .HTMLFieldSetElement = @as(*parser.FieldSet, @ptrCast(e)) },
+ .font => .{ .HTMLFontElement = @as(*parser.Font, @ptrCast(e)) },
+ .form => .{ .HTMLFormElement = @as(*parser.Form, @ptrCast(e)) },
+ .frame => .{ .HTMLFrameElement = @as(*parser.Frame, @ptrCast(e)) },
+ .frameset => .{ .HTMLFrameSetElement = @as(*parser.FrameSet, @ptrCast(e)) },
+ .hr => .{ .HTMLHRElement = @as(*parser.HR, @ptrCast(e)) },
+ .head => .{ .HTMLHeadElement = @as(*parser.Head, @ptrCast(e)) },
+ .h1, .h2, .h3, .h4, .h5, .h6 => .{ .HTMLHeadingElement = @as(*parser.Heading, @ptrCast(e)) },
+ .html => .{ .HTMLHtmlElement = @as(*parser.Html, @ptrCast(e)) },
+ .iframe => .{ .HTMLIFrameElement = @as(*parser.IFrame, @ptrCast(e)) },
+ .img => .{ .HTMLImageElement = @as(*parser.Image, @ptrCast(e)) },
+ .input => .{ .HTMLInputElement = @as(*parser.Input, @ptrCast(e)) },
+ .li => .{ .HTMLLIElement = @as(*parser.LI, @ptrCast(e)) },
+ .label => .{ .HTMLLabelElement = @as(*parser.Label, @ptrCast(e)) },
+ .legend => .{ .HTMLLegendElement = @as(*parser.Legend, @ptrCast(e)) },
+ .link => .{ .HTMLLinkElement = @as(*parser.Link, @ptrCast(e)) },
+ .map => .{ .HTMLMapElement = @as(*parser.Map, @ptrCast(e)) },
+ .meta => .{ .HTMLMetaElement = @as(*parser.Meta, @ptrCast(e)) },
+ .meter => .{ .HTMLMeterElement = @as(*parser.Meter, @ptrCast(e)) },
+ .ins, .del => .{ .HTMLModElement = @as(*parser.Mod, @ptrCast(e)) },
+ .ol => .{ .HTMLOListElement = @as(*parser.OList, @ptrCast(e)) },
+ .object => .{ .HTMLObjectElement = @as(*parser.Object, @ptrCast(e)) },
+ .optgroup => .{ .HTMLOptGroupElement = @as(*parser.OptGroup, @ptrCast(e)) },
+ .option => .{ .HTMLOptionElement = @as(*parser.Option, @ptrCast(e)) },
+ .output => .{ .HTMLOutputElement = @as(*parser.Output, @ptrCast(e)) },
+ .p => .{ .HTMLParagraphElement = @as(*parser.Paragraph, @ptrCast(e)) },
+ .param => .{ .HTMLParamElement = @as(*parser.Param, @ptrCast(e)) },
+ .picture => .{ .HTMLPictureElement = @as(*parser.Picture, @ptrCast(e)) },
+ .pre => .{ .HTMLPreElement = @as(*parser.Pre, @ptrCast(e)) },
+ .progress => .{ .HTMLProgressElement = @as(*parser.Progress, @ptrCast(e)) },
+ .blockquote, .q => .{ .HTMLQuoteElement = @as(*parser.Quote, @ptrCast(e)) },
+ .script => .{ .HTMLScriptElement = @as(*parser.Script, @ptrCast(e)) },
+ .select => .{ .HTMLSelectElement = @as(*parser.Select, @ptrCast(e)) },
+ .source => .{ .HTMLSourceElement = @as(*parser.Source, @ptrCast(e)) },
+ .span => .{ .HTMLSpanElement = @as(*parser.Span, @ptrCast(e)) },
+ .style => .{ .HTMLStyleElement = @as(*parser.Style, @ptrCast(e)) },
+ .table => .{ .HTMLTableElement = @as(*parser.Table, @ptrCast(e)) },
+ .caption => .{ .HTMLTableCaptionElement = @as(*parser.TableCaption, @ptrCast(e)) },
+ .th, .td => .{ .HTMLTableCellElement = @as(*parser.TableCell, @ptrCast(e)) },
+ .col, .colgroup => .{ .HTMLTableColElement = @as(*parser.TableCol, @ptrCast(e)) },
+ .tr => .{ .HTMLTableRowElement = @as(*parser.TableRow, @ptrCast(e)) },
+ .thead, .tbody, .tfoot => .{ .HTMLTableSectionElement = @as(*parser.TableSection, @ptrCast(e)) },
+ .template => .{ .HTMLTemplateElement = @as(*parser.Template, @ptrCast(e)) },
+ .textarea => .{ .HTMLTextAreaElement = @as(*parser.TextArea, @ptrCast(e)) },
+ .time => .{ .HTMLTimeElement = @as(*parser.Time, @ptrCast(e)) },
+ .title => .{ .HTMLTitleElement = @as(*parser.Title, @ptrCast(e)) },
+ .track => .{ .HTMLTrackElement = @as(*parser.Track, @ptrCast(e)) },
+ .ul => .{ .HTMLUListElement = @as(*parser.UList, @ptrCast(e)) },
+ .video => .{ .HTMLVideoElement = @as(*parser.Video, @ptrCast(e)) },
+ .undef => .{ .HTMLUnknownElement = @as(*parser.Unknown, @ptrCast(e)) },
};
}
diff --git a/src/browser/netsurf.zig b/src/browser/netsurf.zig
index 9b17cf5a..ffdcfe3c 100644
--- a/src/browser/netsurf.zig
+++ b/src/browser/netsurf.zig
@@ -328,6 +328,24 @@ pub const Tag = enum(u8) {
else => upperName(@tagName(tag)),
};
}
+
+ pub fn fromString(tagname: []const u8) !Tag {
+ inline for (@typeInfo(Tag).@"enum".fields) |field| {
+ if (std.ascii.eqlIgnoreCase(field.name, tagname)) {
+ return @enumFromInt(field.value);
+ }
+ }
+
+ return error.Invalid;
+ }
+
+ const testing = @import("../testing.zig");
+ test "Tag.elementTag" {
+ try testing.expect(try Tag.fromString("ABBR") == .abbr);
+ try testing.expect(try Tag.fromString("abbr") == .abbr);
+
+ try testing.expect(Tag.fromString("foo") == error.Invalid);
+ }
};
// DOMException
@@ -1577,6 +1595,15 @@ fn elementVtable(elem: *Element) c.dom_element_vtable {
return getVtable(c.dom_element_vtable, Element, elem);
}
+pub fn elementGetTagName(elem: *Element) !?[]const u8 {
+ var s: ?*String = undefined;
+ const err = elementVtable(elem).dom_element_get_tag_name.?(elem, &s);
+ try DOMErr(err);
+ if (s == null) return null;
+
+ return strToData(s.?);
+}
+
pub fn elementGetAttribute(elem: *Element, name: []const u8) !?[]const u8 {
var s: ?*String = undefined;
const err = elementVtable(elem).dom_element_get_attribute.?(elem, try strFromData(name), &s);