diff --git a/src/browser/tests/element/html/script/dynamic.html b/src/browser/tests/element/html/script/dynamic.html
index a6a0179c1..d67b1ef2e 100644
--- a/src/browser/tests/element/html/script/dynamic.html
+++ b/src/browser/tests/element/html/script/dynamic.html
@@ -42,3 +42,19 @@
testing.expectEqual(2, loaded2);
});
+
+
diff --git a/src/browser/tests/element/html/script/dynamic_attribute.js b/src/browser/tests/element/html/script/dynamic_attribute.js
new file mode 100644
index 000000000..fb2bbac5a
--- /dev/null
+++ b/src/browser/tests/element/html/script/dynamic_attribute.js
@@ -0,0 +1 @@
+loadedByAttribute += 1;
diff --git a/src/browser/webapi/element/html/Script.zig b/src/browser/webapi/element/html/Script.zig
index 72ca44a38..7c3c9864f 100644
--- a/src/browser/webapi/element/html/Script.zig
+++ b/src/browser/webapi/element/html/Script.zig
@@ -16,6 +16,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
const std = @import("std");
+const lp = @import("lightpanda");
const js = @import("../../../js/js.zig");
const Frame = @import("../../../Frame.zig");
@@ -24,6 +25,7 @@ const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const HtmlElement = @import("../Html.zig");
+const String = lp.String;
const Script = @This();
_proto: *HtmlElement,
@@ -50,12 +52,7 @@ pub fn getSrc(self: *Script, frame: *Frame) ![]const u8 {
}
pub fn setSrc(self: *Script, src: []const u8, frame: *Frame) !void {
- const element = self.asElement();
- try element.setAttributeSafe(comptime .wrap("src"), .wrap(src), frame);
- self._src = element.getAttributeSafe(comptime .wrap("src")) orelse unreachable;
- if (element.asNode().isConnected()) {
- try frame.scriptAddedCallback(false, self);
- }
+ try self.asElement().setAttributeSafe(comptime .wrap("src"), .wrap(src), frame);
}
pub fn getType(self: *const Script) []const u8 {
@@ -164,6 +161,24 @@ pub const Build = struct {
self._src = element.getAttributeSafe(comptime .wrap("src")) orelse "";
}
+ pub fn attributeChange(element: *Element, name: String, _: String, frame: *Frame) !void {
+ if (!name.eql(comptime .wrap("src"))) {
+ return;
+ }
+
+ const self = element.as(Script);
+ self._src = element.getAttributeSafe(comptime .wrap("src")) orelse "";
+ if (element.asNode().isConnected()) {
+ try frame.scriptAddedCallback(false, self);
+ }
+ }
+
+ pub fn attributeRemove(element: *Element, name: String, _: *Frame) !void {
+ if (name.eql(comptime .wrap("src"))) {
+ element.as(Script)._src = "";
+ }
+ }
+
// Per the HTML spec, the "already started" flag must be propagated to the
// clone so that re-inserting a cloned