mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-24 05:33:16 +00:00
Tweak Finalizer callbacks
1 - Finalizer callbacks are now give a *Page parameter. Various types no longer
need to maintain a reference to *Page just to finalize
2 - EventManager now handles v8_handoff == false cleanup. This is largely
because of the above change, which would require every:
```
defer if (!event._v8_handoff) event.deinit(false);
```
to be turned into:
```
defer if (!event._v8_handoff) event.deinit(false, page);
```
But the caller might not have a page. Besides this, it makes most uses of Event
simpler. But, in some cases, it could leave a window where the event doesn't
reach the EventManager to be properly managed (though, we have no such cases
as of now).
This commit is contained in:
@@ -170,6 +170,8 @@ const DispatchError = error{
|
|||||||
JsException,
|
JsException,
|
||||||
};
|
};
|
||||||
pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) DispatchError!void {
|
pub fn dispatch(self: *EventManager, target: *EventTarget, event: *Event) DispatchError!void {
|
||||||
|
defer if (!event._v8_handoff) event.deinit(false, self.page);
|
||||||
|
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
log.debug(.event, "eventManager.dispatch", .{ .type = event._type_string.str(), .bubbles = event._bubbles });
|
log.debug(.event, "eventManager.dispatch", .{ .type = event._type_string.str(), .bubbles = event._bubbles });
|
||||||
}
|
}
|
||||||
@@ -218,6 +220,8 @@ const DispatchWithFunctionOptions = struct {
|
|||||||
inject_target: bool = true,
|
inject_target: bool = true,
|
||||||
};
|
};
|
||||||
pub fn dispatchWithFunction(self: *EventManager, target: *EventTarget, event: *Event, function_: ?js.Function, comptime opts: DispatchWithFunctionOptions) !void {
|
pub fn dispatchWithFunction(self: *EventManager, target: *EventTarget, event: *Event, function_: ?js.Function, comptime opts: DispatchWithFunctionOptions) !void {
|
||||||
|
defer if (!event._v8_handoff) event.deinit(false, self.page);
|
||||||
|
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
log.debug(.event, "dispatchWithFunction", .{ .type = event._type_string.str(), .context = opts.context, .has_function = function_ != null });
|
log.debug(.event, "dispatchWithFunction", .{ .type = event._type_string.str(), .context = opts.context, .has_function = function_ != null });
|
||||||
}
|
}
|
||||||
@@ -757,7 +761,6 @@ const ActivationState = struct {
|
|||||||
.bubbles = true,
|
.bubbles = true,
|
||||||
.cancelable = false,
|
.cancelable = false,
|
||||||
}, page);
|
}, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
const target = input.asElement().asEventTarget();
|
const target = input.asElement().asEventTarget();
|
||||||
try page._event_manager.dispatch(target, event);
|
try page._event_manager.dispatch(target, event);
|
||||||
|
|||||||
@@ -183,41 +183,41 @@ pub fn standaloneEventTarget(self: *Factory, child: anytype) !*EventTarget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this is a root object
|
// this is a root object
|
||||||
pub fn event(self: *Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
|
pub fn event(_: *const Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
|
||||||
const chain = try PrototypeChain(
|
const chain = try PrototypeChain(
|
||||||
&.{ Event, @TypeOf(child) },
|
&.{ Event, @TypeOf(child) },
|
||||||
).allocate(arena);
|
).allocate(arena);
|
||||||
|
|
||||||
// Special case: Event has a _type_string field, so we need manual setup
|
// Special case: Event has a _type_string field, so we need manual setup
|
||||||
const event_ptr = chain.get(0);
|
const event_ptr = chain.get(0);
|
||||||
event_ptr.* = try self.eventInit(arena, typ, chain.get(1));
|
event_ptr.* = try eventInit(arena, typ, chain.get(1));
|
||||||
chain.setLeaf(1, child);
|
chain.setLeaf(1, child);
|
||||||
|
|
||||||
return chain.get(1);
|
return chain.get(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uiEvent(self: *Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
|
pub fn uiEvent(_: *const Factory, arena: Allocator, typ: String, child: anytype) !*@TypeOf(child) {
|
||||||
const chain = try PrototypeChain(
|
const chain = try PrototypeChain(
|
||||||
&.{ Event, UIEvent, @TypeOf(child) },
|
&.{ Event, UIEvent, @TypeOf(child) },
|
||||||
).allocate(arena);
|
).allocate(arena);
|
||||||
|
|
||||||
// Special case: Event has a _type_string field, so we need manual setup
|
// Special case: Event has a _type_string field, so we need manual setup
|
||||||
const event_ptr = chain.get(0);
|
const event_ptr = chain.get(0);
|
||||||
event_ptr.* = try self.eventInit(arena, typ, chain.get(1));
|
event_ptr.* = try eventInit(arena, typ, chain.get(1));
|
||||||
chain.setMiddle(1, UIEvent.Type);
|
chain.setMiddle(1, UIEvent.Type);
|
||||||
chain.setLeaf(2, child);
|
chain.setLeaf(2, child);
|
||||||
|
|
||||||
return chain.get(2);
|
return chain.get(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouseEvent(self: *Factory, arena: Allocator, typ: String, mouse: MouseEvent, child: anytype) !*@TypeOf(child) {
|
pub fn mouseEvent(_: *const Factory, arena: Allocator, typ: String, mouse: MouseEvent, child: anytype) !*@TypeOf(child) {
|
||||||
const chain = try PrototypeChain(
|
const chain = try PrototypeChain(
|
||||||
&.{ Event, UIEvent, MouseEvent, @TypeOf(child) },
|
&.{ Event, UIEvent, MouseEvent, @TypeOf(child) },
|
||||||
).allocate(arena);
|
).allocate(arena);
|
||||||
|
|
||||||
// Special case: Event has a _type_string field, so we need manual setup
|
// Special case: Event has a _type_string field, so we need manual setup
|
||||||
const event_ptr = chain.get(0);
|
const event_ptr = chain.get(0);
|
||||||
event_ptr.* = try self.eventInit(arena, typ, chain.get(1));
|
event_ptr.* = try eventInit(arena, typ, chain.get(1));
|
||||||
chain.setMiddle(1, UIEvent.Type);
|
chain.setMiddle(1, UIEvent.Type);
|
||||||
|
|
||||||
// Set MouseEvent with all its fields
|
// Set MouseEvent with all its fields
|
||||||
@@ -231,14 +231,13 @@ pub fn mouseEvent(self: *Factory, arena: Allocator, typ: String, mouse: MouseEve
|
|||||||
return chain.get(3);
|
return chain.get(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eventInit(self: *const Factory, arena: Allocator, typ: String, value: anytype) !Event {
|
fn eventInit(arena: Allocator, typ: String, value: anytype) !Event {
|
||||||
// Round to 2ms for privacy (browsers do this)
|
// Round to 2ms for privacy (browsers do this)
|
||||||
const raw_timestamp = @import("../datetime.zig").milliTimestamp(.monotonic);
|
const raw_timestamp = @import("../datetime.zig").milliTimestamp(.monotonic);
|
||||||
const time_stamp = (raw_timestamp / 2) * 2;
|
const time_stamp = (raw_timestamp / 2) * 2;
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._page = self._page,
|
|
||||||
._type = unionInit(Event.Type, value),
|
._type = unionInit(Event.Type, value),
|
||||||
._type_string = typ,
|
._type_string = typ,
|
||||||
._time_stamp = time_stamp,
|
._time_stamp = time_stamp,
|
||||||
|
|||||||
@@ -643,7 +643,6 @@ pub fn documentIsLoaded(self: *Page) void {
|
|||||||
|
|
||||||
pub fn _documentIsLoaded(self: *Page) !void {
|
pub fn _documentIsLoaded(self: *Page) !void {
|
||||||
const event = try Event.initTrusted(.wrap("DOMContentLoaded"), .{ .bubbles = true }, self);
|
const event = try Event.initTrusted(.wrap("DOMContentLoaded"), .{ .bubbles = true }, self);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try self._event_manager.dispatch(
|
try self._event_manager.dispatch(
|
||||||
self.document.asEventTarget(),
|
self.document.asEventTarget(),
|
||||||
event,
|
event,
|
||||||
@@ -664,7 +663,6 @@ pub fn iframeCompletedLoading(self: *Page, iframe: *Element.Html.IFrame) void {
|
|||||||
log.err(.page, "iframe event init", .{ .err = err });
|
log.err(.page, "iframe event init", .{ .err = err });
|
||||||
break :blk;
|
break :blk;
|
||||||
};
|
};
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
self._event_manager.dispatch(iframe.asNode().asEventTarget(), event) catch |err| {
|
self._event_manager.dispatch(iframe.asNode().asEventTarget(), event) catch |err| {
|
||||||
log.warn(.js, "iframe onload", .{ .err = err, .url = iframe._src });
|
log.warn(.js, "iframe onload", .{ .err = err, .url = iframe._src });
|
||||||
};
|
};
|
||||||
@@ -727,7 +725,6 @@ fn _documentIsComplete(self: *Page) !void {
|
|||||||
// Dispatch `_to_load` events before window.load.
|
// Dispatch `_to_load` events before window.load.
|
||||||
for (self._to_load.items) |element| {
|
for (self._to_load.items) |element| {
|
||||||
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
|
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try self._event_manager.dispatch(element.asEventTarget(), event);
|
try self._event_manager.dispatch(element.asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,7 +733,6 @@ fn _documentIsComplete(self: *Page) !void {
|
|||||||
|
|
||||||
// Dispatch window.load event.
|
// Dispatch window.load event.
|
||||||
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
|
const event = try Event.initTrusted(comptime .wrap("load"), .{}, self);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
// This event is weird, it's dispatched directly on the window, but
|
// This event is weird, it's dispatched directly on the window, but
|
||||||
// with the document as the target.
|
// with the document as the target.
|
||||||
event._target = self.document.asEventTarget();
|
event._target = self.document.asEventTarget();
|
||||||
@@ -748,7 +744,6 @@ fn _documentIsComplete(self: *Page) !void {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const pageshow_event = (try PageTransitionEvent.initTrusted(comptime .wrap("pageshow"), .{}, self)).asEvent();
|
const pageshow_event = (try PageTransitionEvent.initTrusted(comptime .wrap("pageshow"), .{}, self)).asEvent();
|
||||||
defer if (!pageshow_event._v8_handoff) pageshow_event.deinit(false);
|
|
||||||
try self._event_manager.dispatchWithFunction(
|
try self._event_manager.dispatchWithFunction(
|
||||||
self.window.asEventTarget(),
|
self.window.asEventTarget(),
|
||||||
pageshow_event,
|
pageshow_event,
|
||||||
@@ -1565,8 +1560,6 @@ pub fn deliverSlotchangeEvents(self: *Page) void {
|
|||||||
log.err(.page, "deliverSlotchange.init", .{ .err = err, .type = self._type });
|
log.err(.page, "deliverSlotchange.init", .{ .err = err, .type = self._type });
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
const target = slot.asNode().asEventTarget();
|
const target = slot.asNode().asEventTarget();
|
||||||
_ = target.dispatchEvent(event, self) catch |err| {
|
_ = target.dispatchEvent(event, self) catch |err| {
|
||||||
log.err(.page, "deliverSlotchange.dispatch", .{ .err = err, .type = self._type });
|
log.err(.page, "deliverSlotchange.dispatch", .{ .err = err, .type = self._type });
|
||||||
@@ -3182,8 +3175,6 @@ pub fn triggerMouseClick(self: *Page, x: f64, y: f64) !void {
|
|||||||
.clientX = x,
|
.clientX = x,
|
||||||
.clientY = y,
|
.clientY = y,
|
||||||
}, self)).asEvent();
|
}, self)).asEvent();
|
||||||
|
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try self._event_manager.dispatch(target.asEventTarget(), event);
|
try self._event_manager.dispatch(target.asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3241,8 +3232,6 @@ pub fn handleClick(self: *Page, target: *Node) !void {
|
|||||||
|
|
||||||
pub fn triggerKeyboard(self: *Page, keyboard_event: *KeyboardEvent) !void {
|
pub fn triggerKeyboard(self: *Page, keyboard_event: *KeyboardEvent) !void {
|
||||||
const event = keyboard_event.asEvent();
|
const event = keyboard_event.asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
const element = self.window._document._active_element orelse return;
|
const element = self.window._document._active_element orelse return;
|
||||||
if (comptime IS_DEBUG) {
|
if (comptime IS_DEBUG) {
|
||||||
log.debug(.page, "page keydown", .{
|
log.debug(.page, "page keydown", .{
|
||||||
@@ -3312,10 +3301,8 @@ pub fn submitForm(self: *Page, submitter_: ?*Element, form_: ?*Element.Html.Form
|
|||||||
const form_element = form.asElement();
|
const form_element = form.asElement();
|
||||||
|
|
||||||
if (submit_opts.fire_event) {
|
if (submit_opts.fire_event) {
|
||||||
const submit_event = try Event.initTrusted(comptime .wrap("submit"), .{ .bubbles = true, .cancelable = true }, self);
|
|
||||||
defer if (!submit_event._v8_handoff) submit_event.deinit(false);
|
|
||||||
|
|
||||||
const onsubmit_handler = try form.asHtmlElement().getOnSubmit(self);
|
const onsubmit_handler = try form.asHtmlElement().getOnSubmit(self);
|
||||||
|
const submit_event = try Event.initTrusted(comptime .wrap("submit"), .{ .bubbles = true, .cancelable = true }, self);
|
||||||
|
|
||||||
var ls: JS.Local.Scope = undefined;
|
var ls: JS.Local.Scope = undefined;
|
||||||
self.js.localScope(&ls);
|
self.js.localScope(&ls);
|
||||||
|
|||||||
@@ -893,7 +893,7 @@ pub const Script = struct {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
defer if (!event._v8_handoff) event.deinit(false, self.manager.page);
|
||||||
|
|
||||||
var caught: js.TryCatch.Caught = undefined;
|
var caught: js.TryCatch.Caught = undefined;
|
||||||
cb.tryCall(void, .{event}, &caught) catch {
|
cb.tryCall(void, .{event}, &caught) catch {
|
||||||
|
|||||||
@@ -1011,7 +1011,7 @@ pub fn queueMicrotaskFunc(self: *Context, cb: js.Function) void {
|
|||||||
self.isolate.enqueueMicrotaskFunc(cb);
|
self.isolate.enqueueMicrotaskFunc(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn createFinalizerCallback(self: *Context, global: v8.Global, ptr: *anyopaque, finalizerFn: *const fn (ptr: *anyopaque) void) !*FinalizerCallback {
|
pub fn createFinalizerCallback(self: *Context, global: v8.Global, ptr: *anyopaque, finalizerFn: *const fn (ptr: *anyopaque, page: *Page) void) !*FinalizerCallback {
|
||||||
const fc = try self.finalizer_callback_pool.create();
|
const fc = try self.finalizer_callback_pool.create();
|
||||||
fc.* = .{
|
fc.* = .{
|
||||||
.ctx = self,
|
.ctx = self,
|
||||||
@@ -1031,10 +1031,10 @@ pub const FinalizerCallback = struct {
|
|||||||
ctx: *Context,
|
ctx: *Context,
|
||||||
ptr: *anyopaque,
|
ptr: *anyopaque,
|
||||||
global: v8.Global,
|
global: v8.Global,
|
||||||
finalizerFn: *const fn (ptr: *anyopaque) void,
|
finalizerFn: *const fn (ptr: *anyopaque, page: *Page) void,
|
||||||
|
|
||||||
pub fn deinit(self: *FinalizerCallback) void {
|
pub fn deinit(self: *FinalizerCallback) void {
|
||||||
self.finalizerFn(self.ptr);
|
self.finalizerFn(self.ptr, self.ctx.page);
|
||||||
self.ctx.finalizer_callback_pool.destroy(self);
|
self.ctx.finalizer_callback_pool.destroy(self);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
// 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 Page = @import("../Page.zig");
|
||||||
const log = @import("../../log.zig");
|
const log = @import("../../log.zig");
|
||||||
const string = @import("../../string.zig");
|
const string = @import("../../string.zig");
|
||||||
|
|
||||||
@@ -1061,7 +1062,7 @@ const Resolved = struct {
|
|||||||
class_id: u16,
|
class_id: u16,
|
||||||
prototype_chain: []const @import("TaggedOpaque.zig").PrototypeChainEntry,
|
prototype_chain: []const @import("TaggedOpaque.zig").PrototypeChainEntry,
|
||||||
finalizer_from_v8: ?*const fn (handle: ?*const v8.WeakCallbackInfo) callconv(.c) void = null,
|
finalizer_from_v8: ?*const fn (handle: ?*const v8.WeakCallbackInfo) callconv(.c) void = null,
|
||||||
finalizer_from_zig: ?*const fn (ptr: *anyopaque) void = null,
|
finalizer_from_zig: ?*const fn (ptr: *anyopaque, page: *Page) void = null,
|
||||||
};
|
};
|
||||||
pub fn resolveValue(value: anytype) Resolved {
|
pub fn resolveValue(value: anytype) Resolved {
|
||||||
const T = bridge.Struct(@TypeOf(value));
|
const T = bridge.Struct(@TypeOf(value));
|
||||||
|
|||||||
@@ -104,11 +104,11 @@ pub fn Builder(comptime T: type) type {
|
|||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finalizer(comptime func: *const fn (self: *T, shutdown: bool) void) Finalizer {
|
pub fn finalizer(comptime func: *const fn (self: *T, shutdown: bool, page: *Page) void) Finalizer {
|
||||||
return .{
|
return .{
|
||||||
.from_zig = struct {
|
.from_zig = struct {
|
||||||
fn wrap(ptr: *anyopaque) void {
|
fn wrap(ptr: *anyopaque, page: *Page) void {
|
||||||
func(@ptrCast(@alignCast(ptr)), true);
|
func(@ptrCast(@alignCast(ptr)), true, page);
|
||||||
}
|
}
|
||||||
}.wrap,
|
}.wrap,
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ pub fn Builder(comptime T: type) type {
|
|||||||
const ctx = fc.ctx;
|
const ctx = fc.ctx;
|
||||||
const value_ptr = fc.ptr;
|
const value_ptr = fc.ptr;
|
||||||
if (ctx.finalizer_callbacks.contains(@intFromPtr(value_ptr))) {
|
if (ctx.finalizer_callbacks.contains(@intFromPtr(value_ptr))) {
|
||||||
func(@ptrCast(@alignCast(value_ptr)), false);
|
func(@ptrCast(@alignCast(value_ptr)), false, ctx.page);
|
||||||
ctx.release(value_ptr);
|
ctx.release(value_ptr);
|
||||||
} else {
|
} else {
|
||||||
// A bit weird, but v8 _requires_ that we release it
|
// A bit weird, but v8 _requires_ that we release it
|
||||||
@@ -398,7 +398,7 @@ pub const Property = struct {
|
|||||||
const Finalizer = struct {
|
const Finalizer = struct {
|
||||||
// The finalizer wrapper when called fro Zig. This is only called on
|
// The finalizer wrapper when called fro Zig. This is only called on
|
||||||
// Context.deinit
|
// Context.deinit
|
||||||
from_zig: *const fn (ctx: *anyopaque) void,
|
from_zig: *const fn (ctx: *anyopaque, page: *Page) void,
|
||||||
|
|
||||||
// The finalizer wrapper when called from V8. This may never be called
|
// The finalizer wrapper when called from V8. This may never be called
|
||||||
// (hence why we fallback to calling in Context.denit). If it is called,
|
// (hence why we fallback to calling in Context.denit). If it is called,
|
||||||
|
|||||||
@@ -77,8 +77,6 @@ pub fn abort(self: *AbortSignal, reason_: ?Reason, local: *const js.Local, page:
|
|||||||
|
|
||||||
// Dispatch abort event
|
// Dispatch abort event
|
||||||
const event = try Event.initTrusted(comptime .wrap("abort"), .{}, page);
|
const event = try Event.initTrusted(comptime .wrap("abort"), .{}, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
try page._event_manager.dispatchWithFunction(
|
try page._event_manager.dispatchWithFunction(
|
||||||
self.asEventTarget(),
|
self.asEventTarget(),
|
||||||
event,
|
event,
|
||||||
|
|||||||
@@ -868,12 +868,10 @@ pub fn focus(self: *Element, page: *Page) !void {
|
|||||||
|
|
||||||
// Dispatch blur on old element (no bubble, composed)
|
// Dispatch blur on old element (no bubble, composed)
|
||||||
const blur_event = try FocusEvent.initTrusted(comptime .wrap("blur"), .{ .composed = true, .relatedTarget = new_target }, page);
|
const blur_event = try FocusEvent.initTrusted(comptime .wrap("blur"), .{ .composed = true, .relatedTarget = new_target }, page);
|
||||||
defer if (!blur_event.asEvent()._v8_handoff) blur_event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(old_target, blur_event.asEvent());
|
try page._event_manager.dispatch(old_target, blur_event.asEvent());
|
||||||
|
|
||||||
// Dispatch focusout on old element (bubbles, composed)
|
// Dispatch focusout on old element (bubbles, composed)
|
||||||
const focusout_event = try FocusEvent.initTrusted(comptime .wrap("focusout"), .{ .bubbles = true, .composed = true, .relatedTarget = new_target }, page);
|
const focusout_event = try FocusEvent.initTrusted(comptime .wrap("focusout"), .{ .bubbles = true, .composed = true, .relatedTarget = new_target }, page);
|
||||||
defer if (!focusout_event.asEvent()._v8_handoff) focusout_event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(old_target, focusout_event.asEvent());
|
try page._event_manager.dispatch(old_target, focusout_event.asEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,12 +879,10 @@ pub fn focus(self: *Element, page: *Page) !void {
|
|||||||
|
|
||||||
// Dispatch focus on new element (no bubble, composed)
|
// Dispatch focus on new element (no bubble, composed)
|
||||||
const focus_event = try FocusEvent.initTrusted(comptime .wrap("focus"), .{ .composed = true, .relatedTarget = old_related }, page);
|
const focus_event = try FocusEvent.initTrusted(comptime .wrap("focus"), .{ .composed = true, .relatedTarget = old_related }, page);
|
||||||
defer if (!focus_event.asEvent()._v8_handoff) focus_event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(new_target, focus_event.asEvent());
|
try page._event_manager.dispatch(new_target, focus_event.asEvent());
|
||||||
|
|
||||||
// Dispatch focusin on new element (bubbles, composed)
|
// Dispatch focusin on new element (bubbles, composed)
|
||||||
const focusin_event = try FocusEvent.initTrusted(comptime .wrap("focusin"), .{ .bubbles = true, .composed = true, .relatedTarget = old_related }, page);
|
const focusin_event = try FocusEvent.initTrusted(comptime .wrap("focusin"), .{ .bubbles = true, .composed = true, .relatedTarget = old_related }, page);
|
||||||
defer if (!focusin_event.asEvent()._v8_handoff) focusin_event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(new_target, focusin_event.asEvent());
|
try page._event_manager.dispatch(new_target, focusin_event.asEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,12 +896,10 @@ pub fn blur(self: *Element, page: *Page) !void {
|
|||||||
|
|
||||||
// Dispatch blur (no bubble, composed)
|
// Dispatch blur (no bubble, composed)
|
||||||
const blur_event = try FocusEvent.initTrusted(comptime .wrap("blur"), .{ .composed = true }, page);
|
const blur_event = try FocusEvent.initTrusted(comptime .wrap("blur"), .{ .composed = true }, page);
|
||||||
defer if (!blur_event.asEvent()._v8_handoff) blur_event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(old_target, blur_event.asEvent());
|
try page._event_manager.dispatch(old_target, blur_event.asEvent());
|
||||||
|
|
||||||
// Dispatch focusout (bubbles, composed)
|
// Dispatch focusout (bubbles, composed)
|
||||||
const focusout_event = try FocusEvent.initTrusted(comptime .wrap("focusout"), .{ .bubbles = true, .composed = true }, page);
|
const focusout_event = try FocusEvent.initTrusted(comptime .wrap("focusout"), .{ .bubbles = true, .composed = true }, page);
|
||||||
defer if (!focusout_event.asEvent()._v8_handoff) focusout_event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(old_target, focusout_event.asEvent());
|
try page._event_manager.dispatch(old_target, focusout_event.asEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ pub const Event = @This();
|
|||||||
|
|
||||||
pub const _prototype_root = true;
|
pub const _prototype_root = true;
|
||||||
_type: Type,
|
_type: Type,
|
||||||
_page: *Page,
|
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_bubbles: bool = false,
|
_bubbles: bool = false,
|
||||||
_cancelable: bool = false,
|
_cancelable: bool = false,
|
||||||
@@ -84,16 +83,16 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*Event {
|
|||||||
const arena = try page.getArena(.{ .debug = "Event" });
|
const arena = try page.getArena(.{ .debug = "Event" });
|
||||||
errdefer page.releaseArena(arena);
|
errdefer page.releaseArena(arena);
|
||||||
const str = try String.init(arena, typ, .{});
|
const str = try String.init(arena, typ, .{});
|
||||||
return initWithTrusted(arena, str, opts_, false, page);
|
return initWithTrusted(arena, str, opts_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*Event {
|
pub fn initTrusted(typ: String, opts_: ?Options, page: *Page) !*Event {
|
||||||
const arena = try page.getArena(.{ .debug = "Event.trusted" });
|
const arena = try page.getArena(.{ .debug = "Event.trusted" });
|
||||||
errdefer page.releaseArena(arena);
|
errdefer page.releaseArena(arena);
|
||||||
return initWithTrusted(arena, typ, opts_, true, page);
|
return initWithTrusted(arena, typ, opts_, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool, page: *Page) !*Event {
|
fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool) !*Event {
|
||||||
const opts = opts_ orelse Options{};
|
const opts = opts_ orelse Options{};
|
||||||
|
|
||||||
// Round to 2ms for privacy (browsers do this)
|
// Round to 2ms for privacy (browsers do this)
|
||||||
@@ -102,7 +101,6 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool
|
|||||||
|
|
||||||
const event = try arena.create(Event);
|
const event = try arena.create(Event);
|
||||||
event.* = .{
|
event.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._type = .generic,
|
._type = .generic,
|
||||||
._bubbles = opts.bubbles,
|
._bubbles = opts.bubbles,
|
||||||
@@ -133,9 +131,9 @@ pub fn initEvent(
|
|||||||
self._prevent_default = false;
|
self._prevent_default = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Event, shutdown: bool) void {
|
pub fn deinit(self: *Event, shutdown: bool, page: *Page) void {
|
||||||
_ = shutdown;
|
_ = shutdown;
|
||||||
self._page.releaseArena(self._arena);
|
page.releaseArena(self._arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as(self: *Event, comptime T: type) *T {
|
pub fn as(self: *Event, comptime T: type) *T {
|
||||||
|
|||||||
@@ -80,8 +80,6 @@ fn goInner(delta: i32, page: *Page) !void {
|
|||||||
if (entry._url) |url| {
|
if (entry._url) |url| {
|
||||||
if (try page.isSameOrigin(url)) {
|
if (try page.isSameOrigin(url)) {
|
||||||
const event = (try PopStateEvent.initTrusted(comptime .wrap("popstate"), .{ .state = entry._state.value }, page)).asEvent();
|
const event = (try PopStateEvent.initTrusted(comptime .wrap("popstate"), .{ .state = entry._state.value }, page)).asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
try page._event_manager.dispatchWithFunction(
|
try page._event_manager.dispatchWithFunction(
|
||||||
page.window.asEventTarget(),
|
page.window.asEventTarget(),
|
||||||
event,
|
event,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ pub fn registerTypes() []const type {
|
|||||||
|
|
||||||
const IntersectionObserver = @This();
|
const IntersectionObserver = @This();
|
||||||
|
|
||||||
_page: *Page,
|
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_callback: js.Function.Temp,
|
_callback: js.Function.Temp,
|
||||||
_observing: std.ArrayList(*Element) = .{},
|
_observing: std.ArrayList(*Element) = .{},
|
||||||
@@ -83,7 +82,6 @@ pub fn init(callback: js.Function.Temp, options: ?ObserverInit, page: *Page) !*I
|
|||||||
|
|
||||||
const self = try arena.create(IntersectionObserver);
|
const self = try arena.create(IntersectionObserver);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._callback = callback,
|
._callback = callback,
|
||||||
._root = opts.root,
|
._root = opts.root,
|
||||||
@@ -93,8 +91,7 @@ pub fn init(callback: js.Function.Temp, options: ?ObserverInit, page: *Page) !*I
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *IntersectionObserver, shutdown: bool) void {
|
pub fn deinit(self: *IntersectionObserver, shutdown: bool, page: *Page) void {
|
||||||
const page = self._page;
|
|
||||||
page.js.release(self._callback);
|
page.js.release(self._callback);
|
||||||
if ((comptime IS_DEBUG) and !shutdown) {
|
if ((comptime IS_DEBUG) and !shutdown) {
|
||||||
std.debug.assert(self._observing.items.len == 0);
|
std.debug.assert(self._observing.items.len == 0);
|
||||||
@@ -140,7 +137,7 @@ pub fn unobserve(self: *IntersectionObserver, target: *Element, page: *Page) voi
|
|||||||
while (j < self._pending_entries.items.len) {
|
while (j < self._pending_entries.items.len) {
|
||||||
if (self._pending_entries.items[j]._target == target) {
|
if (self._pending_entries.items[j]._target == target) {
|
||||||
const entry = self._pending_entries.swapRemove(j);
|
const entry = self._pending_entries.swapRemove(j);
|
||||||
entry.deinit(false);
|
entry.deinit(false, page);
|
||||||
} else {
|
} else {
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
@@ -160,7 +157,7 @@ pub fn disconnect(self: *IntersectionObserver, page: *Page) void {
|
|||||||
self._previous_states.clearRetainingCapacity();
|
self._previous_states.clearRetainingCapacity();
|
||||||
|
|
||||||
for (self._pending_entries.items) |entry| {
|
for (self._pending_entries.items) |entry| {
|
||||||
entry.deinit(false);
|
entry.deinit(false, page);
|
||||||
}
|
}
|
||||||
self._pending_entries.clearRetainingCapacity();
|
self._pending_entries.clearRetainingCapacity();
|
||||||
page.js.safeWeakRef(self);
|
page.js.safeWeakRef(self);
|
||||||
@@ -245,7 +242,6 @@ fn checkIntersection(self: *IntersectionObserver, target: *Element, page: *Page)
|
|||||||
|
|
||||||
const entry = try arena.create(IntersectionObserverEntry);
|
const entry = try arena.create(IntersectionObserverEntry);
|
||||||
entry.* = .{
|
entry.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._target = target,
|
._target = target,
|
||||||
._time = page.window._performance.now(),
|
._time = page.window._performance.now(),
|
||||||
@@ -297,7 +293,6 @@ pub fn deliverEntries(self: *IntersectionObserver, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const IntersectionObserverEntry = struct {
|
pub const IntersectionObserverEntry = struct {
|
||||||
_page: *Page,
|
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_time: f64,
|
_time: f64,
|
||||||
_target: *Element,
|
_target: *Element,
|
||||||
@@ -307,8 +302,8 @@ pub const IntersectionObserverEntry = struct {
|
|||||||
_intersection_ratio: f64,
|
_intersection_ratio: f64,
|
||||||
_is_intersecting: bool,
|
_is_intersecting: bool,
|
||||||
|
|
||||||
pub fn deinit(self: *const IntersectionObserverEntry, _: bool) void {
|
pub fn deinit(self: *const IntersectionObserverEntry, _: bool, page: *Page) void {
|
||||||
self._page.releaseArena(self._arena);
|
page.releaseArena(self._arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTarget(self: *const IntersectionObserverEntry) *Element {
|
pub fn getTarget(self: *const IntersectionObserverEntry) *Element {
|
||||||
|
|||||||
@@ -130,7 +130,6 @@ const PostMessageCallback = struct {
|
|||||||
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
log.err(.dom, "MessagePort.postMessage", .{ .err = err });
|
||||||
return null;
|
return null;
|
||||||
}).asEvent();
|
}).asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
var ls: js.Local.Scope = undefined;
|
var ls: js.Local.Scope = undefined;
|
||||||
page.js.localScope(&ls);
|
page.js.localScope(&ls);
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ pub fn registerTypes() []const type {
|
|||||||
|
|
||||||
const MutationObserver = @This();
|
const MutationObserver = @This();
|
||||||
|
|
||||||
_page: *Page,
|
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_callback: js.Function.Temp,
|
_callback: js.Function.Temp,
|
||||||
_observing: std.ArrayList(Observing) = .{},
|
_observing: std.ArrayList(Observing) = .{},
|
||||||
@@ -79,15 +78,13 @@ pub fn init(callback: js.Function.Temp, page: *Page) !*MutationObserver {
|
|||||||
|
|
||||||
const self = try arena.create(MutationObserver);
|
const self = try arena.create(MutationObserver);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._callback = callback,
|
._callback = callback,
|
||||||
};
|
};
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *MutationObserver, shutdown: bool) void {
|
pub fn deinit(self: *MutationObserver, shutdown: bool, page: *Page) void {
|
||||||
const page = self._page;
|
|
||||||
page.js.release(self._callback);
|
page.js.release(self._callback);
|
||||||
if ((comptime IS_DEBUG) and !shutdown) {
|
if ((comptime IS_DEBUG) and !shutdown) {
|
||||||
std.debug.assert(self._observing.items.len == 0);
|
std.debug.assert(self._observing.items.len == 0);
|
||||||
@@ -174,7 +171,7 @@ pub fn disconnect(self: *MutationObserver, page: *Page) void {
|
|||||||
page.unregisterMutationObserver(self);
|
page.unregisterMutationObserver(self);
|
||||||
self._observing.clearRetainingCapacity();
|
self._observing.clearRetainingCapacity();
|
||||||
for (self._pending_records.items) |record| {
|
for (self._pending_records.items) |record| {
|
||||||
record.deinit(false);
|
record.deinit(false, page);
|
||||||
}
|
}
|
||||||
self._pending_records.clearRetainingCapacity();
|
self._pending_records.clearRetainingCapacity();
|
||||||
page.js.safeWeakRef(self);
|
page.js.safeWeakRef(self);
|
||||||
@@ -218,10 +215,9 @@ pub fn notifyAttributeChange(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const arena = try self._page.getArena(.{ .debug = "MutationRecord" });
|
const arena = try page.getArena(.{ .debug = "MutationRecord" });
|
||||||
const record = try arena.create(MutationRecord);
|
const record = try arena.create(MutationRecord);
|
||||||
record.* = .{
|
record.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._type = .attributes,
|
._type = .attributes,
|
||||||
._target = target_node,
|
._target = target_node,
|
||||||
@@ -263,10 +259,9 @@ pub fn notifyCharacterDataChange(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const arena = try self._page.getArena(.{ .debug = "MutationRecord" });
|
const arena = try page.getArena(.{ .debug = "MutationRecord" });
|
||||||
const record = try arena.create(MutationRecord);
|
const record = try arena.create(MutationRecord);
|
||||||
record.* = .{
|
record.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._type = .characterData,
|
._type = .characterData,
|
||||||
._target = target,
|
._target = target,
|
||||||
@@ -311,10 +306,9 @@ pub fn notifyChildListChange(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const arena = try self._page.getArena(.{ .debug = "MutationRecord" });
|
const arena = try page.getArena(.{ .debug = "MutationRecord" });
|
||||||
const record = try arena.create(MutationRecord);
|
const record = try arena.create(MutationRecord);
|
||||||
record.* = .{
|
record.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._type = .childList,
|
._type = .childList,
|
||||||
._target = target,
|
._target = target,
|
||||||
@@ -354,7 +348,6 @@ pub fn deliverRecords(self: *MutationObserver, page: *Page) !void {
|
|||||||
|
|
||||||
pub const MutationRecord = struct {
|
pub const MutationRecord = struct {
|
||||||
_type: Type,
|
_type: Type,
|
||||||
_page: *Page,
|
|
||||||
_target: *Node,
|
_target: *Node,
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_attribute_name: ?[]const u8,
|
_attribute_name: ?[]const u8,
|
||||||
@@ -370,8 +363,8 @@ pub const MutationRecord = struct {
|
|||||||
characterData,
|
characterData,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn deinit(self: *const MutationRecord, _: bool) void {
|
pub fn deinit(self: *const MutationRecord, _: bool, page: *Page) void {
|
||||||
self._page.releaseArena(self._arena);
|
page.releaseArena(self._arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getType(self: *const MutationRecord) []const u8 {
|
pub fn getType(self: *const MutationRecord) []const u8 {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ pub const init: Selection = .{};
|
|||||||
|
|
||||||
fn dispatchSelectionChangeEvent(page: *Page) !void {
|
fn dispatchSelectionChangeEvent(page: *Page) !void {
|
||||||
const event = try Event.init("selectionchange", .{}, page);
|
const event = try Event.init("selectionchange", .{}, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(page.document.asEventTarget(), event);
|
try page._event_manager.dispatch(page.document.asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -308,12 +308,10 @@ pub fn reportError(self: *Window, err: js.Value, page: *Page) !void {
|
|||||||
.cancelable = true,
|
.cancelable = true,
|
||||||
}, page);
|
}, page);
|
||||||
|
|
||||||
const event = error_event.asEvent();
|
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
// Invoke window.onerror callback if set (per WHATWG spec, this is called
|
// Invoke window.onerror callback if set (per WHATWG spec, this is called
|
||||||
// with 5 arguments: message, source, lineno, colno, error)
|
// with 5 arguments: message, source, lineno, colno, error)
|
||||||
// If it returns true, the event is cancelled.
|
// If it returns true, the event is cancelled.
|
||||||
|
var prevent_default = false;
|
||||||
if (self._on_error) |on_error| {
|
if (self._on_error) |on_error| {
|
||||||
var ls: js.Local.Scope = undefined;
|
var ls: js.Local.Scope = undefined;
|
||||||
page.js.localScope(&ls);
|
page.js.localScope(&ls);
|
||||||
@@ -330,12 +328,12 @@ pub fn reportError(self: *Window, err: js.Value, page: *Page) !void {
|
|||||||
|
|
||||||
// Per spec: returning true from onerror cancels the event
|
// Per spec: returning true from onerror cancels the event
|
||||||
if (result) |r| {
|
if (result) |r| {
|
||||||
if (r.isTrue()) {
|
prevent_default = r.isTrue();
|
||||||
event._prevent_default = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const event = error_event.asEvent();
|
||||||
|
event._prevent_default = prevent_default;
|
||||||
try page._event_manager.dispatch(self.asEventTarget(), event);
|
try page._event_manager.dispatch(self.asEventTarget(), event);
|
||||||
|
|
||||||
if (comptime builtin.is_test == false) {
|
if (comptime builtin.is_test == false) {
|
||||||
@@ -478,7 +476,6 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const event = try Event.initTrusted(comptime .wrap("scroll"), .{ .bubbles = true }, p);
|
const event = try Event.initTrusted(comptime .wrap("scroll"), .{ .bubbles = true }, p);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try p._event_manager.dispatch(p.document.asEventTarget(), event);
|
try p._event_manager.dispatch(p.document.asEventTarget(), event);
|
||||||
|
|
||||||
pos.state = .end;
|
pos.state = .end;
|
||||||
@@ -506,7 +503,6 @@ pub fn scrollTo(self: *Window, opts: ScrollToOpts, y: ?i32, page: *Page) !void {
|
|||||||
.done => return null,
|
.done => return null,
|
||||||
}
|
}
|
||||||
const event = try Event.initTrusted(comptime .wrap("scrollend"), .{ .bubbles = true }, p);
|
const event = try Event.initTrusted(comptime .wrap("scrollend"), .{ .bubbles = true }, p);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try p._event_manager.dispatch(p.document.asEventTarget(), event);
|
try p._event_manager.dispatch(p.document.asEventTarget(), event);
|
||||||
|
|
||||||
pos.state = .done;
|
pos.state = .done;
|
||||||
@@ -527,11 +523,10 @@ pub fn unhandledPromiseRejection(self: *Window, rejection: js.PromiseRejection,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var event = (try @import("event/PromiseRejectionEvent.zig").init("unhandledrejection", .{
|
const event = (try @import("event/PromiseRejectionEvent.zig").init("unhandledrejection", .{
|
||||||
.reason = if (rejection.reason()) |r| try r.temp() else null,
|
.reason = if (rejection.reason()) |r| try r.temp() else null,
|
||||||
.promise = try rejection.promise().temp(),
|
.promise = try rejection.promise().temp(),
|
||||||
}, page)).asEvent();
|
}, page)).asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
try page._event_manager.dispatchWithFunction(
|
try page._event_manager.dispatchWithFunction(
|
||||||
self.asEventTarget(),
|
self.asEventTarget(),
|
||||||
@@ -705,7 +700,6 @@ const PostMessageCallback = struct {
|
|||||||
.bubbles = false,
|
.bubbles = false,
|
||||||
.cancelable = false,
|
.cancelable = false,
|
||||||
}, page)).asEvent();
|
}, page)).asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(window.asEventTarget(), event);
|
try page._event_manager.dispatch(window.asEventTarget(), event);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ pub fn init(page: *Page) !*Animation {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Animation, _: bool) void {
|
pub fn deinit(self: *Animation, _: bool, page: *Page) void {
|
||||||
self._page.releaseArena(self._arena);
|
page.releaseArena(self._arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn play(self: *Animation, page: *Page) !void {
|
pub fn play(self: *Animation, page: *Page) !void {
|
||||||
|
|||||||
@@ -338,7 +338,6 @@ pub fn click(self: *HtmlElement, page: *Page) !void {
|
|||||||
.clientX = 0,
|
.clientX = 0,
|
||||||
.clientY = 0,
|
.clientY = 0,
|
||||||
}, page)).asEvent();
|
}, page)).asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(self.asEventTarget(), event);
|
try page._event_manager.dispatch(self.asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ pub fn setOnSelectionChange(self: *Input, listener: ?js.Function) !void {
|
|||||||
|
|
||||||
fn dispatchSelectionChangeEvent(self: *Input, page: *Page) !void {
|
fn dispatchSelectionChangeEvent(self: *Input, page: *Page) !void {
|
||||||
const event = try Event.init("selectionchange", .{ .bubbles = true }, page);
|
const event = try Event.init("selectionchange", .{ .bubbles = true }, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,7 +343,6 @@ pub fn select(self: *Input, page: *Page) !void {
|
|||||||
const len = if (self._value) |v| @as(u32, @intCast(v.len)) else 0;
|
const len = if (self._value) |v| @as(u32, @intCast(v.len)) else 0;
|
||||||
try self.setSelectionRange(0, len, null, page);
|
try self.setSelectionRange(0, len, null, page);
|
||||||
const event = try Event.init("select", .{ .bubbles = true }, page);
|
const event = try Event.init("select", .{ .bubbles = true }, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ pub fn load(self: *Media, page: *Page) !void {
|
|||||||
|
|
||||||
fn dispatchEvent(self: *Media, name: []const u8, page: *Page) !void {
|
fn dispatchEvent(self: *Media, name: []const u8, page: *Page) !void {
|
||||||
const event = try Event.init(name, .{ .bubbles = false, .cancelable = false }, page);
|
const event = try Event.init(name, .{ .bubbles = false, .cancelable = false }, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ pub fn setOnSelectionChange(self: *TextArea, listener: ?js.Function) !void {
|
|||||||
|
|
||||||
fn dispatchSelectionChangeEvent(self: *TextArea, page: *Page) !void {
|
fn dispatchSelectionChangeEvent(self: *TextArea, page: *Page) !void {
|
||||||
const event = try Event.init("selectionchange", .{ .bubbles = true }, page);
|
const event = try Event.init("selectionchange", .{ .bubbles = true }, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,7 +139,6 @@ pub fn select(self: *TextArea, page: *Page) !void {
|
|||||||
const len = if (self._value) |v| @as(u32, @intCast(v.len)) else 0;
|
const len = if (self._value) |v| @as(u32, @intCast(v.len)) else 0;
|
||||||
try self.setSelectionRange(0, len, null, page);
|
try self.setSelectionRange(0, len, null, page);
|
||||||
const event = try Event.init("select", .{ .bubbles = true }, page);
|
const event = try Event.init("select", .{ .bubbles = true }, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
try page._event_manager.dispatch(self.asElement().asEventTarget(), event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ const Allocator = std.mem.Allocator;
|
|||||||
const TextDecoder = @This();
|
const TextDecoder = @This();
|
||||||
|
|
||||||
_fatal: bool,
|
_fatal: bool,
|
||||||
_page: *Page,
|
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_ignore_bom: bool,
|
_ignore_bom: bool,
|
||||||
_stream: std.ArrayList(u8),
|
_stream: std.ArrayList(u8),
|
||||||
@@ -52,7 +51,6 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder {
|
|||||||
const opts = opts_ orelse InitOpts{};
|
const opts = opts_ orelse InitOpts{};
|
||||||
const self = try arena.create(TextDecoder);
|
const self = try arena.create(TextDecoder);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._stream = .empty,
|
._stream = .empty,
|
||||||
._fatal = opts.fatal,
|
._fatal = opts.fatal,
|
||||||
@@ -61,8 +59,8 @@ pub fn init(label_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*TextDecoder {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *TextDecoder, _: bool) void {
|
pub fn deinit(self: *TextDecoder, _: bool, page: *Page) void {
|
||||||
self._page.releaseArena(self._arena);
|
page.releaseArena(self._arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getIgnoreBOM(self: *const TextDecoder) bool {
|
pub fn getIgnoreBOM(self: *const TextDecoder) bool {
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*CompositionEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *CompositionEvent, shutdown: bool) void {
|
pub fn deinit(self: *CompositionEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *CompositionEvent) *Event {
|
pub fn asEvent(self: *CompositionEvent) *Event {
|
||||||
|
|||||||
@@ -72,12 +72,11 @@ pub fn initCustomEvent(
|
|||||||
self._detail = detail_;
|
self._detail = detail_;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *CustomEvent, shutdown: bool) void {
|
pub fn deinit(self: *CustomEvent, shutdown: bool, page: *Page) void {
|
||||||
const proto = self._proto;
|
|
||||||
if (self._detail) |d| {
|
if (self._detail) |d| {
|
||||||
proto._page.js.release(d);
|
page.js.release(d);
|
||||||
}
|
}
|
||||||
proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *CustomEvent) *Event {
|
pub fn asEvent(self: *CustomEvent) *Event {
|
||||||
|
|||||||
@@ -79,12 +79,11 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *ErrorEvent, shutdown: bool) void {
|
pub fn deinit(self: *ErrorEvent, shutdown: bool, page: *Page) void {
|
||||||
const proto = self._proto;
|
|
||||||
if (self._error) |e| {
|
if (self._error) |e| {
|
||||||
proto._page.js.release(e);
|
page.js.release(e);
|
||||||
}
|
}
|
||||||
proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *ErrorEvent) *Event {
|
pub fn asEvent(self: *ErrorEvent) *Event {
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *FocusEvent, shutdown: bool) void {
|
pub fn deinit(self: *FocusEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *FocusEvent) *Event {
|
pub fn asEvent(self: *FocusEvent) *Event {
|
||||||
|
|||||||
@@ -221,8 +221,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *KeyboardEvent, shutdown: bool) void {
|
pub fn deinit(self: *KeyboardEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *KeyboardEvent) *Event {
|
pub fn asEvent(self: *KeyboardEvent) *Event {
|
||||||
|
|||||||
@@ -72,12 +72,11 @@ fn initWithTrusted(arena: Allocator, typ: String, opts_: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *MessageEvent, shutdown: bool) void {
|
pub fn deinit(self: *MessageEvent, shutdown: bool, page: *Page) void {
|
||||||
const proto = self._proto;
|
|
||||||
if (self._data) |d| {
|
if (self._data) |d| {
|
||||||
proto._page.js.release(d);
|
page.js.release(d);
|
||||||
}
|
}
|
||||||
proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *MessageEvent) *Event {
|
pub fn asEvent(self: *MessageEvent) *Event {
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*MouseEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *MouseEvent, shutdown: bool) void {
|
pub fn deinit(self: *MouseEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *MouseEvent) *Event {
|
pub fn asEvent(self: *MouseEvent) *Event {
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ fn initWithTrusted(
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *NavigationCurrentEntryChangeEvent, shutdown: bool) void {
|
pub fn deinit(self: *NavigationCurrentEntryChangeEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *NavigationCurrentEntryChangeEvent) *Event {
|
pub fn asEvent(self: *NavigationCurrentEntryChangeEvent) *Event {
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *PageTransitionEvent, shutdown: bool) void {
|
pub fn deinit(self: *PageTransitionEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *PageTransitionEvent) *Event {
|
pub fn asEvent(self: *PageTransitionEvent) *Event {
|
||||||
|
|||||||
@@ -127,8 +127,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*PointerEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *PointerEvent, shutdown: bool) void {
|
pub fn deinit(self: *PointerEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *PointerEvent) *Event {
|
pub fn asEvent(self: *PointerEvent) *Event {
|
||||||
|
|||||||
@@ -66,8 +66,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *PopStateEvent, shutdown: bool) void {
|
pub fn deinit(self: *PopStateEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *PopStateEvent) *Event {
|
pub fn asEvent(self: *PopStateEvent) *Event {
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ fn initWithTrusted(arena: Allocator, typ: String, _opts: ?Options, trusted: bool
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *ProgressEvent, shutdown: bool) void {
|
pub fn deinit(self: *ProgressEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *ProgressEvent) *Event {
|
pub fn asEvent(self: *ProgressEvent) *Event {
|
||||||
|
|||||||
@@ -56,16 +56,14 @@ pub fn init(typ: []const u8, opts_: ?Options, page: *Page) !*PromiseRejectionEve
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *PromiseRejectionEvent, shutdown: bool) void {
|
pub fn deinit(self: *PromiseRejectionEvent, shutdown: bool, page: *Page) void {
|
||||||
const proto = self._proto;
|
|
||||||
const js_ctx = proto._page.js;
|
|
||||||
if (self._reason) |r| {
|
if (self._reason) |r| {
|
||||||
js_ctx.release(r);
|
page.js.release(r);
|
||||||
}
|
}
|
||||||
if (self._promise) |p| {
|
if (self._promise) |p| {
|
||||||
js_ctx.release(p);
|
page.js.release(p);
|
||||||
}
|
}
|
||||||
proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *PromiseRejectionEvent) *Event {
|
pub fn asEvent(self: *PromiseRejectionEvent) *Event {
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*TextEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *TextEvent, shutdown: bool) void {
|
pub fn deinit(self: *TextEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *TextEvent) *Event {
|
pub fn asEvent(self: *TextEvent) *Event {
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*UIEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *UIEvent, shutdown: bool) void {
|
pub fn deinit(self: *UIEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as(self: *UIEvent, comptime T: type) *T {
|
pub fn as(self: *UIEvent, comptime T: type) *T {
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ pub fn init(typ: []const u8, _opts: ?Options, page: *Page) !*WheelEvent {
|
|||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *WheelEvent, shutdown: bool) void {
|
pub fn deinit(self: *WheelEvent, shutdown: bool, page: *Page) void {
|
||||||
self._proto.deinit(shutdown);
|
self._proto.deinit(shutdown, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn asEvent(self: *WheelEvent) *Event {
|
pub fn asEvent(self: *WheelEvent) *Event {
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ const URL = @import("../URL.zig");
|
|||||||
const js = @import("../../js/js.zig");
|
const js = @import("../../js/js.zig");
|
||||||
const Page = @import("../../Page.zig");
|
const Page = @import("../../Page.zig");
|
||||||
|
|
||||||
const IS_DEBUG = @import("builtin").mode == .Debug;
|
const Event = @import("../Event.zig");
|
||||||
|
|
||||||
const EventTarget = @import("../EventTarget.zig");
|
const EventTarget = @import("../EventTarget.zig");
|
||||||
|
|
||||||
|
const IS_DEBUG = @import("builtin").mode == .Debug;
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Navigation
|
// https://developer.mozilla.org/en-US/docs/Web/API/Navigation
|
||||||
const Navigation = @This();
|
const Navigation = @This();
|
||||||
|
|
||||||
@@ -203,15 +204,17 @@ pub fn pushEntry(
|
|||||||
try self._entries.append(arena, entry);
|
try self._entries.append(arena, entry);
|
||||||
self._index = index;
|
self._index = index;
|
||||||
|
|
||||||
if (previous) |prev| {
|
if (previous == null or should_dispatch == false) {
|
||||||
if (should_dispatch) {
|
return entry;
|
||||||
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
|
||||||
.wrap("currententrychange"),
|
|
||||||
.{ .from = prev, .navigationType = @tagName(.push) },
|
|
||||||
page,
|
|
||||||
);
|
|
||||||
try self.dispatch(.{ .currententrychange = event }, page);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self._on_currententrychange) |cec| {
|
||||||
|
const event = (try NavigationCurrentEntryChangeEvent.initTrusted(
|
||||||
|
.wrap("currententrychange"),
|
||||||
|
.{ .from = previous.?, .navigationType = @tagName(.push) },
|
||||||
|
page,
|
||||||
|
)).asEvent();
|
||||||
|
try self.dispatch(cec, event, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -243,13 +246,17 @@ pub fn replaceEntry(
|
|||||||
|
|
||||||
self._entries.items[self._index] = entry;
|
self._entries.items[self._index] = entry;
|
||||||
|
|
||||||
if (should_dispatch) {
|
if (should_dispatch == false) {
|
||||||
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self._on_currententrychange) |cec| {
|
||||||
|
const event = (try NavigationCurrentEntryChangeEvent.initTrusted(
|
||||||
.wrap("currententrychange"),
|
.wrap("currententrychange"),
|
||||||
.{ .from = previous, .navigationType = @tagName(.replace) },
|
.{ .from = previous, .navigationType = @tagName(.replace) },
|
||||||
page,
|
page,
|
||||||
);
|
)).asEvent();
|
||||||
try self.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(cec, event, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@@ -335,13 +342,15 @@ pub fn navigateInner(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self._on_currententrychange) |cec| {
|
||||||
// If we haven't navigated off, let us fire off an a currententrychange.
|
// If we haven't navigated off, let us fire off an a currententrychange.
|
||||||
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
const event = (try NavigationCurrentEntryChangeEvent.initTrusted(
|
||||||
.wrap("currententrychange"),
|
.wrap("currententrychange"),
|
||||||
.{ .from = previous, .navigationType = @tagName(kind) },
|
.{ .from = previous, .navigationType = @tagName(kind) },
|
||||||
page,
|
page,
|
||||||
);
|
)).asEvent();
|
||||||
try self.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(cec, event, page);
|
||||||
|
}
|
||||||
|
|
||||||
_ = try committed.persist();
|
_ = try committed.persist();
|
||||||
_ = try finished.persist();
|
_ = try finished.persist();
|
||||||
@@ -420,35 +429,17 @@ pub fn updateCurrentEntry(self: *Navigation, options: UpdateCurrentEntryOptions,
|
|||||||
.value = options.state.toJson(arena) catch return error.DataClone,
|
.value = options.state.toJson(arena) catch return error.DataClone,
|
||||||
};
|
};
|
||||||
|
|
||||||
const event = try NavigationCurrentEntryChangeEvent.initTrusted(
|
if (self._on_currententrychange) |cec| {
|
||||||
|
const event = (try NavigationCurrentEntryChangeEvent.initTrusted(
|
||||||
.wrap("currententrychange"),
|
.wrap("currententrychange"),
|
||||||
.{ .from = previous, .navigationType = null },
|
.{ .from = previous, .navigationType = null },
|
||||||
page,
|
page,
|
||||||
);
|
)).asEvent();
|
||||||
try self.dispatch(.{ .currententrychange = event }, page);
|
try self.dispatch(cec, event, page);
|
||||||
}
|
|
||||||
|
|
||||||
const DispatchType = union(enum) {
|
|
||||||
currententrychange: *NavigationCurrentEntryChangeEvent,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn dispatch(self: *Navigation, event_type: DispatchType, page: *Page) !void {
|
|
||||||
const event, const field = blk: {
|
|
||||||
break :blk switch (event_type) {
|
|
||||||
.currententrychange => |cec| .{ cec.asEvent(), "_on_currententrychange" },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
if (comptime IS_DEBUG) {
|
|
||||||
if (page.js.local == null) {
|
|
||||||
log.fatal(.bug, "null context scope", .{ .src = "Navigation.dispatch", .url = page.url });
|
|
||||||
std.debug.assert(page.js.local != null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const func = @field(self, field) orelse return;
|
pub fn dispatch(self: *Navigation, func: js.Function.Global, event: *Event, page: *Page) !void {
|
||||||
|
|
||||||
var ls: js.Local.Scope = undefined;
|
var ls: js.Local.Scope = undefined;
|
||||||
page.js.localScope(&ls);
|
page.js.localScope(&ls);
|
||||||
defer ls.deinit();
|
defer ls.deinit();
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ pub const InitOpts = Request.InitOpts;
|
|||||||
pub fn init(input: Input, options: ?InitOpts, page: *Page) !js.Promise {
|
pub fn init(input: Input, options: ?InitOpts, page: *Page) !js.Promise {
|
||||||
const request = try Request.init(input, options, page);
|
const request = try Request.init(input, options, page);
|
||||||
const response = try Response.init(null, .{ .status = 0 }, page);
|
const response = try Response.init(null, .{ .status = 0 }, page);
|
||||||
errdefer response.deinit(true);
|
errdefer response.deinit(true, page);
|
||||||
|
|
||||||
const resolver = page.js.local.?.createPromiseResolver();
|
const resolver = page.js.local.?.createPromiseResolver();
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ fn httpErrorCallback(ctx: *anyopaque, err: anyerror) void {
|
|||||||
// clear this. (defer since `self is in the response's arena).
|
// clear this. (defer since `self is in the response's arena).
|
||||||
|
|
||||||
defer if (self._owns_response) {
|
defer if (self._owns_response) {
|
||||||
response.deinit(err == error.Abort);
|
response.deinit(err == error.Abort, self._page);
|
||||||
self._owns_response = false;
|
self._owns_response = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ fn httpShutdownCallback(ctx: *anyopaque) void {
|
|||||||
if (self._owns_response) {
|
if (self._owns_response) {
|
||||||
var response = self._response;
|
var response = self._response;
|
||||||
response._transfer = null;
|
response._transfer = null;
|
||||||
response.deinit(true);
|
response.deinit(true, self._page);
|
||||||
// Do not access `self` after this point: the Fetch struct was
|
// Do not access `self` after this point: the Fetch struct was
|
||||||
// allocated from response._arena which has been released.
|
// allocated from response._arena which has been released.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ pub const Type = enum {
|
|||||||
opaqueredirect,
|
opaqueredirect,
|
||||||
};
|
};
|
||||||
|
|
||||||
_page: *Page,
|
|
||||||
_status: u16,
|
_status: u16,
|
||||||
_arena: Allocator,
|
_arena: Allocator,
|
||||||
_headers: *Headers,
|
_headers: *Headers,
|
||||||
@@ -65,7 +64,6 @@ pub fn init(body_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*Response {
|
|||||||
|
|
||||||
const self = try arena.create(Response);
|
const self = try arena.create(Response);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
._page = page,
|
|
||||||
._arena = arena,
|
._arena = arena,
|
||||||
._status = opts.status,
|
._status = opts.status,
|
||||||
._status_text = status_text,
|
._status_text = status_text,
|
||||||
@@ -78,7 +76,7 @@ pub fn init(body_: ?[]const u8, opts_: ?InitOpts, page: *Page) !*Response {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Response, shutdown: bool) void {
|
pub fn deinit(self: *Response, shutdown: bool, page: *Page) void {
|
||||||
if (self._transfer) |transfer| {
|
if (self._transfer) |transfer| {
|
||||||
if (shutdown) {
|
if (shutdown) {
|
||||||
transfer.terminate();
|
transfer.terminate();
|
||||||
@@ -87,7 +85,7 @@ pub fn deinit(self: *Response, shutdown: bool) void {
|
|||||||
}
|
}
|
||||||
self._transfer = null;
|
self._transfer = null;
|
||||||
}
|
}
|
||||||
self._page.releaseArena(self._arena);
|
page.releaseArena(self._arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getStatus(self: *const Response) u16 {
|
pub fn getStatus(self: *const Response) u16 {
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ pub fn init(page: *Page) !*XMLHttpRequest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *XMLHttpRequest, shutdown: bool) void {
|
pub fn deinit(self: *XMLHttpRequest, shutdown: bool, page: *Page) void {
|
||||||
if (self._transfer) |transfer| {
|
if (self._transfer) |transfer| {
|
||||||
if (shutdown) {
|
if (shutdown) {
|
||||||
transfer.terminate();
|
transfer.terminate();
|
||||||
@@ -102,7 +102,6 @@ pub fn deinit(self: *XMLHttpRequest, shutdown: bool) void {
|
|||||||
self._transfer = null;
|
self._transfer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = self._page;
|
|
||||||
const js_ctx = page.js;
|
const js_ctx = page.js;
|
||||||
if (self._on_ready_state_change) |func| {
|
if (self._on_ready_state_change) |func| {
|
||||||
js_ctx.release(func);
|
js_ctx.release(func);
|
||||||
@@ -182,9 +181,10 @@ pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8) !void
|
|||||||
self._response_headers.clearRetainingCapacity();
|
self._response_headers.clearRetainingCapacity();
|
||||||
self._request_body = null;
|
self._request_body = null;
|
||||||
|
|
||||||
|
const page = self._page;
|
||||||
self._method = try parseMethod(method_);
|
self._method = try parseMethod(method_);
|
||||||
self._url = try URL.resolve(self._arena, self._page.base(), url, .{ .always_dupe = true });
|
self._url = try URL.resolve(self._arena, page.base(), url, .{ .always_dupe = true });
|
||||||
try self.stateChanged(.opened, self._page.js.local.?, self._page);
|
try self.stateChanged(.opened, page.js.local.?, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setRequestHeader(self: *XMLHttpRequest, name: []const u8, value: []const u8, page: *Page) !void {
|
pub fn setRequestHeader(self: *XMLHttpRequest, name: []const u8, value: []const u8, page: *Page) !void {
|
||||||
@@ -524,8 +524,6 @@ fn stateChanged(self: *XMLHttpRequest, state: ReadyState, local: *const js.Local
|
|||||||
self._ready_state = state;
|
self._ready_state = state;
|
||||||
|
|
||||||
const event = try Event.initTrusted(.wrap("readystatechange"), .{}, page);
|
const event = try Event.initTrusted(.wrap("readystatechange"), .{}, page);
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
try page._event_manager.dispatchWithFunction(
|
try page._event_manager.dispatchWithFunction(
|
||||||
self.asEventTarget(),
|
self.asEventTarget(),
|
||||||
event,
|
event,
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ pub fn dispatch(self: *XMLHttpRequestEventTarget, comptime event_type: DispatchT
|
|||||||
.{ .total = progress.total, .loaded = progress.loaded },
|
.{ .total = progress.total, .loaded = progress.loaded },
|
||||||
page,
|
page,
|
||||||
)).asEvent();
|
)).asEvent();
|
||||||
defer if (!event._v8_handoff) event.deinit(false);
|
|
||||||
|
|
||||||
return page._event_manager.dispatchWithFunction(
|
return page._event_manager.dispatchWithFunction(
|
||||||
self.asEventTarget(),
|
self.asEventTarget(),
|
||||||
|
|||||||
Reference in New Issue
Block a user