7

I'm thinking about building a tool that converts all browser events (either native dom events like .click() or jQuery events) to a standard form.

The standard form is: HTMLElement.dispatchEvent(new Event(eventType, eventInitDict))

For example, I want to change HTMLElement.click() to HTMLElement.dispatchEvent(new Event("click", {"bubbles": true, ...})) for all events.

My question:

  1. Is there a complete mapping from events to this standard form and if so, is it documented anywhere?
  2. Are there any events that could be fired that couldn't be converted to this standard form?
  3. Does jQuery do anything fancy where I wouldn't be able to do this conversion.

It is imperative that I completely convert all events into this format... None can be spared!

Thanks!


Why am I trying to do this?

I am trying to capture all events fired by a Chrome extension. To do this, I've decided to modify an extensions content script before it is injected into the page (I don't care about background page or popup pages) so all events triggered are "tagged" as originating from an extension (this will be added to the eventInitDict in the examples above. I'm modifying Chromium to do this.


PS. I couldn't think of a better question title but if you have one, please let me know / change it.

  • `JQuery` has a normalized format for this already: `$(element).trigger('eventname')`, so why reinvent the wheel? [Check this here](http://api.jquery.com/trigger/). – The Alpha Feb 13 '17 at 21:58
  • 1
    @TheAlpha not everyone uses jQuery. I'm trying to convert code to a standardized version (the version mentioned) whether it is written using jQuery or not. If it uses jQuery, I can transform the jQuery file and if not, I can transform the original file. I'm not reinventing the wheel, I'm trying to edit the Event object in the browser to contain other properties. –  Feb 13 '17 at 22:00
  • It's for an extension so you may use anything/any library, right? – The Alpha Feb 13 '17 at 22:01
  • @TheAlpha I am not doing this to my extension, I want to transform the JavaScript before injecting any extensions content script into a page. I am editing Chrome to do this. Not every extension will use jQuery functions. –  Feb 13 '17 at 22:04
  • 2
    for a _DOM events_ reference [link](https://en.wikipedia.org/wiki/DOM_events) – ramabarca Feb 16 '17 at 11:51
  • _"It is imperative that I completely convert all events into this format... None can be spared!"_ Some events require user action to be set to `trusted:true`, else the event will not be dispatched; for example, `click` on an `` element should not be dispatched without user action. Which specific events are you trying to dispatch? – guest271314 Feb 18 '17 at 05:19
  • See http://stackoverflow.com/questions/26225987/one-listener-for-all-events-in-jquery-event-namespace/ – guest271314 Feb 18 '17 at 05:33

1 Answers1

0

To capture all events you'll need to add event listeners to the DOM for each event.

There are a lot of events to capture and this is laborious. I know because I've had to do this in a project i'm currently working on.

Normally in a SO answer it's advisable to place all the relevant text into the answer, in this instance because of the number of events available, I'm not going to do that. You can find a detailed list of DOM Events here (MDN)

Now fortunately for you events can be captured regardless of what triggers them. Underneath, JQuery most likely triggers DOM events although as I haven't looked at the JQuery source, I couldn't say for sure.

When adding event listeners, you'll want to pass a boolean set to true for useCapture on the addEventListener function.

target.addEventListener(type, listener, useCapture);

Further documentation on addEventListener here

It's likely you'll want to declare a JSON array of events you want to capture, or a static array in your code so that you can maintain the list of events you wish to capture.

Furthermore for triggering events, you'll need to store a reference to the element that they targeted. I've had to do this as well. You'll want to find a way to get the selector for whatever element fired the event.

something like the following

var eventList = ['click', 'keydown'];
for(var i = 0;i < eventList.length; i++) {
    var eventName = eventList[i];
    document.addEventListener(eventName, function (evt) {
        var selector = getElementSelector(evt.target); // where getElementSelector will be a function that returns an id, css path or xpath selector.
        var captured = { eventName: eventName, selector: selector };
    });
}

To trigger the captured event you might do the following, assuming you use the object structure above

var eventObject = { eventName: 'click', selector: '#targetId'};
var target = document.querySelector(eventObject.selector);
var event = new Event(eventName, {
    view: window,
    bubbles: true,
    cancelable: true
});
target.dispatchEvent(event);

There is a caveat, for each event captured, you'll want to capture properties on the event that may be specific to that event type, and save that in your custom object that stored event properties like eventName, selector and the like.

The 'standard' form of new Event won't suffice. Some events have different initialisation dictionaries which will be ignored by a plain Event if the properties aren't standard for the Event and this is why you should instantiate the correct object type, e.g. new MouseEvent, new KeyboardEvent. etc.

You can use new CustomEvent for capturing synthetic events that add none standard properties to the detail property of the event, but this will not suffice for regular DOM events.

It's not a small task by any measure.

Daniel Lane
  • 2,575
  • 2
  • 18
  • 33
  • Unfortunately I cannot modify the DOM. I am trying to prevent events from firing from extensions without being converted to a standard form. If I change the DOM, we 1) could not stop the original event from firing (I believe) and 2) we might intercept non-extension events and block them. I'm starting to think it's not possible to do this because of the dynamic language of JavaScript and being able to fire an event like `xxx['cli' + 'ck']()`... –  Feb 20 '17 at 11:53
  • So if I understand correctly, you're trying to trap all events triggered in a content script and stop them propagating to the page context of where they've been loaded? – Daniel Lane Feb 20 '17 at 15:31
  • Exactly. I want to taint content script events so that I can manipulate them in the v8 engine. –  Feb 21 '17 at 15:39
  • Well, presumably the events you're talking about are fired by your self? If so, as you say mark them with a property such as isChrome = true. Then in your content script at the document level, register a listener for each event you want to capture and if the event has isChrome, cancel it. – Daniel Lane Feb 21 '17 at 15:51
  • They are not being fired by myself. I am analyzing third party extensions. –  Feb 22 '17 at 13:35