diff options
Diffstat (limited to 'src/html')
-rw-r--r-- | src/html/dom.nim | 19 | ||||
-rw-r--r-- | src/html/event.nim | 44 | ||||
-rw-r--r-- | src/html/xmlhttprequest.nim | 15 |
3 files changed, 55 insertions, 23 deletions
diff --git a/src/html/dom.nim b/src/html/dom.nim index bb2c4982..90a2e164 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -2819,6 +2819,12 @@ proc blur(ctx: JSContext; element: Element) {.jsfunc.} = if element.document.focus == element: element.document.setFocus(nil) +proc click(ctx: JSContext; element: Element) {.jsfunc.} = + #TODO should also trigger click on inputs. + let event = newEvent(satClick.toAtom(), element, bubbles = true, + cancelable = true) + discard ctx.dispatch(element, event) + proc scrollTo(element: Element) {.jsfunc.} = discard #TODO maybe in app mode? @@ -2851,9 +2857,10 @@ func findAutoFocus*(document: Document): Element = proc fireEvent*(window: Window; event: Event; target: EventTarget) = discard window.jsctx.dispatch(target, event) -proc fireEvent*(window: Window; name: StaticAtom; target: EventTarget) = - let event = newEvent(name.toAtom(), target) - event.isTrusted = true +proc fireEvent*(window: Window; name: StaticAtom; target: EventTarget; + bubbles, cancelable, trusted: bool) = + let event = newEvent(name.toAtom(), target, bubbles, cancelable) + event.isTrusted = trusted window.fireEvent(event, target) proc parseColor(element: Element; s: string): ARGBColor = @@ -4357,7 +4364,8 @@ proc loadResource*(window: Window; image: HTMLImageElement) = image.invalidate() #TODO fire error on error if window.settings.scripting != smFalse: - window.fireEvent(satLoad, image) + window.fireEvent(satLoad, image, bubbles = false, + cancelable = false, trusted = true) ) ) window.pendingResources.add(p) @@ -5803,7 +5811,8 @@ proc createEvent(ctx: JSContext; document: Document; atom: CAtom): of satCustomevent: return ok(ctx.newCustomEvent(satUempty.toAtom())) of satEvent, satEvents, satSvgevents: - return ok(newEvent(satUempty.toAtom(), nil)) + return ok(newEvent(satUempty.toAtom(), nil, + bubbles = false, cancelable = false)) of satUievent, satUievents: return ok(newUIEvent(satUempty.toAtom())) else: diff --git a/src/html/event.nim b/src/html/event.nim index 132ea926..7a4d030d 100644 --- a/src/html/event.nim +++ b/src/html/event.nim @@ -37,10 +37,10 @@ type eventPhase {.jsget.}: uint16 bubbles {.jsget.}: bool cancelable {.jsget.}: bool - #TODO DOMHighResTimeStamp? - timeStamp {.jsget.}: float64 flags*: set[EventFlag] isTrusted* {.jsufget.}: bool + #TODO DOMHighResTimeStamp? + timeStamp {.jsget.}: float64 CustomEvent* = ref object of Event detail {.jsget.}: JSValue @@ -131,11 +131,14 @@ proc newEvent(ctx: JSContext; ctype: CAtom; eventInitDict = EventInit()): event.innerEventCreationSteps(eventInitDict) return event -proc newEvent*(ctype: CAtom; target: EventTarget): Event = +proc newEvent*(ctype: CAtom; target: EventTarget; bubbles, cancelable: bool): + Event = return Event( ctype: ctype, target: target, - currentTarget: target + currentTarget: target, + bubbles: bubbles, + cancelable: cancelable ) proc initialize(this: Event; ctype: CAtom; bubbles, cancelable: bool) = @@ -352,8 +355,7 @@ proc invoke(ctx: JSContext; listener: EventListener; event: Event): JSValue = # Apparently it's a bad idea to call a function that can then delete # the reference it was called from. let callback = JS_DupValue(ctx, listener.callback) - let ret = JS_Call(ctx, callback, jsTarget, 1, - jsEvent.toJSValueArray()) + let ret = JS_Call(ctx, callback, jsTarget, 1, jsEvent.toJSValueArray()) JS_FreeValue(ctx, callback) JS_FreeValue(ctx, jsTarget) JS_FreeValue(ctx, jsEvent) @@ -517,13 +519,13 @@ proc hasEventListener*(eventTarget: EventTarget; ctype: CAtom): bool = return false proc dispatchEvent0(ctx: JSContext; event: Event; currentTarget: EventTarget; - stop, canceled: var bool) = + stop, canceled: var bool; capture: bool) = event.currentTarget = currentTarget var els = currentTarget.eventListeners # copy intentionally for el in els: if JS_IsUndefined(el.callback): continue # removed, presumably by a previous handler - if el.ctype == event.ctype: + if el.ctype == event.ctype and el.capture == capture: let e = ctx.invoke(el, event) if JS_IsException(e): ctx.logException() @@ -536,15 +538,31 @@ proc dispatchEvent0(ctx: JSContext; event: Event; currentTarget: EventTarget; break proc dispatch*(ctx: JSContext; target: EventTarget; event: Event): bool = - #TODO this is far from being compliant var canceled = false var stop = false event.flags.incl(efDispatch) event.target = target - var target = target - while target != nil and not stop: - ctx.dispatchEvent0(event, target, stop, canceled) - target = ctx.getParentImpl(target, event) + var it = target + var targets: seq[EventTarget] = @[] + while it != nil: + targets.add(it) + it = ctx.getParentImpl(it, event) + event.eventPhase = 1 + for i in countdown(targets.high, 1): + if stop: + break + let it = targets[i] + ctx.dispatchEvent0(event, it, stop, canceled, capture = true) + event.eventPhase = 2 + ctx.dispatchEvent0(event, target, stop, canceled, capture = true) + ctx.dispatchEvent0(event, target, stop, canceled, capture = false) + if event.bubbles: + event.eventPhase = 3 + for target in targets: + if stop: + break + ctx.dispatchEvent0(event, target, stop, canceled, capture = false) + event.eventPhase = 0 event.flags.excl(efDispatch) return canceled diff --git a/src/html/xmlhttprequest.nim b/src/html/xmlhttprequest.nim index 47a6bef9..1879bb29 100644 --- a/src/html/xmlhttprequest.nim +++ b/src/html/xmlhttprequest.nim @@ -118,6 +118,10 @@ proc parseMethod(s: string): DOMResult[HttpMethod] = else: errDOMException("Invalid method", "SyntaxError") +proc fireReadyStateChangeEvent(window: Window; target: EventTarget) = + window.fireEvent(satReadystatechange, target, bubbles = false, + cancelable = false, trusted = true) + proc open(ctx: JSContext; this: XMLHttpRequest; httpMethod, url: string; misc: varargs[JSValueConst]): Err[DOMException] {.jsfunc.} = let httpMethod = ?parseMethod(httpMethod) @@ -156,7 +160,7 @@ proc open(ctx: JSContext; this: XMLHttpRequest; httpMethod, url: string; #TODO response object, received bytes if this.readyState != xhrsOpened: this.readyState = xhrsOpened - global.fireEvent(satReadystatechange, this) + global.fireReadyStateChangeEvent(this) return ok() proc checkOpened(this: XMLHttpRequest): DOMResult[void] = @@ -207,6 +211,7 @@ proc fireProgressEvent(window: Window; target: EventTarget; name: StaticAtom; total: length, lengthComputable: length != 0 )) + event.isTrusted = true window.fireEvent(event, target) proc errorSteps(window: Window; this: XMLHttpRequest; name: StaticAtom) = @@ -214,7 +219,7 @@ proc errorSteps(window: Window; this: XMLHttpRequest; name: StaticAtom) = this.response = makeNetworkError() this.flags.excl(xhrfSend) if xhrfSync notin this.flags: - window.fireEvent(satReadystatechange, this) + window.fireReadyStateChangeEvent(this) if xhrfUploadComplete notin this.flags: this.flags.incl(xhrfUploadComplete) if xhrfUploadListener in this.flags: @@ -260,7 +265,7 @@ proc onReadXHR(response: Response) = this.received.setLen(olen + n) if this.readyState == xhrsHeadersReceived: this.readyState = xhrsLoading - window.fireEvent(satReadystatechange, this) + window.fireReadyStateChangeEvent(this) window.fireProgressEvent(this, satProgress, int64(this.received.len), opaque.len) @@ -275,7 +280,7 @@ proc onFinishXHR(response: Response; success: bool) = window.fireProgressEvent(this, satProgress, recvLen, opaque.len) this.readyState = xhrsDone this.flags.excl(xhrfSend) - window.fireEvent(satReadystatechange, this) + window.fireReadyStateChangeEvent(this) window.fireProgressEvent(this, satLoad, recvLen, opaque.len) window.fireProgressEvent(this, satLoadend, recvLen, opaque.len) else: @@ -348,7 +353,7 @@ proc send(ctx: JSContext; this: XMLHttpRequest; body: JSValueConst = JS_NULL): let response = res.get this.response = response this.readyState = xhrsHeadersReceived - window.fireEvent(satReadystatechange, this) + window.fireReadyStateChangeEvent(this) if this.readyState != xhrsHeadersReceived: return let len = max(response.getContentLength(), 0) |