Skip to content

Generalize js_handler with Auto-Return-Value-Intercept (ARVI) #4759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

evnchn
Copy link
Collaborator

@evnchn evnchn commented May 16, 2025

This PR should end the saga of PR #4689, PR #4618, while addressing 5 issue / discussions / feature request (#3762, #4611, #4606, #4577, and #4589) as stated in #4618 (comment)

Background

The crux of the issue is, we want to be able to return custom values which are only possible to be extracted via JavaScript and/or too deep in nested property which args does not handle. Stuff gets pretty complex and case-by-case, so read up those 7 referenced items above!

Established Requirements

We debated a long time over the API design, and we needed the following requirements:

  • Avoid adding extra parameters whenever possible
    • Option js_transform = "(e) => e.offsetY" was eliminated
  • JavaScript transformations should be as easy to add as "(e) => e.offsetY"
    • Option js_handler = "(e) => {defaultHandler(e.offsetY)}" was eliminated
  • Must be as clear and minimize confusion
    • Option "shoehorning args", as well as all other above options, were eliminated

This PR illustrates the idea at #4689 (comment) to comply with all of the aforementioned requirements.

  • Avoid adding extra parameters whenever possible
    • Yes
  • JavaScript transformations should be as easy to add as "(e) => e.offsetY"
    • js_handler = "(e) => e.offsetY"
  • Must be as clear and minimize confusion
    • I think so???

Logic behind this PR

The keyword is ARVI, which stands for Auto-Return-Value-Intercept. It means we intercept the js_handler's return value, if and only if Python-side handler is attached.

As a recap from #4689 (comment):

  • .on('blah', handler=python_handler, js_handler='(e) => e.event.button')
    • Since we pass both handler and js_handler, we now do care about the return value, and if there is a return value, we pass to defaultHandler right away.
  • .on('blah', js_handler='(e) => e.event.button')
    • Old behaviour. js_handler doesn't care about return value.
  • .on('blah', handler=python_handler)
    • Old behaviour 🙄

Notable implementation details

  • args and js_handler remain mutally exclusive.
    • Makes no sense otherwise. You wanna filter twice?
  • Logic check if (event.js_handler) { changed safely to if (!event.handler) {
    • Because no handler + code is even executed => js_handler must be present
    • Since we have a if handler or js_handler: on Python-side

Remaining to-do

@evnchn evnchn requested a review from falkoschindler May 16, 2025 22:06
@evnchn
Copy link
Collaborator Author

evnchn commented May 16, 2025

So we said here #4689

imagine setting a flag JS_TRANSFORMATION = True somewhere, marking that we now suddenly do care about the return value

Actually that flag is implemented here.

'handler': self.handler is not None,

With event.handler == true, the JS side, instead of handler = eval(event.js_handler);, will processed_args = [JSON.stringify(eval(event.js_handler)(...args))]; instead.

Note that processed_args is a list of JSON-strings, so we match the original format.

@evnchn
Copy link
Collaborator Author

evnchn commented May 17, 2025

Closing this to further encourage converging on #4689 (comment)

Branch not immediately deleted just in case.

@evnchn evnchn closed this May 17, 2025
@evnchn evnchn deleted the jshandler-AND-handler branch May 26, 2025 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant