Skip to content

Commit

Permalink
Pass controller instance to registerActionOption callback (#691)
Browse files Browse the repository at this point in the history
Add ability for registerActionOption callbacks to receive the controller instance

Resolves #668
  • Loading branch information
lb- committed Jul 12, 2023
1 parent c989795 commit da8be68
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 7 deletions.
13 changes: 7 additions & 6 deletions docs/reference/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,13 @@ route the event to the controller action, return `true`.

The callback accepts a single object argument with the following keys:

| Name | Description |
| ------- | ----------------------------------------------------------------------------------------------------- |
| name | String: The option's name (`"open"` in the example above) |
| value | Boolean: The value of the option (`:open` would yield `true`, `:!open` would yield `false`) |
| event | [Event][]: The event instance, including with the `params` action parameters on the submitter element |
| element | [Element]: The element where the action descriptor is declared |
| Name | Description |
| ---------- | ----------------------------------------------------------------------------------------------------- |
| name | String: The option's name (`"open"` in the example above) |
| value | Boolean: The value of the option (`:open` would yield `true`, `:!open` would yield `false`) |
| event | [Event][]: The event instance, including with the `params` action parameters on the submitter element |
| element | [Element]: The element where the action descriptor is declared |
| controller | The `Controller` instance which would receive the method call |

[toggle]: https://developer.mozilla.org/en-US/docs/Web/API/HTMLDetailsElement/toggle_event
[Event]: https://developer.mozilla.org/en-US/docs/web/api/event
Expand Down
3 changes: 3 additions & 0 deletions src/core/action_descriptor.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import type { Controller } from "./controller"

export type ActionDescriptorFilters = Record<string, ActionDescriptorFilter>
export type ActionDescriptorFilter = (options: ActionDescriptorFilterOptions) => boolean
type ActionDescriptorFilterOptions = {
name: string
value: boolean
event: Event
element: Element
controller: Controller<Element>
}

export const defaultActionDescriptorFilters: ActionDescriptorFilters = {
Expand Down
3 changes: 2 additions & 1 deletion src/core/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,15 @@ export class Binding {
private applyEventModifiers(event: Event): boolean {
const { element } = this.action
const { actionDescriptorFilters } = this.context.application
const { controller } = this.context

let passes = true

for (const [name, value] of Object.entries(this.eventOptions)) {
if (name in actionDescriptorFilters) {
const filter = actionDescriptorFilters[name]

passes = passes && filter({ name, value, event, element })
passes = passes && filter({ name, value, event, element, controller })
} else {
continue
}
Expand Down
42 changes: 42 additions & 0 deletions src/tests/modules/core/event_options_tests.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Controller } from "src/core"
import { LogControllerTestCase } from "../../cases/log_controller_test_case"

export default class EventOptionsTests extends LogControllerTestCase {
Expand Down Expand Up @@ -177,6 +178,47 @@ export default class EventOptionsTests extends LogControllerTestCase {
this.assertNoActions()
}

async "test custom action option callback params contain the controller instance"() {
let lastActionOptions: { controller?: Controller<Element> } = {}

const mockCallback = (options: Object) => {
lastActionOptions = options
}

this.application.registerActionOption("all", (options: Object) => {
mockCallback(options)
return true
})

await this.setAction(this.buttonElement, "click->c#log:all")

await this.triggerEvent(this.buttonElement, "click")

this.assertActions({ name: "log", identifier: "c", eventType: "click", currentTarget: this.buttonElement })

this.assert.deepEqual(["name", "value", "event", "element", "controller"], Object.keys(lastActionOptions))

this.assert.equal(
lastActionOptions.controller,
this.application.getControllerForElementAndIdentifier(this.element, "c")
)

this.controllerConstructor.actionLog = [] // clear actions

await this.setAction(this.buttonElement, "click->d#log:all")

await this.triggerEvent(this.buttonElement, "click")

this.assertActions({ name: "log", identifier: "d", eventType: "click", currentTarget: this.buttonElement })

this.assert.deepEqual(["name", "value", "event", "element", "controller"], Object.keys(lastActionOptions))

this.assert.equal(
lastActionOptions.controller,
this.application.getControllerForElementAndIdentifier(this.element, "d")
)
}

async "test custom option"() {
this.application.registerActionOption("open", ({ value, event: { type, target } }) => {
switch (type) {
Expand Down

0 comments on commit da8be68

Please sign in to comment.