Skip to content

Commit

Permalink
Move defaultEventNames into Schema
Browse files Browse the repository at this point in the history
This allows applications to extend the mapping with support for custom
elements.

Closes hotwired#660
  • Loading branch information
grncdr committed Feb 17, 2023
1 parent f7bfc35 commit 83e84b7
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 19 deletions.
21 changes: 2 additions & 19 deletions src/core/action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ActionDescriptor, parseActionDescriptorString, stringifyEventTarget } from "./action_descriptor"
import { Token } from "../mutation-observers"
import { Schema } from "./schema"
import { getDefaultEventNameForElement, Schema } from "./schema"
import { camelize } from "./string_helpers"
import { hasProperty } from "./utils"

Expand All @@ -23,7 +23,7 @@ export class Action {
this.element = element
this.index = index
this.eventTarget = descriptor.eventTarget || element
this.eventName = descriptor.eventName || getDefaultEventNameForElement(element) || error("missing event name")
this.eventName = descriptor.eventName || getDefaultEventNameForElement(element, schema) || error("missing event name")
this.eventOptions = descriptor.eventOptions || {}
this.identifier = descriptor.identifier || error("missing identifier")
this.methodName = descriptor.methodName || error("missing method name")
Expand Down Expand Up @@ -86,23 +86,6 @@ export class Action {
}
}

const defaultEventNames: { [tagName: string]: (element: Element) => string } = {
a: () => "click",
button: () => "click",
form: () => "submit",
details: () => "toggle",
input: (e) => (e.getAttribute("type") == "submit" ? "click" : "input"),
select: () => "change",
textarea: () => "input",
}

export function getDefaultEventNameForElement(element: Element): string | undefined {
const tagName = element.tagName.toLowerCase()
if (tagName in defaultEventNames) {
return defaultEventNames[tagName](element)
}
}

function error(message: string): never {
throw new Error(message)
}
Expand Down
17 changes: 17 additions & 0 deletions src/core/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface Schema {
targetAttributeForScope(identifier: string): string
outletAttributeForScope(identifier: string, outlet: string): string
keyMappings: { [key: string]: string }
defaultEventNames: { [tagName: string]: (element: Element) => string }
}

export const defaultSchema: Schema = {
Expand All @@ -29,6 +30,22 @@ export const defaultSchema: Schema = {
// [0-9]
...objectFromEntries("0123456789".split("").map((n) => [n, n])),
},
defaultEventNames: {
a: () => "click",
button: () => "click",
form: () => "submit",
details: () => "toggle",
input: (e) => (e.getAttribute("type") == "submit" ? "click" : "input"),
select: () => "change",
textarea: () => "input",
}
}

export function getDefaultEventNameForElement(element: Element, schema = defaultSchema): string | undefined {
const tagName = element.tagName.toLowerCase()
if (tagName in schema.defaultEventNames) {
return schema.defaultEventNames[tagName](element)
}
}

function objectFromEntries(array: [string, any][]): object {
Expand Down
20 changes: 20 additions & 0 deletions src/tests/modules/core/action_custom_default_event_tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { TestApplication } from "../../cases/application_test_case"
import { LogControllerTestCase } from "../../cases/log_controller_test_case"
import { Schema, defaultSchema } from "../../../core/schema"
import { Application } from "../../../core/application"

export default class ActionKeyboardFilterTests extends LogControllerTestCase {
schema: Schema = {
...defaultSchema,
defaultEventNames: { ...defaultSchema.defaultEventNames, "some-element": () => "click" },
}
application: Application = new TestApplication(this.fixtureElement, this.schema)

identifier = "c"
fixtureHTML = `<some-element data-controller="c" data-action="c#log"></some-element>`

async "test default event"() {
await this.triggerEvent("some-element", "click")
this.assertActions({ name: "log", eventType: "click" })
}
}

0 comments on commit 83e84b7

Please sign in to comment.