- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
So part of this issue is about having a linting rule put in place to ensure that new code added to Drupal does not implement jQuery's .trigger method AND the same rule provides a nice checklist of all the places where Drupal core is currently implementing that method. That's a good piece of foundational / platform support for ensuring we're reducing our jQuery footprint.
It's also part of, but not all of, the main goal here. The main goal is to actually reduce jQuery's footprint by removing all the instances of the method. Once that's done, we can close the door on adding new code that uses that part of jQuery. Then we're done.
In my opinion, we are currently unblocked from making progress in that area. So i'm going to hack on this idea a bit.
- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
Current output of yarn lint:core-js-passing when the jquery/no-trigger rule is enabled:
/var/www/html/web/core/misc/ajax.js 584:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger 585:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger 587:17 error Prefer dispatchEvent to $.trigger jquery/no-trigger 744:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 1101:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/details.js 21:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/dialog/dialog.ajax.js 38:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger 42:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 102:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger 102:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger 102:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/dialog/dialog.jquery-ui.js 72:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/dialog/dialog.js 73:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 76:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 80:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 84:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/dialog/dialog.position.js 125:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/dialog/off-canvas/js/off-canvas.js 142:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 244:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/displace.js 222:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/form.js 147:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger 292:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 298:24 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/machine-name.js 190:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/states.js 735:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 746:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/tabbingmanager.js 181:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 248:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 367:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger 382:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger 396:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/tabledrag.js 395:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger 610:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 665:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 735:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/tableresponsive.js 49:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger 186:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/tableselect.js 64:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 86:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/misc/vertical-tabs.js 173:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/contextual/js/contextual.js 135:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/editor/js/editor.admin.js 30:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 46:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 65:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/editor/js/editor.dialog.js 32:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/editor/js/editor.js 305:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/field_ui/field_ui.js 50:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger 63:15 error Prefer dispatchEvent to $.trigger jquery/no-trigger 338:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/file/file.js 198:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 214:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 278:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/filter/filter.js 28:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/media_library/js/media_library.click_to_select.js 29:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/media_library/js/media_library.ui.js 65:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 336:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger 373:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/media_library/js/media_library.view.js 30:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/menu_ui/menu_ui.js 80:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger 81:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger 90:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/node/node.preview.js 97:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/settings_tray/js/settings_tray.js 36:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger 43:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger 100:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 209:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 209:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/system/js/system.date.js 60:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/system/js/system.js 79:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/text/text.js 68:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/toolbar/js/toolbar.js 177:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 180:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger 183:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/toolbar/tests/src/Nightwatch/Tests/toolbarTest.js 241:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 254:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 304:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 308:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/tour/js/tour.js 39:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/views_ui/js/ajax.js 108:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 177:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/views_ui/js/dialog.views.js 54:11 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/modules/views_ui/js/views-admin.js 480:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 581:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 622:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 1180:7 error Prefer dispatchEvent to $.trigger jquery/no-trigger 1246:9 error Prefer dispatchEvent to $.trigger jquery/no-trigger 1259:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/tests/Drupal/Nightwatch/Tests/tabbableShimTest.js 180:22 error Prefer dispatchEvent to $.trigger jquery/no-trigger 180:22 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/themes/claro/js/details.js 24:13 error Prefer dispatchEvent to $.trigger jquery/no-trigger /var/www/html/web/core/themes/claro/js/nav-tabs.js 71:5 error Prefer dispatchEvent to $.trigger jquery/no-trigger
- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
To fix, this guidance from stack overflow seems important: https://stackoverflow.com/questions/5658849/whats-the-equivalent-of-jque...
In this article, they (as as the linting error response) recommend using JavaScript's dispatchEvent method on the targeted element. What the stack overflow article mentions is that we can avoid potential problems by being thoughtful about what kind of Event we dispatch. Considering the careful creation and use of JavaScript Events, we are likely to discover that each use of .trigger('specific_event') has a sensible default replacement.
Let's create a list of all the different kinds of events we're currently triggering and figure out a
dispatchEvent
equivalent. - πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
Found .triggers (excluding 3rd party js)
- focus
- formUpdated.machineName
- ajaxSuccess
- ajaxComplete
- ajaxStop
- summaryUpdated
- click
- mousedown
- mouseup
- dialog:beforecreate
- dialog:aftercreate
- dialog:beforeclose
- dialog:afterclose
- dialogContentResize
- resize.dialogResize
- resize.off-canvas
- dialogContentResize.off-canvas
- drupalViewportOffsetChange
- summaryUpdated
- formUpdated
- formFragmentLinkClickOrHashChange
- change
- drupalTabbingConstrained
- DrupalTabbingContextReleased
- DrupalTabbingContextActivated
- DrupalTabbingContextDeactivated
- blur
- drupalEditorFeatureAdded
- drupalEditorFeatureRemoved
- drupalEditorFeatureModified
- editor:dialogsave
- fileUpload
- change.filterGuidelines
- submit
- resize.tabs
A lot of these seem to be custom events. jQuery enumerates it's events as:
- blur
- change
- click
- contextmenu
- dblclick
- error
- focus
- hover
- keydown
- keypress
- keyup
- load
- mousedown
- mouseenter
- mouseleave
- mousemove
- mouseout
- mouseover
- mouseoff
- mouseup
- resize
- scroll
- select
- submit
- unload
- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
When we use jQuery's list of events to reduce our list of found usages of .trigger we can reduce the list to:
- custom events we create
- focus
- click
- mousedown
- mouseup
- change
- blur
- submit
- resize?
Tricky bit might come into play when we need to stop using .trigger for jQuery events that we are overriding / extending. Best place to see what I mean here is to look at ajaxSuccess (all the ajax* "Events")
from ajax.es6.js, line 1768
$.extend(true, $.event.special, { ajaxSuccess: { trigger(event, xhr, settings) { if (stopEvent(xhr, settings)) { return false; } }, }, ajaxComplete: { trigger(event, xhr, settings) { if (stopEvent(xhr, settings)) { // jQuery decrements its internal active ajax counter even when we // stop the ajaxComplete event, but we don't want that counter // decremented, because for our purposes this request is still active // while commands are executing. By incrementing it here, the net // effect is that it remains unchanged. By remaining above 0, the // ajaxStop event is also prevented. $.active++; return false; } }, }, });
- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
Scanning core for all instances of $.extend returns > 50 files. Perhaps that's not a good search at the moment. Maybe we should take a stab at fixing these "easy" replacements and see how much is left aftwards.
To that end, how can we map the current "easy" uses .trigger to non-jquery solutions. In order to understand better how to provide developers a good replacement for what they currently have available with jQuery's event system let's focus on Focus.
Possible deprecation code comment / guidance we could provide
.trigger('focus') => .dispatchEvent(new FocusEvent('focus'))
Using an event object instead of doing something like $element.focus() allows the event system to properly bubble / propagate the event through the system.
When we use an Event object, JavaScript's event dispatcher triggers the event, allows any event handlers to do their actions, and when they're all done, finally focuses on the targeted element.
When .focus() is used, the targeted element immediately receives focus then the event handlers get notified of the event and they do their actions.
- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
More research also uncovered a possible solution for the CustomEvent concern. Regarding:
Anything event related such as trigger may have a little bit of additional complexity as we need to account for event listeners in contrib modules that expect the [, extraParameters ] arg http://api.jquery.com/trigger/. I'm pretty sure there are reasonable ways to hack around it though, and there's only upside to getting started on this even if that part isn't figured out yet.
Even when we're using only JavaScript to define events we'll need to allow those events to define custom data to consume. We can do so using an Event's detail property:
// Create a custom event with type 'myEvent' and include custom options var customEvent = new CustomEvent('myEvent', { detail: { options: [ { name: "Option 1", value: "1" }, { name: "Option 2", value: "2" } ] } }); // Dispatch the custom event document.getElementById("myButton").dispatchEvent(customEvent);
- πΊπΈUnited States cosmicdreams Minneapolis/St. Paul
Considering all of the above, it appears that we're unblocked here. All this groundwork is all the time I have today to explore this question. I'll see if I can get back to this tonight to start hacking on a MR for some of these easy bits.
- π³π±Netherlands eelkeblok Netherlands π³π±
Maybe this is a silly question, but is this backwards compatible? How to jQuery events compare to events triggered through dispatchEvent()?
- Status changed to Needs work
11 months ago 7:35am 20 February 2024 Sam Phillemon β changed the visibility of the branch 3239127-refactor-trigger to hidden.
I am facing issues with the PHP unit tests. I have tried fixing some of them but it is causing others to fail. It would be great if someone else could have a look at it.