Skip to content

Conversation

@yaisog
Copy link
Contributor

@yaisog yaisog commented Dec 28, 2025

This PR extends the $action-sendmessage widget to support passing and manipulating event properties, enabling better integration with $messagecatcher and more flexible event handling.

Currently, when using the MessageCatcherWidget to capture messages like tm-navigate, there's no straightforward way to fully forward those events with the ActionSendMessageWidget since it requires certain properties of the event object to be set, e.g. navigateTo, navigateFromTitle or (boolean) navigateSuppressNavigation. The MessageCatcherWidget converts all event properties to strings for the event-* variables, which loses type information.

This PR enables type-preserving event forwarding via JSON serialization. String properties may also be set using single-parameter attributes and / or filter expressions for multiple parameters (similar to the existing $names and $values attributes).

  • Overhaul documentation tiddlers
  • Switch to $tw.utils.copyObjectPropertiesSafe() for JSON generation

Changes

MessageCatcherWidget

  • Exports new json-message variable containing primitive message properties (string, boolean, number) as JSON
  • Preserves types unlike existing string-based event-* variables
  • Duplicates all event-* variables as message-* variables and deprecates the event-* versions

ActionSendMessageWidget

Added support for injecting properties into the dispatched params object:

  • $messageJSON: Accepts JSON-serialized event data, parsing and merging properties with preserved types

Priority order (later overwrites earlier):

  1. Default params (param, paramObject, event, tiddlerTitle, navigateFromTitle)
  2. Properties from $eventJson
  3. Properties from $eventNames/$eventValues
  4. Properties from $event-* attributes
  5. type from $message (if specified)

Usage Examples

Simple event forwarding with additional actions:

\procedure actions()
<!-- additional actions or possibly manipulation of the JSON variable json-event -->
<$action-sendmessage $eventJson=<<json-event>> />
\end

<$messagecatcher $tm-navigate="<<actions>>" >
<$button to="HelloThere" >CLICK</$button>
</$messagecatcher>

Resolves #7343
Resolves #6493

Extends the action-sendmessage widget to support passing event
properties to the dispatched message params object

New features:
- $event-* attributes: Add properties directly to params/event object
  (e.g., $event-type="tm-navigate" adds type: "tm-navigate" to params)
- $eventNames and $eventValues: Filter-based property assignment
  to params object (e.g., $eventNames="[enlist<list-event>]")

This enables action-sendmessage to forward event properties from
MessageCatcherWidget and other event sources while maintaining
backward compatibility with existing functionality.
Extends event handling to preserve types when forwarding events between
widgets by using JSON serialization.

MessageCatcherWidget changes:
- Exports new "json-event" variable containing the full event object
  as JSON, preserving boolean and number types

SendMessageWidget changes:
- Accepts new $eventJson attribute for JSON-serialized event data
- Parses JSON and merges properties into dispatched params object

This enables type-safe event forwarding while maintaining backward
compatibility and allowing flexible event manipulation.
@netlify
Copy link

netlify bot commented Dec 28, 2025

Deploy Preview for tiddlywiki-previews ready!

Name Link
🔨 Latest commit 40fb630
🔍 Latest deploy log https://app.netlify.com/projects/tiddlywiki-previews/deploys/69778f592cd6240008c15169
😎 Deploy Preview https://deploy-preview-9528--tiddlywiki-previews.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link

Confirmed: yaisog has already signed the Contributor License Agreement (see contributing.md)

@github-actions
Copy link

github-actions bot commented Dec 28, 2025

📊 Build Size Comparison: empty.html

Branch Size
Base (master) 2448.8 KB
PR 2451.8 KB

Diff: ⬆️ Increase: +3.0 KB


✅ Change Note Status

All change notes are properly formatted and validated!

📝 $:/changenotes/5.4.0/#9528

Type: enhancement | Category: widget
Release: 5.4.0

Add event parameter manipulation to ActionSendMessageWidget

🔗 #9528

👥 Contributors: yaisog


📖 Change Note Guidelines

Change notes help track and communicate changes effectively. See the full documentation for details.

@yaisog yaisog changed the title Extend ActionSendMessageWidget to parameterize the event object Add event parameter forwarding to ActionSendMessageWidget Dec 28, 2025
@yaisog yaisog changed the title Add event parameter forwarding to ActionSendMessageWidget Add event parameter manipulation to ActionSendMessageWidget Dec 28, 2025
@yaisog
Copy link
Contributor Author

yaisog commented Dec 28, 2025

I am not sure if the $event-* and $eventNames/$eventValues parameters are really that useful. It probably depends on the message type. Something like

<$action-sendmessage $eventNames="[enlist<list-event>]" $eventValues="[enlist<list-event>addprefix[event-]getvariable[]]" />

might not work as expected if there are boolean types involved, e.g. navigateSuppressNavigation. The MessageCatcherWidget would generate the variable event-navigateSuppressNavigation with string value false (or true). Passing this to the ActionSendMessageWidget would make this a string property which will not be properly handled. Such cases would be difficult to debug since the true nature of navigateSuppressNavigation cannot be determined within WikiText. At least with the JSON-serialized object, this is visible.

@Jermolene
Copy link
Member

Thanks @yaisog this is looking good. It would be helpful to document some of the common use cases (like forwarding a message).

@saqimtiaz
Copy link
Member

@yaisog this is a much needed improvement, thank you. I think we should drop the $event-* and $eventNames/$eventValues parameters for the reasons you outlined in favour of the JSON blob that we provide.

It is also very unfortunate that we have used the term "events" in conjunction with Widget Messages as that often leads to confusion with DOM events. We should take the opportunity in 5.4 to start deprecating parameters and variables to do with Widget messages that use the event or ev prefix in favour of a message prefix. $eventJSON would thus become $messageJSON.

Copy link
Contributor Author

@yaisog yaisog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @saqimtiaz, I thankfully removed the $event* attributes and also renamed the other to $messageJson (or should it be $messageJSON?).
I also amended the MessageCatcherWidget to set message-* and message-paramObject variables in addition to the current event variables, preparing for deprecation and later removal of the latter.

I think regarding messages there is not a lot else to clean up.

Next up I'll work over the documentation regarding MessageCatcherWidget and ActionSendMessageWidget to reflect the changes and maybe add some examples.

@saqimtiaz
Copy link
Member

I thankfully removed the $event* attributes and also renamed the other to $messageJson (or should it be $messageJSON?).

messageJSON would be preferrable, thank you.

@yaisog
Copy link
Contributor Author

yaisog commented Jan 8, 2026

I pushed an update that implements quite comprehensive documentation tiddlers for ActionSendMessageWidget and MessageCatcherWidget that should satisfy @Jermolene.

Note that I also took the opportunity to switch the hierarchy between [[Messages]] and [[Core Messages]], so that the latter is now a direct descendant of the former, not vice versa. This made it necessary to update the tags on all tm-* doc tiddlers, hence the large number of changed files.

@yaisog yaisog marked this pull request as ready for review January 8, 2026 18:32
@saqimtiaz
Copy link
Member

@yaisog the plan for v5.4.0 is to also introduce a similar JSON blob to provide by the eventcatcher widget. The PR is still a draft and needs a few small changes. I am wondering if the code that copies the object so it can be safely strinfigied could be reused here, or if we could refactor to allow the same code to be usable in both places.

@yaisog
Copy link
Contributor Author

yaisog commented Jan 9, 2026

Hi @saqimtiaz, that's a good idea to reuse that code. From a first look I'd say it should be usable as is. It does have a few more safeguards than we will probably need here, but that shouldn't hurt.
I'll try to integrate it later (which will probably lead to merge conflict in utils.js?)

@yaisog
Copy link
Contributor Author

yaisog commented Jan 9, 2026

Hi @saqimtiaz, I had a closer look and I don't think it'll work.

  • copyObjectPropertiesSafe() returns the event object with all its properties, which is not relevant for message handling.
  • It also recurses into widget objects. These are attached to messages, but probably not to events. But you still might want to take care of them. I used the condition obj.parseTreeNode !== undefined && obj.constructor !== Object to check for these.
  • It returns (or would return) a bunch of "[Widget]" or "[DOM element]" properties, which I think is confusing and of no purpose to message handling.
  • The circular reference check is unnecessary when I omit widgets and DOM elements and the only object is the paramObject.

I'd have to add a parameter to copyObjectPropertiesSafe() to switch it into a different mode that mostly copies the code that is now in messagecatcher.js and calls that when the parameter is set. Not sure if that makes sense.
If we ever need it in another situation, we could still move my code to a new utils function.

Let me know your thoughts on this.

@saqimtiaz
Copy link
Member

@yaisog there might be room to standardize on an implementation for both widgets that when copying the object properties, entirely skips DOM elements, Widgets and circular references instead of reporting them as strings, as these would not be of value in either scenario.

@yaisog
Copy link
Contributor Author

yaisog commented Jan 12, 2026

Hi @saqimtiaz, I'll happily take a look. How should we handle the event object, which is not relevant for the $messagecatcher? We could have a function parameter like skipEvent to omit that for messages. That doesn't make it too messy, I think.

@saqimtiaz
Copy link
Member

@yaisog do you mean event.event in widget messages? I think something along the lines of adding an options object as an argument to the method, which has a property except which is an array of property names to skip copying might be the way to go.

… conversion

This commit uses the $tw.utils.copyObjectPropertiesSafe function from PR TiddlyWiki#8919 to gather the properties from the message event object before converting them to JSON.
This ensures that only safe and relevant properties are included in the JSON representation, avoiding potential issues with circular references or unwanted data.
The function was modified to silently skip DOM elements, widgets or unserializable properties and extended with an exception list to allow specific properties to also be skipped.
@yaisog
Copy link
Contributor Author

yaisog commented Jan 13, 2026

@yaisog do you mean event.event in widget messages?

Yes, exactly that.

I took your copyObjectPropertiesSafe method and implemented it here. Instead of outputting the unusable elements as "[Reason]", they are now skipped silently.
I also added an options object with an excludeProperties property. This takes an array of property paths to exclude from the output. In the MessageCatcherWidget case, this would just be

$tw.utils.copyObjectPropertiesSafe(event,{excludeProperties: ["event"]})

to remove event.event, but in principle you could also exclude any sub-property like ["event","navigateFromClientRect.height"]. Only properties matching the full path are removed.

Let me know if that works for your EventCatcherWidget implementation or if we should fine-tune.

@saqimtiaz
Copy link
Member

@yaisog at first glance I think that looks good. Perhaps just add a short comment block before the new utils method explaining the structure of the optional options object.

If there are any minor adjustments required to this method, I can work on them when I get the chance to pick up the work on the eventcatcher PR. We should take this opportunity to standardize as much as we can in terms of how both catcher widgets provide variables to the actions they invoke.

@yaisog
Copy link
Contributor Author

yaisog commented Jan 13, 2026

We should take this opportunity to standardize as much as we can in terms of how both catcher widgets provide variables to the actions they invoke.

I agree 100%.

I will add a comment block above the method with a short explanation.

@saqimtiaz
Copy link
Member

@yaisog having given this some further thought, I do not think we should be excluding the browser DOM event that initiated the message (event.event) from the JSON payload that we provide.

The folllowing properties can potentially be useful in $messagecatcher:

  • clientX / clientY
  • screenX / screenY
  • pageX / pageY
  • event.detail

@yaisog
Copy link
Contributor Author

yaisog commented Jan 26, 2026

Hi @saqimtiaz, just getting back to this. I see your point. But if we want to leave these in, we have to leave the whole event.event object in - unless you want to individually exclude all the 30 or so properties that might not be needed. Then this would add a bit of "noise" to the parameters list. However, it might still be better than to have to fix this later because someone needs a property that we don't provide.

In that case I can remove the exclude list from the copyObjectPropertiesSafe method again, since event was the only excluded property. Or do you want to leave it in, just to be more flexible down the road?

@saqimtiaz
Copy link
Member

Hi @yaisog I think it makes sense to provide access to the stringified version of the event object in messagecatcher, and the version of copyObjectPropertiesSafe in #9609 should work from you, apart from perhaps needing to exclude widget instances.

However, I am less sure about the changes to action-sendmessage. Indeed copying over anything from the stringified event object would make no sense here, and it might almost be more sensible to use the original event object (event.event).

I don't have the time to look at this carefully at the moment, but I am concerned that re-emitting a caught message needs to behave exactly the same as the original message if we can help it. One alternative here is a passthrough option on the messagecatcher widget, where it invokes actions and allows the original message to propagate. One can imagine a widget message whose handling also requires access to the original event object, and we should be able to catch and re-emit it.

@yaisog
Copy link
Contributor Author

yaisog commented Jan 26, 2026

Hi @saqimtiaz,

the version of copyObjectPropertiesSafe in #9609 should work from you, apart from perhaps needing to exclude widget instances

OK, I'll have a look when that is merged and then remove that file from the PR.

One alternative here is a passthrough option on the messagecatcher widget, where it invokes actions and allows the original message to propagate.

I did propose that back in #6493. However, @Jermolene favored extending the ´<$action-sendmessage>widget instead. Personally, I'd be fine with a MessageCatcherWidget that knowsstopPropagation=never`, and that's what I use in my wikis. I have not felt the need for anything beyond that so far.

One can imagine a widget message whose handling also requires access to the original event object, and we should be able to catch and re-emit it.

Can you name any message that uses the event.event values at all? I didn't find any. Passing the original event object along, with widgets and everything in it, would be even more rare. That's not even needed for tm-navigate which is the one message that is most difficult to pass along at the moment.
And even if the MessageCatcherWidget were to not pass event.event on, the ActionSendMessageWidget could still emit it by inserting respective properties into the JSON.

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.

[IDEA] Extend $action-sendmessage to be able to set properties on the event object [IDEA] Ability to propagate caught tm-navigate messages

3 participants