mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-08-01 02:06:17 -04:00
feat(webapi): reflect attributes on HTMLSourceElement
Add the reflected IDL attributes to the existing HTMLSourceElement, which previously reflected none: src (resolved as a URL like HTMLEmbedElement.src), srcset, sizes, media, type, width and height. Mirrors the reflection idiom used by HTMLEmbedElement. width and height are reflected as strings, matching the sibling HTMLEmbedElement accessors. Adds element/html/source.html covering parse-from-markup, property/attribute round-trips and src URL resolution.
This commit is contained in:
77
src/browser/tests/element/html/source.html
Normal file
77
src/browser/tests/element/html/source.html
Normal file
@@ -0,0 +1,77 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../../testing.js"></script>
|
||||
|
||||
<source id="s1" src="/video.webm" srcset="/img-1x.png 1x, /img-2x.png 2x" sizes="100vw" media="(min-width: 600px)" type="video/webm" width="640" height="480">
|
||||
<source id="s2">
|
||||
|
||||
<script id="source-from-html">
|
||||
{
|
||||
const s1 = document.getElementById('s1');
|
||||
testing.expectEqual('HTMLSourceElement', s1.constructor.name);
|
||||
testing.expectEqual(testing.ORIGIN + '/video.webm', s1.src);
|
||||
testing.expectEqual('/img-1x.png 1x, /img-2x.png 2x', s1.srcset);
|
||||
testing.expectEqual('100vw', s1.sizes);
|
||||
testing.expectEqual('(min-width: 600px)', s1.media);
|
||||
testing.expectEqual('video/webm', s1.type);
|
||||
testing.expectEqual('640', s1.width);
|
||||
testing.expectEqual('480', s1.height);
|
||||
|
||||
const s2 = document.getElementById('s2');
|
||||
testing.expectEqual('', s2.src);
|
||||
testing.expectEqual('', s2.srcset);
|
||||
testing.expectEqual('', s2.sizes);
|
||||
testing.expectEqual('', s2.media);
|
||||
testing.expectEqual('', s2.type);
|
||||
testing.expectEqual('', s2.width);
|
||||
testing.expectEqual('', s2.height);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="source-reflection">
|
||||
{
|
||||
const s = document.createElement('source');
|
||||
|
||||
s.srcset = '/a.png 1x';
|
||||
testing.expectEqual('/a.png 1x', s.getAttribute('srcset'));
|
||||
s.setAttribute('srcset', '/b.png 2x');
|
||||
testing.expectEqual('/b.png 2x', s.srcset);
|
||||
|
||||
s.sizes = '50vw';
|
||||
testing.expectEqual('50vw', s.getAttribute('sizes'));
|
||||
s.setAttribute('sizes', '25vw');
|
||||
testing.expectEqual('25vw', s.sizes);
|
||||
|
||||
s.media = 'screen';
|
||||
testing.expectEqual('screen', s.getAttribute('media'));
|
||||
s.setAttribute('media', 'print');
|
||||
testing.expectEqual('print', s.media);
|
||||
|
||||
s.type = 'video/mp4';
|
||||
testing.expectEqual('video/mp4', s.getAttribute('type'));
|
||||
s.setAttribute('type', 'image/svg+xml');
|
||||
testing.expectEqual('image/svg+xml', s.type);
|
||||
|
||||
s.width = '320';
|
||||
testing.expectEqual('320', s.getAttribute('width'));
|
||||
s.setAttribute('width', '160');
|
||||
testing.expectEqual('160', s.width);
|
||||
|
||||
s.height = '240';
|
||||
testing.expectEqual('240', s.getAttribute('height'));
|
||||
s.setAttribute('height', '120');
|
||||
testing.expectEqual('120', s.height);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="source-src-url">
|
||||
{
|
||||
const s = document.createElement('source');
|
||||
testing.expectEqual('', s.src);
|
||||
|
||||
s.src = 'https://lightpanda.io/clip.webm';
|
||||
testing.expectEqual('https://lightpanda.io/clip.webm', s.src);
|
||||
|
||||
s.src = '/relative.webm';
|
||||
testing.expectEqual(testing.ORIGIN + '/relative.webm', s.src);
|
||||
}
|
||||
</script>
|
||||
@@ -1,4 +1,5 @@
|
||||
const js = @import("../../../js/js.zig");
|
||||
const Frame = @import("../../../Frame.zig");
|
||||
const Node = @import("../../Node.zig");
|
||||
const Element = @import("../../Element.zig");
|
||||
const HtmlElement = @import("../Html.zig");
|
||||
@@ -10,10 +11,74 @@ _proto: *HtmlElement,
|
||||
pub fn asElement(self: *Source) *Element {
|
||||
return self._proto._proto;
|
||||
}
|
||||
pub fn asConstElement(self: *const Source) *const Element {
|
||||
return self._proto._proto;
|
||||
}
|
||||
pub fn asNode(self: *Source) *Node {
|
||||
return self.asElement().asNode();
|
||||
}
|
||||
|
||||
pub fn getSrc(self: *const Source, frame: *Frame) ![]const u8 {
|
||||
const element = self.asConstElement();
|
||||
const src = element.getAttributeSafe(comptime .wrap("src")) orelse return "";
|
||||
if (src.len == 0) {
|
||||
return "";
|
||||
}
|
||||
return element.asConstNode().resolveURL(src, frame, .{});
|
||||
}
|
||||
|
||||
pub fn setSrc(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("src"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub fn getSrcset(self: *const Source) []const u8 {
|
||||
return self.asConstElement().getAttributeSafe(comptime .wrap("srcset")) orelse "";
|
||||
}
|
||||
|
||||
pub fn setSrcset(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("srcset"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub fn getSizes(self: *const Source) []const u8 {
|
||||
return self.asConstElement().getAttributeSafe(comptime .wrap("sizes")) orelse "";
|
||||
}
|
||||
|
||||
pub fn setSizes(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("sizes"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub fn getMedia(self: *const Source) []const u8 {
|
||||
return self.asConstElement().getAttributeSafe(comptime .wrap("media")) orelse "";
|
||||
}
|
||||
|
||||
pub fn setMedia(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("media"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub fn getType(self: *const Source) []const u8 {
|
||||
return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse "";
|
||||
}
|
||||
|
||||
pub fn setType(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub fn getWidth(self: *const Source) []const u8 {
|
||||
return self.asConstElement().getAttributeSafe(comptime .wrap("width")) orelse "";
|
||||
}
|
||||
|
||||
pub fn setWidth(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("width"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub fn getHeight(self: *const Source) []const u8 {
|
||||
return self.asConstElement().getAttributeSafe(comptime .wrap("height")) orelse "";
|
||||
}
|
||||
|
||||
pub fn setHeight(self: *Source, value: []const u8, frame: *Frame) !void {
|
||||
try self.asElement().setAttributeSafe(comptime .wrap("height"), .wrap(value), frame);
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
pub const bridge = js.Bridge(Source);
|
||||
|
||||
@@ -22,4 +87,17 @@ pub const JsApi = struct {
|
||||
pub const prototype_chain = bridge.prototypeChain();
|
||||
pub var class_id: bridge.ClassId = undefined;
|
||||
};
|
||||
|
||||
pub const height = bridge.accessor(Source.getHeight, Source.setHeight, .{ .ce_reactions = true });
|
||||
pub const media = bridge.accessor(Source.getMedia, Source.setMedia, .{ .ce_reactions = true });
|
||||
pub const sizes = bridge.accessor(Source.getSizes, Source.setSizes, .{ .ce_reactions = true });
|
||||
pub const src = bridge.accessor(Source.getSrc, Source.setSrc, .{ .ce_reactions = true });
|
||||
pub const srcset = bridge.accessor(Source.getSrcset, Source.setSrcset, .{ .ce_reactions = true });
|
||||
pub const @"type" = bridge.accessor(Source.getType, Source.setType, .{ .ce_reactions = true });
|
||||
pub const width = bridge.accessor(Source.getWidth, Source.setWidth, .{ .ce_reactions = true });
|
||||
};
|
||||
|
||||
const testing = @import("../../../../testing.zig");
|
||||
test "WebApi: HTML.Source" {
|
||||
try testing.htmlRunner("element/html/source.html", .{});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user