diff --git a/src/core/drive/form_submission.ts b/src/core/drive/form_submission.ts index 56a1fc525..244461352 100644 --- a/src/core/drive/form_submission.ts +++ b/src/core/drive/form_submission.ts @@ -29,6 +29,11 @@ enum FormEnctype { plain = "text/plain", } +export type TurboSubmitStartEvent = CustomEvent<{ formSubmission: FormSubmission }> +export type TurboSubmitEndEvent = CustomEvent< + { formSubmission: FormSubmission } & { [K in keyof FormSubmissionResult]?: FormSubmissionResult[K] } +> + function formEnctypeFromString(encoding: string): FormEnctype { switch (encoding.toLowerCase()) { case FormEnctype.multipart: @@ -163,7 +168,7 @@ export class FormSubmission { requestStarted(_request: FetchRequest) { this.state = FormSubmissionState.waiting this.submitter?.setAttribute("disabled", "") - dispatch("turbo:submit-start", { + dispatch("turbo:submit-start", { target: this.formElement, detail: { formSubmission: this }, }) @@ -200,7 +205,7 @@ export class FormSubmission { requestFinished(_request: FetchRequest) { this.state = FormSubmissionState.stopped this.submitter?.removeAttribute("disabled") - dispatch("turbo:submit-end", { + dispatch("turbo:submit-end", { target: this.formElement, detail: { formSubmission: this, ...this.result }, }) diff --git a/src/core/frames/link_interceptor.ts b/src/core/frames/link_interceptor.ts index 53ff4b31b..65ff1066f 100644 --- a/src/core/frames/link_interceptor.ts +++ b/src/core/frames/link_interceptor.ts @@ -1,3 +1,5 @@ +import { TurboClickEvent, TurboBeforeVisitEvent } from "../session" + export interface LinkInterceptorDelegate { shouldInterceptLinkClick(element: Element, url: string): boolean linkClickIntercepted(element: Element, url: string): void @@ -33,7 +35,7 @@ export class LinkInterceptor { } } - linkClicked = ((event: CustomEvent) => { + linkClicked = ((event: TurboClickEvent) => { if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) { if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url)) { this.clickEvent.preventDefault() @@ -44,9 +46,9 @@ export class LinkInterceptor { delete this.clickEvent }) - willVisit = () => { + willVisit = ((_event: TurboBeforeVisitEvent) => { delete this.clickEvent - } + }) respondsToEventTarget(target: EventTarget | null) { const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null diff --git a/src/core/index.ts b/src/core/index.ts index f736483cf..24136d790 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -12,6 +12,21 @@ import { FormSubmission } from "./drive/form_submission" const session = new Session() const { navigator } = session export { navigator, session, PageRenderer, PageSnapshot, FrameRenderer } +export { + TurboBeforeCacheEvent, + TurboBeforeRenderEvent, + TurboBeforeVisitEvent, + TurboClickEvent, + TurboFrameLoadEvent, + TurboFrameRenderEvent, + TurboLoadEvent, + TurboRenderEvent, + TurboVisitEvent, +} from "./session" + +export { TurboSubmitStartEvent, TurboSubmitEndEvent } from "./drive/form_submission" +export { TurboBeforeFetchRequestEvent, TurboBeforeFetchResponseEvent } from "../http/fetch_request" +export { TurboBeforeStreamRenderEvent } from "../elements/stream_element" /** * Starts the main session. diff --git a/src/core/session.ts b/src/core/session.ts index 727019ba5..4b723577f 100644 --- a/src/core/session.ts +++ b/src/core/session.ts @@ -21,6 +21,15 @@ import { FetchResponse } from "../http/fetch_response" import { Preloader, PreloaderDelegate } from "./drive/preloader" export type TimingData = unknown +export type TurboBeforeCacheEvent = CustomEvent +export type TurboBeforeRenderEvent = CustomEvent<{ newBody: HTMLBodyElement; resume: (value: any) => void }> +export type TurboBeforeVisitEvent = CustomEvent<{ url: string }> +export type TurboClickEvent = CustomEvent<{ url: string; originalEvent: MouseEvent }> +export type TurboFrameLoadEvent = CustomEvent +export type TurboFrameRenderEvent = CustomEvent<{ fetchResponse: FetchResponse }> +export type TurboLoadEvent = CustomEvent<{ url: string; timing: TimingData }> +export type TurboRenderEvent = CustomEvent +export type TurboVisitEvent = CustomEvent<{ url: string; action: Action }> export class Session implements @@ -311,7 +320,7 @@ export class Session } notifyApplicationAfterClickingLinkToLocation(link: Element, location: URL, event: MouseEvent) { - return dispatch("turbo:click", { + return dispatch("turbo:click", { target: link, detail: { url: location.href, originalEvent: event }, cancelable: true, @@ -319,7 +328,7 @@ export class Session } notifyApplicationBeforeVisitingLocation(location: URL) { - return dispatch("turbo:before-visit", { + return dispatch("turbo:before-visit", { detail: { url: location.href }, cancelable: true, }) @@ -327,27 +336,27 @@ export class Session notifyApplicationAfterVisitingLocation(location: URL, action: Action) { markAsBusy(document.documentElement) - return dispatch("turbo:visit", { detail: { url: location.href, action } }) + return dispatch("turbo:visit", { detail: { url: location.href, action } }) } notifyApplicationBeforeCachingSnapshot() { - return dispatch("turbo:before-cache") + return dispatch("turbo:before-cache") } notifyApplicationBeforeRender(newBody: HTMLBodyElement, resume: (value: any) => void) { - return dispatch("turbo:before-render", { + return dispatch("turbo:before-render", { detail: { newBody, resume }, cancelable: true, }) } notifyApplicationAfterRender() { - return dispatch("turbo:render") + return dispatch("turbo:render") } notifyApplicationAfterPageLoad(timing: TimingData = {}) { clearBusyState(document.documentElement) - return dispatch("turbo:load", { + return dispatch("turbo:load", { detail: { url: this.location.href, timing }, }) } @@ -362,11 +371,11 @@ export class Session } notifyApplicationAfterFrameLoad(frame: FrameElement) { - return dispatch("turbo:frame-load", { target: frame }) + return dispatch("turbo:frame-load", { target: frame }) } notifyApplicationAfterFrameRender(fetchResponse: FetchResponse, frame: FrameElement) { - return dispatch("turbo:frame-render", { + return dispatch("turbo:frame-render", { detail: { fetchResponse }, target: frame, cancelable: true, diff --git a/src/elements/stream_element.ts b/src/elements/stream_element.ts index 8d3475ccf..4e803a3cf 100644 --- a/src/elements/stream_element.ts +++ b/src/elements/stream_element.ts @@ -1,6 +1,8 @@ import { StreamActions } from "../core/streams/stream_actions" import { nextAnimationFrame } from "../util" +export type TurboBeforeStreamRenderEvent = CustomEvent + //