-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathEventTarget.swift
More file actions
112 lines (99 loc) · 5.34 KB
/
EventTarget.swift
File metadata and controls
112 lines (99 loc) · 5.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
//
// EventTarget.swift
// JavaScriptCoreBrowserObjectModel
//
// Created by Connor Grady on 11/15/17.
// Copyright © 2017 Connor Grady. All rights reserved.
//
import Foundation
import JavaScriptCore
// SPEC: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
@objc public protocol EventTargetJSProtocol: JSExport {
func addEventListener(_ event: String!, _ listener: EventListener!, _ options: JSValue?) -> Void
func removeEventListener(_ event: String!, _ listener: EventListener!, _ options: JSValue?) -> Void
func dispatchEvent(_ event: String!) -> Bool
}
@objc public class EventTarget: NSObject, EventTargetJSProtocol {
private var _eventListeners = [String: [( eventListener: EventListenerRef, options: EventListenerOptions? )]]()
public func addEventListener(_ event: String!, _ listener: EventListener!, _ options: JSValue? = nil) -> Void {
//let context = (JSContext.current() ?? listener.context)!
let context = listener.context!
//if var options = options {
// if options.isBoolean {
// options = JSValue(object: ( capture: options.toBool(), once: false, passive: false ), in: context)
// } else if /*options is EventListenerOptions*/options.isObject {
// // ...
// }
//}
if _eventListeners[event] == nil {
_eventListeners[event] = [( eventListener: EventListenerRef, options: EventListenerOptions? )]()
}
let managedValue = JSManagedValue(value: listener)!
context.virtualMachine.addManagedReference(managedValue, withOwner: self)
_eventListeners[event]!.append(( eventListener: managedValue, options: /*options*/nil ))
return
}
public func removeEventListener(_ event: String!, _ listener: EventListener!, _ options: JSValue? = nil) -> Void {
if let eventListeners = _eventListeners[event] {
if let listenerIdx = eventListeners.index(where: { listener == $0.eventListener.value }) {
removeEventListener(event, listenerIdx)
}
}
return
}
@discardableResult
func removeEventListener(_ event: String, _ index: Int) -> Bool {
if var eventListeners = _eventListeners[event] {
let removed = eventListeners.remove(at: index)
let virtualMachine = removed.eventListener.value.context.virtualMachine
virtualMachine?.removeManagedReference(removed.eventListener, withOwner: self)
return true
}
return false
}
@discardableResult
public func dispatchEvent(_ event: String!) -> Bool {
if let eventListener = value(forKey: "on\(String(stringLiteral: event))") as? EventListener {
//eventListener.value.call(withArguments: [])
let thisObject = JSValue(object: self, in: eventListener.context)!
JSObjectCallAsFunction(eventListener.context.jsGlobalContextRef, eventListener.jsValueRef, thisObject.jsValueRef, 0, nil, nil)
}
if let eventListeners = _eventListeners[event] {
eventListeners.forEach({ (eventListener, options) in
//eventListener.value.call(withArguments: [])
let listener = eventListener.value!
let thisObject = JSValue(object: self, in: listener.context)!
JSObjectCallAsFunction(listener.context.jsGlobalContextRef, listener.jsValueRef, thisObject.jsValueRef, 0, nil, nil)
})
while let removeIdx = eventListeners.index(where: { $0.options?.once == true }) {
removeEventListener(event, removeIdx)
}
}
return true
}
/*
private func invokeEventListener(_ eventListener: EventListener, arguments: [JSValue] = []) -> Any? {
//eventListener.value.call(withArguments: arguments)
let listener = eventListener.value!
let thisObject = JSValue(object: self, in: listener.context)!
JSObjectCallAsFunction(listener.context.jsGlobalContextRef, listener.jsValueRef, thisObject.jsValueRef, 0, nil, nil)
//let args = arguments.map { $0.jsValueRef }
let args = JSValue(object: arguments, in: listener.context)
let argsPtr: UnsafePointer<JSValueRef?> = (args != nil ? &(args!.jsValueRef) : nil)
JSObjectCallAsFunction(<#T##ctx: JSContextRef!##JSContextRef!#>, <#T##object: JSObjectRef!##JSObjectRef!#>, <#T##thisObject: JSObjectRef!##JSObjectRef!#>, <#T##argumentCount: Int##Int#>, <#T##arguments: UnsafePointer<JSValueRef?>!##UnsafePointer<JSValueRef?>!#>, <#T##exception: UnsafeMutablePointer<JSValueRef?>!##UnsafeMutablePointer<JSValueRef?>!#>)
let retVal = JSObjectCallAsFunction(<#T##ctx: JSContextRef!##JSContextRef!#>, <#T##object: JSObjectRef!##JSObjectRef!#>, <#T##thisObject: JSObjectRef!##JSObjectRef!#>, arguments.count, args?.jsValueRef, nil)
}
*/
}
//public typealias EventListener = () -> Void
//public typealias EventListener = (Event) -> Void
//public typealias EventListener = @convention(block) () -> Void
//public typealias EventListener = @convention(block) (Event) -> Void
public typealias EventListener = JSValue
//public typealias EventListener = JSManagedValue
public typealias EventListenerRef = JSManagedValue
@objc public protocol EventListenerOptions {
var capture: Bool { get set }
var once: Bool { get set }
var passive: Bool { get set }
}