Skip to content

Commit

Permalink
Fix data-turbo-confirm on <a> without data-turbo-method
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoroth committed Feb 16, 2023
1 parent e013072 commit b9bc188
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 13 deletions.
5 changes: 5 additions & 0 deletions src/core/confirmation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class Confirmation {
static confirmMethod(message: string, _element: Element, _submitter: Element | undefined): Promise<boolean> {
return Promise.resolve(confirm(message))
}
}
11 changes: 2 additions & 9 deletions src/core/drive/form_submission.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FetchRequest, FetchMethod, fetchMethodFromString } from "../../http/fetch_request"
import { FetchResponse } from "../../http/fetch_response"
import { Confirmation } from "../confirmation"
import { expandURL } from "../url"
import { dispatch, getAttribute, getMetaContent, hasAttribute } from "../../util"
import { StreamMessage } from "../streams/stream_message"
Expand Down Expand Up @@ -56,14 +57,6 @@ export class FormSubmission {
state = FormSubmissionState.initialized
result?: FormSubmissionResult

static confirmMethod(
message: string,
_element: HTMLFormElement,
_submitter: HTMLElement | undefined
): Promise<boolean> {
return Promise.resolve(confirm(message))
}

constructor(
delegate: FormSubmissionDelegate,
formElement: HTMLFormElement,
Expand Down Expand Up @@ -126,7 +119,7 @@ export class FormSubmission {
const confirmationMessage = getAttribute("data-turbo-confirm", this.submitter, this.formElement)

if (typeof confirmationMessage === "string") {
const answer = await FormSubmission.confirmMethod(confirmationMessage, this.formElement, this.submitter)
const answer = await Confirmation.confirmMethod(confirmationMessage, this.formElement, this.submitter)
if (!answer) {
return
}
Expand Down
6 changes: 3 additions & 3 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Adapter } from "./native/adapter"
import { FormMode, Session } from "./session"
import { Cache } from "./cache"
import { Confirmation } from "./confirmation"
import { Locatable } from "./url"
import { StreamMessage } from "./streams/stream_message"
import { StreamSource } from "./types"
import { VisitOptions } from "./drive/visit"
import { PageRenderer } from "./drive/page_renderer"
import { PageSnapshot } from "./drive/page_snapshot"
import { FrameRenderer } from "./frames/frame_renderer"
import { FormSubmission } from "./drive/form_submission"

const session = new Session()
const cache = new Cache(session)
Expand Down Expand Up @@ -125,9 +125,9 @@ export function setProgressBarDelay(delay: number) {
}

export function setConfirmMethod(
confirmMethod: (message: string, element: HTMLFormElement, submitter: HTMLElement | undefined) => Promise<boolean>
confirmMethod: (message: string, element: HTMLElement, submitter: HTMLElement | undefined) => Promise<boolean>
) {
FormSubmission.confirmMethod = confirmMethod
Confirmation.confirmMethod = confirmMethod
}

export function setFormMode(mode: FormMode) {
Expand Down
11 changes: 10 additions & 1 deletion src/core/session.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Adapter } from "./native/adapter"
import { BrowserAdapter, ReloadReason } from "./native/browser_adapter"
import { CacheObserver } from "../observers/cache_observer"
import { Confirmation } from "./confirmation"
import { FormSubmitObserver, FormSubmitObserverDelegate } from "../observers/form_submit_observer"
import { FrameRedirector } from "./frames/frame_redirector"
import { History, HistoryDelegate } from "./drive/history"
Expand Down Expand Up @@ -191,9 +192,17 @@ export class Session
)
}

followedLinkToLocation(link: Element, location: URL) {
async followedLinkToLocation(link: Element, location: URL) {
const action = this.getActionForLink(link)
const acceptsStreamResponse = link.hasAttribute("data-turbo-stream")
const confirmationMessage = link.getAttribute("data-turbo-confirm")

if (typeof confirmationMessage === "string") {
const answer = await Confirmation.confirmMethod(confirmationMessage, link, link)
if (!answer) {
return
}
}

this.visit(location.href, { action, acceptsStreamResponse })
}
Expand Down
25 changes: 25 additions & 0 deletions src/tests/functional/visit_tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,28 @@ test("test Visit with network error", async ({ page }) => {
async function visitLocation(page: Page, location: string) {
return page.evaluate((location) => window.Turbo.visit(location), location)
}

test("test data-turbo-confirm on anchor element without data-turbo-method", async ({ page }) => {
let confirmed = false

page.on("dialog", (alert) => {
assert.equal(alert.message(), "Are you sure?")
alert.accept()
confirmed = true
})

await page.evaluate(() => {
const link = document.querySelector<HTMLAnchorElement>("#same-origin-link")

if (link) link.dataset.turboConfirm = "Are you sure?"
})

assert.equal(await page.locator("#same-origin-link[data-turbo-confirm]:not([data-turbo-method])").count(), 1)
assert.equal(pathname(page.url()), "/src/tests/fixtures/visit.html")

await page.click("#same-origin-link")
await nextEventNamed(page, "turbo:load")

assert.isTrue(confirmed)
assert.equal(pathname(page.url()), "/src/tests/fixtures/one.html")
})

0 comments on commit b9bc188

Please sign in to comment.