diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..e70c82c9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,22 @@ +name: Build and test + +on: + pull_request: + push: + branches: [main] + +jobs: + macos_test: + runs-on: macos-11.0 + + steps: + - uses: actions/checkout@v2 + - name: Run the test suite on macOS + shell: bash + run: | + set -ex + sudo xcode-select --switch /Applications/Xcode_12.3.app/Contents/Developer/ + + brew install swiftwasm/tap/carton + + carton test --environment defaultBrowser diff --git a/Sources/DOMKit/ECMAScript/Support.swift b/Sources/DOMKit/ECMAScript/Support.swift index 3b36737e..45736af2 100644 --- a/Sources/DOMKit/ECMAScript/Support.swift +++ b/Sources/DOMKit/ECMAScript/Support.swift @@ -38,34 +38,19 @@ public class ReadableStream: JSBridgedClass { } } -@propertyWrapper public struct ClosureHandler { - +@propertyWrapper public final class OptionalClosureHandler +where ArgumentType: JSValueCompatible, ReturnType: JSValueCompatible { let jsObject: JSObject let name: String + var closure: JSClosure? public init(jsObject: JSObject, name: String) { self.jsObject = jsObject self.name = name } - public var wrappedValue: (ArgumentType) -> ReturnType { - get { - { arg in jsObject[name]!(arg).fromJSValue()! } - } - set { - jsObject[name] = JSClosure { newValue($0[0].fromJSValue()!).jsValue() }.jsValue() - } - } -} - -@propertyWrapper public struct OptionalClosureHandler { - - let jsObject: JSObject - let name: String - - public init(jsObject: JSObject, name: String) { - self.jsObject = jsObject - self.name = name + deinit { + closure?.release() } public var wrappedValue: ((ArgumentType) -> ReturnType)? { @@ -76,8 +61,13 @@ public class ReadableStream: JSBridgedClass { return { function($0.jsValue()).fromJSValue()! } } set { + if let closure = closure { + closure.release() + } if let newValue = newValue { - jsObject[name] = JSClosure { newValue($0[0].fromJSValue()!).jsValue() }.jsValue() + let closure = JSClosure { newValue($0[0].fromJSValue()!).jsValue() } + jsObject[name] = closure.jsValue() + self.closure = closure } else { jsObject[name] = .null } diff --git a/Sources/DOMKit/WebIDL/AddEventListenerOptions.swift b/Sources/DOMKit/WebIDL/AddEventListenerOptions.swift index 5dd30a38..52ecbe6b 100644 --- a/Sources/DOMKit/WebIDL/AddEventListenerOptions.swift +++ b/Sources/DOMKit/WebIDL/AddEventListenerOptions.swift @@ -12,11 +12,11 @@ public struct AddEventListenerOptions: ExpressibleByDictionaryLiteral, JSBridged private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/AnyDocumentAndElementEventHandlers.swift b/Sources/DOMKit/WebIDL/AnyDocumentAndElementEventHandlers.swift deleted file mode 100644 index b64af0ce..00000000 --- a/Sources/DOMKit/WebIDL/AnyDocumentAndElementEventHandlers.swift +++ /dev/null @@ -1,16 +0,0 @@ - -/* - * The following code is auto generated using webidl2swift - */ - -import JavaScriptKit - -class AnyDocumentAndElementEventHandlers: JSBridgedClass, DocumentAndElementEventHandlers { - public class var constructor: JSFunction { JSObject.global.DocumentAndElementEventHandlers.function! } - - let jsObject: JSObject - - required init(unsafelyWrapping jsObject: JSObject) { - self.jsObject = jsObject - } -} diff --git a/Sources/DOMKit/WebIDL/AnyGlobalEventHandlers.swift b/Sources/DOMKit/WebIDL/AnyGlobalEventHandlers.swift deleted file mode 100644 index 87ffb996..00000000 --- a/Sources/DOMKit/WebIDL/AnyGlobalEventHandlers.swift +++ /dev/null @@ -1,16 +0,0 @@ - -/* - * The following code is auto generated using webidl2swift - */ - -import JavaScriptKit - -class AnyGlobalEventHandlers: JSBridgedClass, GlobalEventHandlers { - public class var constructor: JSFunction { JSObject.global.GlobalEventHandlers.function! } - - let jsObject: JSObject - - required init(unsafelyWrapping jsObject: JSObject) { - self.jsObject = jsObject - } -} diff --git a/Sources/DOMKit/WebIDL/ArrayBufferView.swift b/Sources/DOMKit/WebIDL/ArrayBufferView.swift index d415bdf7..1cc4e1c2 100644 --- a/Sources/DOMKit/WebIDL/ArrayBufferView.swift +++ b/Sources/DOMKit/WebIDL/ArrayBufferView.swift @@ -5,4 +5,58 @@ import JavaScriptKit -public typealias ArrayBufferView = Int8ArrayOrInt16ArrayOrInt32ArrayOrUint8ArrayOrUint16ArrayOrUint32ArrayOrUint8ClampedArrayOrFloat32ArrayOrFloat64ArrayOrDataView +public enum ArrayBufferView: JSBridgedType { + case int8Array(JSTypedArray) + case int16Array(JSTypedArray) + case int32Array(JSTypedArray) + case uint8Array(JSTypedArray) + case uint16Array(JSTypedArray) + case uint32Array(JSTypedArray) + case uint8ClampedArray(JSTypedArray) + case float32Array(JSTypedArray) + case float64Array(JSTypedArray) + case dataView(DataView) + + public init?(from value: JSValue) { + if let decoded: JSTypedArray = value.fromJSValue() { + self = .int8Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .int16Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .int32Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .uint8Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .uint16Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .uint32Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .uint8ClampedArray(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .float32Array(decoded) + } else if let decoded: JSTypedArray = value.fromJSValue() { + self = .float64Array(decoded) + } else if let decoded: DataView = value.fromJSValue() { + self = .dataView(decoded) + } else { + return nil + } + } + + public var value: JSValue { jsValue() } + + public func jsValue() -> JSValue { + switch self { + case let .int8Array(v): return v.jsValue() + case let .int16Array(v): return v.jsValue() + case let .int32Array(v): return v.jsValue() + case let .uint8Array(v): return v.jsValue() + case let .uint16Array(v): return v.jsValue() + case let .uint32Array(v): return v.jsValue() + case let .uint8ClampedArray(v): return v.jsValue() + case let .float32Array(v): return v.jsValue() + case let .float64Array(v): return v.jsValue() + case let .dataView(v): return v.jsValue() + } + } +} diff --git a/Sources/DOMKit/WebIDL/AssignedNodesOptions.swift b/Sources/DOMKit/WebIDL/AssignedNodesOptions.swift index 61ffd95b..8754b6ac 100644 --- a/Sources/DOMKit/WebIDL/AssignedNodesOptions.swift +++ b/Sources/DOMKit/WebIDL/AssignedNodesOptions.swift @@ -12,11 +12,11 @@ public struct AssignedNodesOptions: ExpressibleByDictionaryLiteral, JSBridgedTyp private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/BlobPropertyBag.swift b/Sources/DOMKit/WebIDL/BlobPropertyBag.swift index f5e4c3db..8dd21c0f 100644 --- a/Sources/DOMKit/WebIDL/BlobPropertyBag.swift +++ b/Sources/DOMKit/WebIDL/BlobPropertyBag.swift @@ -12,11 +12,11 @@ public struct BlobPropertyBag: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/CustomEventInit.swift b/Sources/DOMKit/WebIDL/CustomEventInit.swift index 0cbb224d..52c858d6 100644 --- a/Sources/DOMKit/WebIDL/CustomEventInit.swift +++ b/Sources/DOMKit/WebIDL/CustomEventInit.swift @@ -12,11 +12,11 @@ public struct CustomEventInit: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/ElementCreationOptions.swift b/Sources/DOMKit/WebIDL/ElementCreationOptions.swift index 32e7a73d..0a2b9c15 100644 --- a/Sources/DOMKit/WebIDL/ElementCreationOptions.swift +++ b/Sources/DOMKit/WebIDL/ElementCreationOptions.swift @@ -12,11 +12,11 @@ public struct ElementCreationOptions: ExpressibleByDictionaryLiteral, JSBridgedT private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/EndingType.swift b/Sources/DOMKit/WebIDL/EndingType.swift index 69c66d5d..91a975d3 100644 --- a/Sources/DOMKit/WebIDL/EndingType.swift +++ b/Sources/DOMKit/WebIDL/EndingType.swift @@ -5,7 +5,7 @@ import JavaScriptKit -public enum EndingType: String, JSValueCodable { +public enum EndingType: String, JSValueCompatible { public static func construct(from jsValue: JSValue) -> EndingType? { if let string = jsValue.string, let value = EndingType(rawValue: string) diff --git a/Sources/DOMKit/WebIDL/EventInit.swift b/Sources/DOMKit/WebIDL/EventInit.swift index 7719ba90..30322086 100644 --- a/Sources/DOMKit/WebIDL/EventInit.swift +++ b/Sources/DOMKit/WebIDL/EventInit.swift @@ -12,11 +12,11 @@ public struct EventInit: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/EventListener.swift b/Sources/DOMKit/WebIDL/EventListener.swift index b083400c..493a6072 100644 --- a/Sources/DOMKit/WebIDL/EventListener.swift +++ b/Sources/DOMKit/WebIDL/EventListener.swift @@ -6,5 +6,5 @@ import JavaScriptKit public protocol EventListener: JSBridgedType { - func handleEvent(event: Event) -> Void + func handleEvent(event: Event) } diff --git a/Sources/DOMKit/WebIDL/EventListenerOptions.swift b/Sources/DOMKit/WebIDL/EventListenerOptions.swift index d40fabd8..2786767f 100644 --- a/Sources/DOMKit/WebIDL/EventListenerOptions.swift +++ b/Sources/DOMKit/WebIDL/EventListenerOptions.swift @@ -12,11 +12,11 @@ public struct EventListenerOptions: ExpressibleByDictionaryLiteral, JSBridgedTyp private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/EventTarget.swift b/Sources/DOMKit/WebIDL/EventTarget.swift index 64442b04..f5496619 100644 --- a/Sources/DOMKit/WebIDL/EventTarget.swift +++ b/Sources/DOMKit/WebIDL/EventTarget.swift @@ -6,8 +6,14 @@ import JavaScriptKit public class EventTarget: JSBridgedClass { + public struct Token { + var type: String + var index: Int + } public class var constructor: JSFunction { JSObject.global.EventTarget.function! } + var eventListeners = [String: [JSClosure]]() + public let jsObject: JSObject public required init(unsafelyWrapping jsObject: JSObject) { @@ -18,20 +24,63 @@ public class EventTarget: JSBridgedClass { self.init(unsafelyWrapping: EventTarget.constructor.new()) } - public func addEventListener(type: String, callback: EventListenerType?, options: AddEventListenerOptionsOrBool = [:]) -> Void { + deinit { + for (_, listeners) in eventListeners { + for closure in listeners { + closure.release() + } + } + } + + public func addEventListener( + type: String, + options: AddEventListenerOptionsOrBool = [:], + callback: EventListenerType) { _ = jsObject.addEventListener!(type.jsValue(), callback.jsValue(), options.jsValue()) } - public func addEventListener(type: String, callback: ((Event) -> Void)?, options: AddEventListenerOptionsOrBool = [:]) { - _ = jsObject.addEventListener!(type.jsValue(), callback == nil ? nil : JSClosure { callback!($0[0].fromJSValue()!) }, options.jsValue()) + public func addEventListener( + type: String, + options: AddEventListenerOptionsOrBool = [:], + callback: @escaping (Event) -> () + ) -> Token { + let closure = JSClosure { callback($0[0].fromJSValue()!) } + let token: Token + let listeners: [JSClosure] + if var existingListeners = eventListeners[type] { + token = Token(type: type, index: existingListeners.count) + existingListeners.append(closure) + listeners = existingListeners + } else { + token = Token(type: type, index: 0) + listeners = [closure] + } + eventListeners[type] = listeners + + _ = jsObject.addEventListener!(type.jsValue(), closure, options.jsValue()) + + return token } - public func removeEventListener(type: String, callback: EventListenerType?, options: EventListenerOptionsOrBool = [:]) -> Void { + public func removeEventListener( + type: String, + options: EventListenerOptionsOrBool = [:], + callback: EventListenerType + ) { _ = jsObject.removeEventListener!(type.jsValue(), callback.jsValue(), options.jsValue()) } - public func removeEventListener(type: String, callback: ((Event) -> Void)?, options: EventListenerOptionsOrBool = [:]) { - _ = jsObject.removeEventListener!(type.jsValue(), callback == nil ? nil : JSClosure { callback!($0[0].fromJSValue()!) }, options.jsValue()) + public func removeEventListener( + type: String, + token: Token, + options: EventListenerOptionsOrBool = [:] + ) { + guard var listeners = eventListeners[type] else { return } + + let closure = listeners[token.index] + _ = jsObject.removeEventListener!(type.jsValue(), closure, options.jsValue()) + listeners.remove(at: token.index) + closure.release() } public func dispatchEvent(event: Event) -> Bool { diff --git a/Sources/DOMKit/WebIDL/FilePropertyBag.swift b/Sources/DOMKit/WebIDL/FilePropertyBag.swift index 5845c2f3..6415c050 100644 --- a/Sources/DOMKit/WebIDL/FilePropertyBag.swift +++ b/Sources/DOMKit/WebIDL/FilePropertyBag.swift @@ -12,11 +12,11 @@ public struct FilePropertyBag: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/FocusOptions.swift b/Sources/DOMKit/WebIDL/FocusOptions.swift index 50a1972c..ff3f0a1a 100644 --- a/Sources/DOMKit/WebIDL/FocusOptions.swift +++ b/Sources/DOMKit/WebIDL/FocusOptions.swift @@ -12,11 +12,11 @@ public struct FocusOptions: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/GetRootNodeOptions.swift b/Sources/DOMKit/WebIDL/GetRootNodeOptions.swift index 20f859ea..cc024db8 100644 --- a/Sources/DOMKit/WebIDL/GetRootNodeOptions.swift +++ b/Sources/DOMKit/WebIDL/GetRootNodeOptions.swift @@ -12,11 +12,11 @@ public struct GetRootNodeOptions: ExpressibleByDictionaryLiteral, JSBridgedType private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/GlobalEventHandlers.swift b/Sources/DOMKit/WebIDL/HTMLElement+EventHandler.swift similarity index 58% rename from Sources/DOMKit/WebIDL/GlobalEventHandlers.swift rename to Sources/DOMKit/WebIDL/HTMLElement+EventHandler.swift index 021b0b12..41d678e8 100644 --- a/Sources/DOMKit/WebIDL/GlobalEventHandlers.swift +++ b/Sources/DOMKit/WebIDL/HTMLElement+EventHandler.swift @@ -5,9 +5,7 @@ import JavaScriptKit -public protocol GlobalEventHandlers: JSBridgedClass {} - -public extension GlobalEventHandlers { +public extension HTMLElement { var onabort: EventHandler { get { guard let function = jsObject.onabort.function else { @@ -17,9 +15,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onabort = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onabort"] { + oldClosure.release() + } + eventHandlerClosures["onabort"] = closure + jsObject.onabort = closure.jsValue() } else { jsObject.onabort = .null } @@ -35,9 +38,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onauxclick = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onauxclick"] { + oldClosure.release() + } + eventHandlerClosures["onauxclick"] = closure + jsObject.onauxclick = closure.jsValue() } else { jsObject.onauxclick = .null } @@ -53,9 +61,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onblur = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onblur"] { + oldClosure.release() + } + eventHandlerClosures["onblur"] = closure + jsObject.onblur = closure.jsValue() } else { jsObject.onblur = .null } @@ -71,9 +84,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oncancel = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oncancel"] { + oldClosure.release() + } + eventHandlerClosures["oncancel"] = closure + jsObject.oncancel = closure.jsValue() } else { jsObject.oncancel = .null } @@ -89,9 +107,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oncanplay = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oncanplay"] { + oldClosure.release() + } + eventHandlerClosures["oncanplay"] = closure + jsObject.oncanplay = closure.jsValue() } else { jsObject.oncanplay = .null } @@ -107,9 +130,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oncanplaythrough = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oncanplaythrough"] { + oldClosure.release() + } + eventHandlerClosures["oncanplaythrough"] = closure + jsObject.oncanplaythrough = closure.jsValue() } else { jsObject.oncanplaythrough = .null } @@ -125,9 +153,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onchange = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onchange"] { + oldClosure.release() + } + eventHandlerClosures["onchange"] = closure + jsObject.onchange = closure.jsValue() } else { jsObject.onchange = .null } @@ -143,9 +176,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onclick = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onclick"] { + oldClosure.release() + } + eventHandlerClosures["onclick"] = closure + jsObject.onclick = closure.jsValue() } else { jsObject.onclick = .null } @@ -161,9 +199,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onclose = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onclose"] { + oldClosure.release() + } + eventHandlerClosures["onclose"] = closure + jsObject.onclose = closure.jsValue() } else { jsObject.onclose = .null } @@ -179,9 +222,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oncontextmenu = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oncontextmenu"] { + oldClosure.release() + } + eventHandlerClosures["oncontextmenu"] = closure + jsObject.oncontextmenu = closure.jsValue() } else { jsObject.oncontextmenu = .null } @@ -197,9 +245,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oncuechange = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oncuechange"] { + oldClosure.release() + } + eventHandlerClosures["oncuechange"] = closure + jsObject.oncuechange = closure.jsValue() } else { jsObject.oncuechange = .null } @@ -215,9 +268,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondblclick = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondblclick"] { + oldClosure.release() + } + eventHandlerClosures["ondblclick"] = closure + jsObject.ondblclick = closure.jsValue() } else { jsObject.ondblclick = .null } @@ -233,9 +291,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondrag = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondrag"] { + oldClosure.release() + } + eventHandlerClosures["ondrag"] = closure + jsObject.ondrag = closure.jsValue() } else { jsObject.ondrag = .null } @@ -251,9 +314,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondragend = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondragend"] { + oldClosure.release() + } + eventHandlerClosures["ondragend"] = closure + jsObject.ondragend = closure.jsValue() } else { jsObject.ondragend = .null } @@ -269,9 +337,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondragenter = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondragenter"] { + oldClosure.release() + } + eventHandlerClosures["ondragenter"] = closure + jsObject.ondragenter = closure.jsValue() } else { jsObject.ondragenter = .null } @@ -287,9 +360,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondragexit = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondragexit"] { + oldClosure.release() + } + eventHandlerClosures["ondragexit"] = closure + jsObject.ondragexit = closure.jsValue() } else { jsObject.ondragexit = .null } @@ -305,9 +383,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondragleave = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondragleave"] { + oldClosure.release() + } + eventHandlerClosures["ondragleave"] = closure + jsObject.ondragleave = closure.jsValue() } else { jsObject.ondragleave = .null } @@ -323,9 +406,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondragover = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondragover"] { + oldClosure.release() + } + eventHandlerClosures["ondragover"] = closure + jsObject.ondragover = closure.jsValue() } else { jsObject.ondragover = .null } @@ -341,9 +429,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondragstart = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondragstart"] { + oldClosure.release() + } + eventHandlerClosures["ondragstart"] = closure + jsObject.ondragstart = closure.jsValue() } else { jsObject.ondragstart = .null } @@ -359,9 +452,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondrop = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondrop"] { + oldClosure.release() + } + eventHandlerClosures["ondrop"] = closure + jsObject.ondrop = closure.jsValue() } else { jsObject.ondrop = .null } @@ -377,9 +475,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ondurationchange = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ondurationchange"] { + oldClosure.release() + } + eventHandlerClosures["ondurationchange"] = closure + jsObject.ondurationchange = closure.jsValue() } else { jsObject.ondurationchange = .null } @@ -395,9 +498,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onemptied = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onemptied"] { + oldClosure.release() + } + eventHandlerClosures["onemptied"] = closure + jsObject.onemptied = closure.jsValue() } else { jsObject.onemptied = .null } @@ -413,9 +521,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onended = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onended"] { + oldClosure.release() + } + eventHandlerClosures["onended"] = closure + jsObject.onended = closure.jsValue() } else { jsObject.onended = .null } @@ -431,9 +544,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onerror = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!, arguments[1].fromJSValue()!, arguments[2].fromJSValue()!, arguments[3].fromJSValue()!, arguments[4].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onerror"] { + oldClosure.release() + } + eventHandlerClosures["onerror"] = closure + jsObject.onerror = closure.jsValue() } else { jsObject.onerror = .null } @@ -449,9 +567,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onfocus = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onfocus"] { + oldClosure.release() + } + eventHandlerClosures["onfocus"] = closure + jsObject.onfocus = closure.jsValue() } else { jsObject.onfocus = .null } @@ -467,9 +590,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onformdata = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onformdata"] { + oldClosure.release() + } + eventHandlerClosures["onformdata"] = closure + jsObject.onformdata = closure.jsValue() } else { jsObject.onformdata = .null } @@ -485,9 +613,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oninput = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oninput"] { + oldClosure.release() + } + eventHandlerClosures["oninput"] = closure + jsObject.oninput = closure.jsValue() } else { jsObject.oninput = .null } @@ -503,9 +636,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.oninvalid = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["oninvalid"] { + oldClosure.release() + } + eventHandlerClosures["oninvalid"] = closure + jsObject.oninvalid = closure.jsValue() } else { jsObject.oninvalid = .null } @@ -521,9 +659,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onkeydown = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onkeydown"] { + oldClosure.release() + } + eventHandlerClosures["onkeydown"] = closure + jsObject.onkeydown = closure.jsValue() } else { jsObject.onkeydown = .null } @@ -539,9 +682,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onkeypress = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onkeypress"] { + oldClosure.release() + } + eventHandlerClosures["onkeypress"] = closure + jsObject.onkeypress = closure.jsValue() } else { jsObject.onkeypress = .null } @@ -557,9 +705,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onkeyup = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onkeyup"] { + oldClosure.release() + } + eventHandlerClosures["onkeyup"] = closure + jsObject.onkeyup = closure.jsValue() } else { jsObject.onkeyup = .null } @@ -575,9 +728,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onload = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onload"] { + oldClosure.release() + } + eventHandlerClosures["onload"] = closure + jsObject.onload = closure.jsValue() } else { jsObject.onload = .null } @@ -593,9 +751,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onloadeddata = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onloadeddata"] { + oldClosure.release() + } + eventHandlerClosures["onloadeddata"] = closure + jsObject.onloadeddata = closure.jsValue() } else { jsObject.onloadeddata = .null } @@ -611,9 +774,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onloadedmetadata = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onloadedmetadata"] { + oldClosure.release() + } + eventHandlerClosures["onloadedmetadata"] = closure + jsObject.onloadedmetadata = closure.jsValue() } else { jsObject.onloadedmetadata = .null } @@ -629,9 +797,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onloadstart = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onloadstart"] { + oldClosure.release() + } + eventHandlerClosures["onloadstart"] = closure + jsObject.onloadstart = closure.jsValue() } else { jsObject.onloadstart = .null } @@ -647,9 +820,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmousedown = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmousedown"] { + oldClosure.release() + } + eventHandlerClosures["onmousedown"] = closure + jsObject.onmousedown = closure.jsValue() } else { jsObject.onmousedown = .null } @@ -665,9 +843,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmouseenter = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmouseenter"] { + oldClosure.release() + } + eventHandlerClosures["onmouseenter"] = closure + jsObject.onmouseenter = closure.jsValue() } else { jsObject.onmouseenter = .null } @@ -683,9 +866,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmouseleave = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmouseleave"] { + oldClosure.release() + } + eventHandlerClosures["onmouseleave"] = closure + jsObject.onmouseleave = closure.jsValue() } else { jsObject.onmouseleave = .null } @@ -701,9 +889,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmousemove = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmousemove"] { + oldClosure.release() + } + eventHandlerClosures["onmousemove"] = closure + jsObject.onmousemove = closure.jsValue() } else { jsObject.onmousemove = .null } @@ -719,9 +912,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmouseout = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmouseout"] { + oldClosure.release() + } + eventHandlerClosures["onmouseout"] = closure + jsObject.onmouseout = closure.jsValue() } else { jsObject.onmouseout = .null } @@ -737,9 +935,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmouseover = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmouseover"] { + oldClosure.release() + } + eventHandlerClosures["onmouseover"] = closure + jsObject.onmouseover = closure.jsValue() } else { jsObject.onmouseover = .null } @@ -755,9 +958,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onmouseup = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onmouseup"] { + oldClosure.release() + } + eventHandlerClosures["onmouseup"] = closure + jsObject.onmouseup = closure.jsValue() } else { jsObject.onmouseup = .null } @@ -773,9 +981,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onpause = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onpause"] { + oldClosure.release() + } + eventHandlerClosures["onpause"] = closure + jsObject.onpause = closure.jsValue() } else { jsObject.onpause = .null } @@ -791,9 +1004,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onplay = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onplay"] { + oldClosure.release() + } + eventHandlerClosures["onplay"] = closure + jsObject.onplay = closure.jsValue() } else { jsObject.onplay = .null } @@ -809,9 +1027,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onplaying = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onplaying"] { + oldClosure.release() + } + eventHandlerClosures["onplaying"] = closure + jsObject.onplaying = closure.jsValue() } else { jsObject.onplaying = .null } @@ -827,9 +1050,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onprogress = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onprogress"] { + oldClosure.release() + } + eventHandlerClosures["onprogress"] = closure + jsObject.onprogress = closure.jsValue() } else { jsObject.onprogress = .null } @@ -845,9 +1073,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onratechange = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onratechange"] { + oldClosure.release() + } + eventHandlerClosures["onratechange"] = closure + jsObject.onratechange = closure.jsValue() } else { jsObject.onratechange = .null } @@ -863,9 +1096,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onreset = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onreset"] { + oldClosure.release() + } + eventHandlerClosures["onreset"] = closure + jsObject.onreset = closure.jsValue() } else { jsObject.onreset = .null } @@ -881,9 +1119,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onresize = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onresize"] { + oldClosure.release() + } + eventHandlerClosures["onresize"] = closure + jsObject.onresize = closure.jsValue() } else { jsObject.onresize = .null } @@ -899,9 +1142,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onscroll = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onscroll"] { + oldClosure.release() + } + eventHandlerClosures["onscroll"] = closure + jsObject.onscroll = closure.jsValue() } else { jsObject.onscroll = .null } @@ -917,9 +1165,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onsecuritypolicyviolation = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onsecuritypolicyviolation"] { + oldClosure.release() + } + eventHandlerClosures["onsecuritypolicyviolation"] = closure + jsObject.onsecuritypolicyviolation = closure.jsValue() } else { jsObject.onsecuritypolicyviolation = .null } @@ -935,9 +1188,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onseeked = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onseeked"] { + oldClosure.release() + } + eventHandlerClosures["onseeked"] = closure + jsObject.onseeked = closure.jsValue() } else { jsObject.onseeked = .null } @@ -953,9 +1211,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onseeking = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onseeking"] { + oldClosure.release() + } + eventHandlerClosures["onseeking"] = closure + jsObject.onseeking = closure.jsValue() } else { jsObject.onseeking = .null } @@ -971,9 +1234,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onselect = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onselect"] { + oldClosure.release() + } + eventHandlerClosures["onselect"] = closure + jsObject.onselect = closure.jsValue() } else { jsObject.onselect = .null } @@ -989,9 +1257,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onslotchange = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onslotchange"] { + oldClosure.release() + } + eventHandlerClosures["onslotchange"] = closure + jsObject.onslotchange = closure.jsValue() } else { jsObject.onslotchange = .null } @@ -1007,9 +1280,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onstalled = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onstalled"] { + oldClosure.release() + } + eventHandlerClosures["onstalled"] = closure + jsObject.onstalled = closure.jsValue() } else { jsObject.onstalled = .null } @@ -1025,9 +1303,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onsubmit = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onsubmit"] { + oldClosure.release() + } + eventHandlerClosures["onsubmit"] = closure + jsObject.onsubmit = closure.jsValue() } else { jsObject.onsubmit = .null } @@ -1043,9 +1326,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onsuspend = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onsuspend"] { + oldClosure.release() + } + eventHandlerClosures["onsuspend"] = closure + jsObject.onsuspend = closure.jsValue() } else { jsObject.onsuspend = .null } @@ -1061,9 +1349,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ontimeupdate = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ontimeupdate"] { + oldClosure.release() + } + eventHandlerClosures["ontimeupdate"] = closure + jsObject.ontimeupdate = closure.jsValue() } else { jsObject.ontimeupdate = .null } @@ -1079,9 +1372,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.ontoggle = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["ontoggle"] { + oldClosure.release() + } + eventHandlerClosures["ontoggle"] = closure + jsObject.ontoggle = closure.jsValue() } else { jsObject.ontoggle = .null } @@ -1097,9 +1395,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onvolumechange = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onvolumechange"] { + oldClosure.release() + } + eventHandlerClosures["onvolumechange"] = closure + jsObject.onvolumechange = closure.jsValue() } else { jsObject.onvolumechange = .null } @@ -1115,9 +1418,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onwaiting = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onwaiting"] { + oldClosure.release() + } + eventHandlerClosures["onwaiting"] = closure + jsObject.onwaiting = closure.jsValue() } else { jsObject.onwaiting = .null } @@ -1133,9 +1441,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onwebkitanimationend = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onwebkitanimationend"] { + oldClosure.release() + } + eventHandlerClosures["onwebkitanimationend"] = closure + jsObject.onwebkitanimationend = closure.jsValue() } else { jsObject.onwebkitanimationend = .null } @@ -1151,9 +1464,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onwebkitanimationiteration = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onwebkitanimationiteration"] { + oldClosure.release() + } + eventHandlerClosures["onwebkitanimationiteration"] = closure + jsObject.onwebkitanimationiteration = closure.jsValue() } else { jsObject.onwebkitanimationiteration = .null } @@ -1169,9 +1487,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onwebkitanimationstart = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onwebkitanimationstart"] { + oldClosure.release() + } + eventHandlerClosures["onwebkitanimationstart"] = closure + jsObject.onwebkitanimationstart = closure.jsValue() } else { jsObject.onwebkitanimationstart = .null } @@ -1187,9 +1510,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onwebkittransitionend = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onwebkittransitionend"] { + oldClosure.release() + } + eventHandlerClosures["onwebkittransitionend"] = closure + jsObject.onwebkittransitionend = closure.jsValue() } else { jsObject.onwebkittransitionend = .null } @@ -1205,9 +1533,14 @@ public extension GlobalEventHandlers { } set { if let newValue = newValue { - jsObject.onwheel = JSClosure { arguments in + let closure = JSClosure { arguments in newValue(arguments[0].fromJSValue()!).jsValue() - }.jsValue() + } + if let oldClosure = eventHandlerClosures["onwheel"] { + oldClosure.release() + } + eventHandlerClosures["onwheel"] = closure + jsObject.onwheel = closure.jsValue() } else { jsObject.onwheel = .null } diff --git a/Sources/DOMKit/WebIDL/HTMLElement.swift b/Sources/DOMKit/WebIDL/HTMLElement.swift index 36afc2c6..da6d96b9 100644 --- a/Sources/DOMKit/WebIDL/HTMLElement.swift +++ b/Sources/DOMKit/WebIDL/HTMLElement.swift @@ -5,9 +5,11 @@ import JavaScriptKit -public class HTMLElement: Element, DocumentAndElementEventHandlers, ElementContentEditable, GlobalEventHandlers, HTMLOrSVGElement { +public class HTMLElement: Element, DocumentAndElementEventHandlers, ElementContentEditable, HTMLOrSVGElement { override public class var constructor: JSFunction { JSObject.global.HTMLElement.function! } + var eventHandlerClosures = [String: JSClosure]() + public required init(unsafelyWrapping jsObject: JSObject) { _title = ReadWriteAttribute(jsObject: jsObject, name: "title") _lang = ReadWriteAttribute(jsObject: jsObject, name: "lang") @@ -67,4 +69,10 @@ public class HTMLElement: Element, DocumentAndElementEventHandlers, ElementConte public func attachInternals() -> ElementInternals { return jsObject.attachInternals!().fromJSValue()! } + + deinit { + for (_, closure) in eventHandlerClosures { + closure.release() + } + } } diff --git a/Sources/DOMKit/WebIDL/Int8ArrayOrInt16ArrayOrInt32ArrayOrUint8ArrayOrUint16ArrayOrUint32ArrayOrUint8ClampedArrayOrFloat32ArrayOrFloat64ArrayOrDataView.swift b/Sources/DOMKit/WebIDL/Int8ArrayOrInt16ArrayOrInt32ArrayOrUint8ArrayOrUint16ArrayOrUint32ArrayOrUint8ClampedArrayOrFloat32ArrayOrFloat64ArrayOrDataView.swift deleted file mode 100644 index f4c75d16..00000000 --- a/Sources/DOMKit/WebIDL/Int8ArrayOrInt16ArrayOrInt32ArrayOrUint8ArrayOrUint16ArrayOrUint32ArrayOrUint8ClampedArrayOrFloat32ArrayOrFloat64ArrayOrDataView.swift +++ /dev/null @@ -1,62 +0,0 @@ - -/* - * The following code is auto generated using webidl2swift - */ - -import JavaScriptKit - -public enum Int8ArrayOrInt16ArrayOrInt32ArrayOrUint8ArrayOrUint16ArrayOrUint32ArrayOrUint8ClampedArrayOrFloat32ArrayOrFloat64ArrayOrDataView: JSBridgedType { - case int8Array(JSTypedArray) - case int16Array(JSTypedArray) - case int32Array(JSTypedArray) - case uint8Array(JSTypedArray) - case uint16Array(JSTypedArray) - case uint32Array(JSTypedArray) - case uint8ClampedArray(JSTypedArray) - case float32Array(JSTypedArray) - case float64Array(JSTypedArray) - case dataView(DataView) - - public init?(from value: JSValue) { - if let decoded: JSTypedArray = value.fromJSValue() { - self = .int8Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .int16Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .int32Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .uint8Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .uint16Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .uint32Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .uint8ClampedArray(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .float32Array(decoded) - } else if let decoded: JSTypedArray = value.fromJSValue() { - self = .float64Array(decoded) - } else if let decoded: DataView = value.fromJSValue() { - self = .dataView(decoded) - } else { - return nil - } - } - - public var value: JSValue { jsValue() } - - public func jsValue() -> JSValue { - switch self { - case let .int8Array(v): return v.jsValue() - case let .int16Array(v): return v.jsValue() - case let .int32Array(v): return v.jsValue() - case let .uint8Array(v): return v.jsValue() - case let .uint16Array(v): return v.jsValue() - case let .uint32Array(v): return v.jsValue() - case let .uint8ClampedArray(v): return v.jsValue() - case let .float32Array(v): return v.jsValue() - case let .float64Array(v): return v.jsValue() - case let .dataView(v): return v.jsValue() - } - } -} diff --git a/Sources/DOMKit/WebIDL/MutationObserver.swift b/Sources/DOMKit/WebIDL/MutationObserver.swift index d36bd7ca..c3a7eb19 100644 --- a/Sources/DOMKit/WebIDL/MutationObserver.swift +++ b/Sources/DOMKit/WebIDL/MutationObserver.swift @@ -9,13 +9,20 @@ public class MutationObserver: JSBridgedClass { public class var constructor: JSFunction { JSObject.global.MutationObserver.function! } public let jsObject: JSObject + var closure: JSClosure? public required init(unsafelyWrapping jsObject: JSObject) { self.jsObject = jsObject } public convenience init(callback: @escaping MutationCallback) { - self.init(unsafelyWrapping: MutationObserver.constructor.new(JSClosure { callback($0[0].fromJSValue()!, $0[1].fromJSValue()!) })) + let closure = JSClosure { callback($0[0].fromJSValue()!, $0[1].fromJSValue()!) } + self.init(unsafelyWrapping: MutationObserver.constructor.new(closure)) + self.closure = closure + } + + deinit { + closure?.release() } public func observe(target: Node, options: MutationObserverInit = [:]) { diff --git a/Sources/DOMKit/WebIDL/MutationObserverInit.swift b/Sources/DOMKit/WebIDL/MutationObserverInit.swift index 5e973949..81f50906 100644 --- a/Sources/DOMKit/WebIDL/MutationObserverInit.swift +++ b/Sources/DOMKit/WebIDL/MutationObserverInit.swift @@ -12,11 +12,11 @@ public struct MutationObserverInit: ExpressibleByDictionaryLiteral, JSBridgedTyp private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/ShadowRootInit.swift b/Sources/DOMKit/WebIDL/ShadowRootInit.swift index fb071d95..86cd543f 100644 --- a/Sources/DOMKit/WebIDL/ShadowRootInit.swift +++ b/Sources/DOMKit/WebIDL/ShadowRootInit.swift @@ -12,11 +12,11 @@ public struct ShadowRootInit: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/ShadowRootMode.swift b/Sources/DOMKit/WebIDL/ShadowRootMode.swift index 0161d46c..4768453a 100644 --- a/Sources/DOMKit/WebIDL/ShadowRootMode.swift +++ b/Sources/DOMKit/WebIDL/ShadowRootMode.swift @@ -5,7 +5,7 @@ import JavaScriptKit -public enum ShadowRootMode: String, JSValueCodable { +public enum ShadowRootMode: String, JSValueCompatible { public static func construct(from jsValue: JSValue) -> ShadowRootMode? { if let string = jsValue.string, let value = ShadowRootMode(rawValue: string) diff --git a/Sources/DOMKit/WebIDL/StaticRangeInit.swift b/Sources/DOMKit/WebIDL/StaticRangeInit.swift index 63f5f796..90e7a402 100644 --- a/Sources/DOMKit/WebIDL/StaticRangeInit.swift +++ b/Sources/DOMKit/WebIDL/StaticRangeInit.swift @@ -12,11 +12,11 @@ public struct StaticRangeInit: ExpressibleByDictionaryLiteral, JSBridgedType { private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/ValidityStateFlags.swift b/Sources/DOMKit/WebIDL/ValidityStateFlags.swift index 4bd8045d..8b507bc0 100644 --- a/Sources/DOMKit/WebIDL/ValidityStateFlags.swift +++ b/Sources/DOMKit/WebIDL/ValidityStateFlags.swift @@ -12,11 +12,11 @@ public struct ValidityStateFlags: ExpressibleByDictionaryLiteral, JSBridgedType private let dictionary: [String: JSValue] - public init(uniqueKeysWithValues elements: [(Key, JSValueConvertible)]) { + public init(uniqueKeysWithValues elements: [(Key, ConvertibleToJSValue)]) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } - public init(dictionaryLiteral elements: (Key, JSValueConvertible)...) { + public init(dictionaryLiteral elements: (Key, ConvertibleToJSValue)...) { dictionary = Dictionary(uniqueKeysWithValues: elements.map { ($0.0.rawValue, $0.1.jsValue()) }) } diff --git a/Sources/DOMKit/WebIDL/VoidFunction.swift b/Sources/DOMKit/WebIDL/VoidFunction.swift deleted file mode 100644 index 941d3c81..00000000 --- a/Sources/DOMKit/WebIDL/VoidFunction.swift +++ /dev/null @@ -1,8 +0,0 @@ - -/* - * The following code is auto generated using webidl2swift - */ - -import JavaScriptKit - -public typealias VoidFunction = (() -> Void) diff --git a/Tests/DOMKitTests/DOMKitTests.swift b/Tests/DOMKitTests/DOMKitTests.swift index e84bfa64..b7b08b80 100644 --- a/Tests/DOMKitTests/DOMKitTests.swift +++ b/Tests/DOMKitTests/DOMKitTests.swift @@ -1,19 +1,17 @@ import XCTest -import JavaScriptKit -@testable import DOMKit +import DOMKit final class DOMKitTests: XCTestCase { func testExample() { let document = globalThis.document let button = document.createElement(localName: "button") - button.textContent = "Hello, world" - button.addEventListener(type: "click", callback: { event in + button.textContent = "Hello, world!" + button.addEventListener(type: "click") { event in (event.target as? HTMLElement)?.textContent = "Clicked!" - }) + } _ = document.querySelector(selectors: "body")?.appendChild(node: button) - } - static var allTests = [ - ("testExample", testExample), - ] + let queriedButton = document.querySelector(selectors: "body button") + XCTAssertEqual(button.textContent, "Hello, world!") + } } diff --git a/Tests/DOMKitTests/XCTestManifests.swift b/Tests/DOMKitTests/XCTestManifests.swift deleted file mode 100644 index d65618a5..00000000 --- a/Tests/DOMKitTests/XCTestManifests.swift +++ /dev/null @@ -1,9 +0,0 @@ -import XCTest - -#if !canImport(ObjectiveC) -public func allTests() -> [XCTestCaseEntry] { - return [ - testCase(DOMKitTests.allTests), - ] -} -#endif diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift deleted file mode 100644 index 534719dd..00000000 --- a/Tests/LinuxMain.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest - -import DOMKitTests - -var tests = [XCTestCaseEntry]() -tests += DOMKitTests.allTests() -XCTMain(tests)