Fire event in Raphael.js - javascript

I have an Raphael element with click event handler:
var paper = Raphael("container", 770, 160);
var c = paper.rect(10, 10, 50, 50);
c.click(function () {
alert("triggering");
})
How I can manually fire this event? (c.click() don't work)
Thanks!

Although this question is already answered, I will post my solution which I found out by random.
It's possible with the Raphael internals:
When you attach an event listener like element.click(func) then the element object holds an array with all events. In this array there's an object which has a method f (strange naming convention) which triggers the event.
So to sum it up you can call your event with knowing the order of your events, in your case there's just the click event which is on index 0, you can call it like: c.events[0].f();
A more generic solution would be a function like
function triggerClick(element) {
for(var i = 0, len = element.events.length; i < len; i++) {
if (element.events[i].name == 'click') {
element.events[i].f();
}
}
}​
But beware that if you had multiple click events all were triggered.
Here's a fiddle to demonstrate.

Even though this has already been answered a while ago, I was looking for something a little "more native" in nature. Here's how I go about it without relying on Mootools or jQuery.
var evObj = document.createEvent('MouseEvents');
evObj.initEvent('click', true, false);
c.node.dispatchEvent(evObj);
This basically creates the event in the browser and then dispatches it to the node associated with the Raphaël object.
Here's also the MOZ link for reference:
https://developer.mozilla.org/en-US/docs/DOM/document.createEvent

I actually found a slightly more elegant way to use Kris' method.
Raphael supports native extension of the element object so I built a little patch to add the trigger method to raphael
here it is:
//raphael programatic event firing
Raphael.el.trigger = function (str, scope, params){ //takes the name of the event to fire and the scope to fire it with
scope = scope || this;
for(var i = 0; i < this.events.length; i++){
if(this.events[i].name === str){
this.events[i].f.call(scope, params);
}
}
};
I set up a Js fiddle to show how it works: here

EDIT :
The solution purposed by Dan Lee is working better.

I write a plug-in for this, use event to calculate the right position;
Raphael.el.trigger = function(evtName, event) {
var el = this[0]; //get pure elements;
if (event.initMouseEvent) { // all browsers except IE before version 9
var mousedownEvent = document.createEvent ("MouseEvent");
mousedownEvent.initMouseEvent (
"mousedown", true, true, window, 0,
event.screenX, event.screenY, event.clientX, event.clientY,
event.ctrlKey, event.altKey, event.shiftKey, event.metaKey,
0, null);
el.dispatchEvent (mousedownEvent);
} else {
if (document.createEventObject) { // IE before version 9
var mousedownEvent = document.createEventObject (window.event);
mousedownEvent.button = 1; // left button is down
el.fireEvent (evtName, mousedownEvent);
}
}
};
Usage:
circle2.mousedown(function(e) {
var circle = this.clone();
circle.drag(move, down, up);
circle.trigger("mousedown", e);
});

Related

Simulating drag and drop on a SortableJS sortable list using JavaScript

I'm attempting to simulate a drag and drop action on a sortable HTML list created using the Sortable library. It uses the native HTML5 API to implement draggable elements and sorting within a list.
To simulate these drag events, I found and modified the following JavaScript code:
var triggerSortableDragAndDrop = function (selectorDrag, selectorDrop, callback) {
var DELAY_INTERVAL_MS = 10;
var MAX_TRIES = 2;
// fetch target elements
var elemDrag = document.querySelector(selectorDrag);
var elemDrop = document.querySelector(selectorDrop);
elemDrag.setAttribute('draggable',"true");
elemDrop.setAttribute('draggable',"true");
elemDrag.href="#";
var dragItems = document.querySelectorAll('[draggable=true]');
if (!elemDrag || !elemDrop) {
console.log("can't get elements");
return false;
}
var startingDropRect = elemDrop.getBoundingClientRect();
function rectsEqual(r1, r2) {
return r1.top === r2.top && r1.right === r2.right && r1.bottom === r2.bottom && r1.left === r2.left;
}
// function for triggering mouse events
function fireMouseEvent(type, elem) {
var evt = document.createEvent('MouseEvent');
evt.initMouseEvent(type, true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem);
elem.dispatchEvent(evt);
};
// trigger dragging process on top of drop target
// We sometimes need to do this multiple times due to the vagaries of
// how Sortable manages the list re-arrangement
var counter = 0;
function dragover() {
counter++;
console.log('DRAGOVER #' + counter);
var currentDropRect = elemDrop.getBoundingClientRect();
if (rectsEqual(startingDropRect, currentDropRect) && counter < MAX_TRIES) {
if (counter != 1) console.log("drop target rect hasn't changed, trying again");
// mouseover / mouseout etc events not necessary
// dragenter / dragleave events not necessary either
fireMouseEvent('dragover', elemDrop);
setTimeout(dragover, DELAY_INTERVAL_MS);
} else {
if (rectsEqual(startingDropRect, currentDropRect)) {
console.log("wasn't able to budge drop target after " + MAX_TRIES + " tries, aborting");
fireMouseEvent('drop', elemDrop);
if (callback) callback(false);
} else {
setTimeout(drop, DELAY_INTERVAL_MS);
}
}
}
function drop() {
console.log('DROP');
// release dragged element on top of drop target
fireMouseEvent('drop', elemDrop);
fireMouseEvent('mouseup', elemDrop); // not strictly necessary but I like the symmetry
if (callback) callback(true);
}
// start dragging process
console.log('DRAGSTART');
fireMouseEvent('mousedown', elemDrag);
console.log('mousedown triggered');
fireMouseEvent('dragstart', elemDrag);
console.log('dragstart triggered');
// after a delay, do the first dragover; this will run up to MAX_TRIES times
// (with a delay between each run) and finally run drop() with a delay:
setTimeout(dragover, DELAY_INTERVAL_MS);
return true;
};
And the markup of the section I'm trying to drag and drop with is as follows:
When I tried to set breakpoints on the browser's drag event listeners, and execute the helper function in my browser console using:
triggerSortableDragAndDrop('#bookmarkItems > li:nth-child(2)', '#bookmarkItems > li:nth-child(2)');
I noticed that the dragstart event was never captured, but the mousedown and dragover events were.
How can I get the dragstart event fire to trigger its listener? Because I think that is what's causing the drag and drop simulation to fail.
I can see in your code the dragstart event is created of type MouseEvent while it is of type DragEvent.
var elem = document.getElementById("one");
var mousedown = document.createEvent('MouseEvent');
mousedown.initMouseEvent("mousedown", true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem);
elem.dispatchEvent(mousedown);
var dragstart = document.createEvent('DragEvent');
dragstart.initMouseEvent("dragstart", true, true, window, 1, 1, 1, 0, 0, false, false, false, false, 0, elem);
elem.dispatchEvent(dragstart);
<div id="one" draggable="true" onmousedown="console.log('mousedown')" ondragstart="console.log('dragstart')">drag me</div>
Creating the dragstart as an event of the correct type, at least on Chrome and Edge, it works.
Hope this helps.
I used a more modern approach to trigger the dragstart and mousedown events (note that using event constructors is preferable over document.createEvent()). Both events work as expected. Some code to illustrate that below:
let text = document.getElementById('image');
text.addEventListener('dragstart', () => {
console.log('dragstart triggered')
});
text.addEventListener('mousedown', () => {
console.log('mousedown triggered')
});
function btn_click() {
const evt_1 = new MouseEvent('mousedown');
text.dispatchEvent(evt_1);
const evt_2 = new DragEvent('dragstart');
text.dispatchEvent(evt_2);
}
<p>Drag around the image to trigger the ondragstart and mousedown event.</p>
<button onclick='btn_click()'>Programatically trigger the ondragstart and onmousedown events.</button>
<br>
<br>
<img id='image' src='https://via.placeholder.com/150'>
However there is a big unknown in your code; How does the library you are using handle these events? Does it even handle the ondragstart event? It may very well only use other events, thus you can't assume these events in your JS code. The main issue is the coupling between your JS and that in the library.
So there are 2 ways to go about this
Ensure your code uses the events the library responds to (keep in mind that the code in the library and the available events may change over time)
Implement your own drag-and-drop behaviour
PS: If you are writing tests, you may decide not to test the library and trust it to behave as expected. Maybe you can validate whether your implementation of the library is correct instead.

Transitionend triggered on child transitionend [duplicate]

I need to use javascript only for this project. Sorry, no jQuery (I feel ashamed as well).
I am adding an addEventListener to a div. "Problem" is that it applies to all its children, too.
Is there a way to avoid this, and have the listener work only for that div?
Thankd in advance.
my code looks like this:
document.getElementById(myObj.id).addEventListener("mousedown", myObjDown, false);
function myObjDown() {
//do stuff here
}
You can tell which element the event actually fired on by reading event.target in your callback.
var el = ...
el.addEventListener('click', function(event){
if (el !== event.target) return;
// Do your stuff.
}, false);
The other option would be to have handlers bound to the child elements to prevent the event from reaching the parent handler, but that is more work and potentially hides events from things that might actually be listening for them above the parent.
Update
Given your example code, you should be able to do this.
var el = document.getElementById(myObj.id);
el.addEventListener("mousedown", myObjDown, false);
function myObjDown(event) {
if (el !== event.target) return;
//do stuff here
}
Also as a general note, keep in mind that none if this will work on IE < 9 because addEventListener is not supported on those.
You can use the currentTarget Event Property
el.addEventListener('click', function(event) {
if (event.currentTarget !== event.target) {
return;
}
// Do your stuff.
}, false);
More details: https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
Here's an alternative, which keeps your myObjDown function in line with a typical event handler. (using e.target as reference to the event invoking element)
var CssSelector = "div.className";
var elms = document.querySelectorAll(CssSelector);
for (i = 0; i < elms.length; i++) {
elms[i].addEventListener("mousedown", myObjDown.bind(null, {"target":elms[i]}, false);
}
function myObjDown(e) {
console.log("event: %o - target: %o", e, e.target);
var elm = e.target;
//do stuff here
}
It was suggested that ..
this method could cause memory leaks with versions of some browsers. If anyone experiences this or has any valuable insights. Please comment.
an alternative, in this regard would be
var CssSelector = "div.className";
var elms = document.querySelectorAll(CssSelector);
for (i = 0; i < elms.length; i++) {
elms[i].addEventListener("mousedown", myObjDown.bind(null, elms[i].id}, false);
}
function myObjDown(id) {
console.log("element: %o ", document.getElementById(id));
//do stuff here
}
this work for me:
document.getElementById(myObj.id).addEventListener("mousedown", myObjDown, false);
function myObjDown(e) {
var myTarget= ele.target;
while (myTarget!== this) {
myTarget= myTarget.parentNode; //finding correct tag
}
//do stuff here
}

Please explain what this code means

I'm going through the tutorial at the address: http://www.stanford.edu/~ouster/cgi-bin/cs142-spring12/lecture.php?topic=event.
And I don't understand about code at the lines that I have marked with asterisks.
function Dragger(id) {
this.isMouseDown = false;
this.element = document.getElementById(id);
var obj = this;
this.element.onmousedown = function(event) {
obj.mouseDown(event);
}
}
Dragger.prototype.mouseDown = function(event) {
var obj = this;
this.oldMoveHandler = document.body.onmousemove; /******/
document.body.onmousemove = function(event) { /******/
obj.mouseMove(event);
}
this.oldUpHandler = document.body.onmouseup; /******/
document.body.onmouseup = function(event) { /******/
obj.mouseUp(event);
}
this.oldX = event.clientX;
this.oldY = event.clientY;
this.isMouseDown = true;
}
Dragger.prototype.mouseMove = function(event) {
if (!this.isMouseDown) {
return;
}
this.element.style.left = (this.element.offsetLeft
+ (event.clientX - this.oldX)) + "px";
this.element.style.top = (this.element.offsetTop
+ (event.clientY - this.oldY)) + "px";
this.oldX = event.clientX;
this.oldY = event.clientY;
}
Dragger.prototype.mouseUp = function(event) {
this.isMouseDown = false;
document.body.onmousemove = this.oldMoveHandler; /******/
document.body.onmouseup = this.oldUpHandler; /******/
}
The purpose of the this.oldMoveHandler references are to store whatever event handlers a previous developer of the page may have added to "document.body.onmousemove", with the goal of not interrupting whatever behavior that developer no doubt spend painful hours to build. It goes like this:
Press down with the mouse, store the old handler, add our fancy dragging handler.
Move the mouse, lovely dragging behavior occurs.
Release the mouse, dragging behavior stops, restore old handler (even if it's null).
This is a way to stay out of the way of previous code, although it's a bad solution. The much preferred way is to use addEventListener/removeEventListener or attachEvent/detachEvent for barbaric IE browsers. These functions are designed so that multiple handlers can subscribe to the same event without stepping on each other. Here's some good reading:
http://www.quirksmode.org/js/introevents.html
Setting document.body.onmousemove is one (ugly) way to listen for mousemove events on the document.body element.
Therefore, this.oldMoveHandler = document.body.onmousemove; is simply storing a reference to the event handler function, if any.
Please note that using element.addEventListener is preferred for attaching event handlers.
As noted in the comments the use of intrusive event handling is very old fashioned and not recommended now.
However to answer your question the code is implementing drag and drop, when the mousedown event is triggered by a mouse press the current event handlers for mouseup and mouseover (first 4 lines of marked code) are "saved" and replaced by the event handlers that will perform the drag and drop.
When the dragged element is "dropped" i.e. the mouseup event fires, the mousemove and mouseup event handlers are replaced with the original event handlers that were saved (last 2 lines of marked code)

javascript addEventListener without selecting children

I need to use javascript only for this project. Sorry, no jQuery (I feel ashamed as well).
I am adding an addEventListener to a div. "Problem" is that it applies to all its children, too.
Is there a way to avoid this, and have the listener work only for that div?
Thankd in advance.
my code looks like this:
document.getElementById(myObj.id).addEventListener("mousedown", myObjDown, false);
function myObjDown() {
//do stuff here
}
You can tell which element the event actually fired on by reading event.target in your callback.
var el = ...
el.addEventListener('click', function(event){
if (el !== event.target) return;
// Do your stuff.
}, false);
The other option would be to have handlers bound to the child elements to prevent the event from reaching the parent handler, but that is more work and potentially hides events from things that might actually be listening for them above the parent.
Update
Given your example code, you should be able to do this.
var el = document.getElementById(myObj.id);
el.addEventListener("mousedown", myObjDown, false);
function myObjDown(event) {
if (el !== event.target) return;
//do stuff here
}
Also as a general note, keep in mind that none if this will work on IE < 9 because addEventListener is not supported on those.
You can use the currentTarget Event Property
el.addEventListener('click', function(event) {
if (event.currentTarget !== event.target) {
return;
}
// Do your stuff.
}, false);
More details: https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget
Here's an alternative, which keeps your myObjDown function in line with a typical event handler. (using e.target as reference to the event invoking element)
var CssSelector = "div.className";
var elms = document.querySelectorAll(CssSelector);
for (i = 0; i < elms.length; i++) {
elms[i].addEventListener("mousedown", myObjDown.bind(null, {"target":elms[i]}, false);
}
function myObjDown(e) {
console.log("event: %o - target: %o", e, e.target);
var elm = e.target;
//do stuff here
}
It was suggested that ..
this method could cause memory leaks with versions of some browsers. If anyone experiences this or has any valuable insights. Please comment.
an alternative, in this regard would be
var CssSelector = "div.className";
var elms = document.querySelectorAll(CssSelector);
for (i = 0; i < elms.length; i++) {
elms[i].addEventListener("mousedown", myObjDown.bind(null, elms[i].id}, false);
}
function myObjDown(id) {
console.log("element: %o ", document.getElementById(id));
//do stuff here
}
this work for me:
document.getElementById(myObj.id).addEventListener("mousedown", myObjDown, false);
function myObjDown(e) {
var myTarget= ele.target;
while (myTarget!== this) {
myTarget= myTarget.parentNode; //finding correct tag
}
//do stuff here
}

Is it possible to programmatically catch all events on the page in the browser?

First of all, here is a list of event types that are defined by the W3C standards. (This list is based on the onevent attributes defined in the HTML5 standard. I assume that there are dozens of other event types, but this list is long enough as it is.)
abort
afterprint
beforeprint
beforeunload
blur
canplay
canplaythrough
change
click
contextmenu
copy
cuechange
cut
dblclick
DOMContentLoaded
drag
dragend
dragenter
dragleave
dragover
dragstart
drop
durationchange
emptied
ended
error
focus
focusin
focusout
formchange
forminput
hashchange
input
invalid
keydown
keypress
keyup
load
loadeddata
loadedmetadata
loadstart
message
mousedown
mouseenter
mouseleave
mousemove
mouseout
mouseover
mouseup
mousewheel
offline
online
pagehide
pageshow
paste
pause
play
playing
popstate
progress
ratechange
readystatechange
redo
reset
resize
scroll
seeked
seeking
select
show
stalled
storage
submit
suspend
timeupdate
undo
unload
volumechange
waiting
Now, is it possible to define a global event handler that is called when any event originally occurs on any element on the page? (In this case, I don't want to count those events that occurred on elements because they bubbled up from a descendant element - that's why I wrote "originally occurs".)
If that is not possible, is it at least possible to define an event handler that is called when any event bubbles up to the root of the DOM tree (which is either the document object or the window object - both should work)? (I know that it's possible to stop bubbling programmatically, but I would use this event handler on a page that has no other handlers defined on any other elements.) (Also, I believe some events don't bubble up, but let's ignore these cases for the sake of this argument.)
I know that I can do this (using jQuery):
$(document).bind('abort afterprint beforeprint beforeunload etc.', function() {
// handle event
});
but that would be a rather undesirable solution for me.
btw I don't need a cross-browser solution. If it works in just one browser, I'm fine.
Also, Firebug is able to log events, but I would like to be able to catch the event programmatically (via JavaScript) rather then having them simply logged in the console.
/*
function getAllEventTypes(){
if(location.href !='https://developer.mozilla.org/en-US/docs/Web/Events') return;
var types = {};
$('.standard-table:eq(0) tr').find('td:eq(1)').map(function(){
var type = $.trim(this.innerText) || 'OtherEvent';
types[type] = types[type] || [];
var event = $.trim(this.previousElementSibling.innerText);
if(event) types[type].push(event);
});
for(var t in types) types[t] = types[t].join(' ');
return "var DOMEvents = "+JSON.stringify(types, null, 4).replace(/"(\w+)\":/ig, '$1:');
}
*/
var DOMEvents = {
UIEvent: "abort DOMActivate error load resize scroll select unload",
ProgressEvent: "abort error load loadend loadstart progress progress timeout",
Event: "abort afterprint beforeprint cached canplay canplaythrough change chargingchange chargingtimechange checking close dischargingtimechange DOMContentLoaded downloading durationchange emptied ended ended error error error error fullscreenchange fullscreenerror input invalid languagechange levelchange loadeddata loadedmetadata noupdate obsolete offline online open open orientationchange pause pointerlockchange pointerlockerror play playing ratechange readystatechange reset seeked seeking stalled submit success suspend timeupdate updateready visibilitychange volumechange waiting",
AnimationEvent: "animationend animationiteration animationstart",
AudioProcessingEvent: "audioprocess",
BeforeUnloadEvent: "beforeunload",
TimeEvent: "beginEvent endEvent repeatEvent",
OtherEvent: "blocked complete upgradeneeded versionchange",
FocusEvent: "blur DOMFocusIn Unimplemented DOMFocusOut Unimplemented focus focusin focusout",
MouseEvent: "click contextmenu dblclick mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup show",
SensorEvent: "compassneedscalibration Unimplemented userproximity",
OfflineAudioCompletionEvent: "complete",
CompositionEvent: "compositionend compositionstart compositionupdate",
ClipboardEvent: "copy cut paste",
DeviceLightEvent: "devicelight",
DeviceMotionEvent: "devicemotion",
DeviceOrientationEvent: "deviceorientation",
DeviceProximityEvent: "deviceproximity",
MutationNameEvent: "DOMAttributeNameChanged DOMElementNameChanged",
MutationEvent: "DOMAttrModified DOMCharacterDataModified DOMNodeInserted DOMNodeInsertedIntoDocument DOMNodeRemoved DOMNodeRemovedFromDocument DOMSubtreeModified",
DragEvent: "drag dragend dragenter dragleave dragover dragstart drop",
GamepadEvent: "gamepadconnected gamepaddisconnected",
HashChangeEvent: "hashchange",
KeyboardEvent: "keydown keypress keyup",
MessageEvent: "message message message message",
PageTransitionEvent: "pagehide pageshow",
PopStateEvent: "popstate",
StorageEvent: "storage",
SVGEvent: "SVGAbort SVGError SVGLoad SVGResize SVGScroll SVGUnload",
SVGZoomEvent: "SVGZoom",
TouchEvent: "touchcancel touchend touchenter touchleave touchmove touchstart",
TransitionEvent: "transitionend",
WheelEvent: "wheel"
}
var RecentlyLoggedDOMEventTypes = {};
for (var DOMEvent in DOMEvents) {
var DOMEventTypes = DOMEvents[DOMEvent].split(' ');
DOMEventTypes.filter(function(DOMEventType) {
var DOMEventCategory = DOMEvent + ' ' + DOMEventType;
document.addEventListener(DOMEventType, function(e){
if(RecentlyLoggedDOMEventTypes[DOMEventCategory]) { return; }
RecentlyLoggedDOMEventTypes[DOMEventCategory] = true;
setTimeout(function(){ RecentlyLoggedDOMEventTypes[DOMEventCategory] = false }, 5000);
var isActive = e.target == document.activeElement;
if(isActive) {
console.info(DOMEventCategory,
' target=', e.target,
' active=', document.activeElement,
' isActive=', true );
} else {
console.log(DOMEventCategory,
' target=', e.target,
' active=', document.activeElement,
' isActive=', false );
}
}, true);
});
}
You can iterate through all properties of dom element and select ones that match /on(.*)/ pattern (for example onclick or onmousemove):
var events = [];
for (var property in element) {
var match = property.match(/^on(.*)/)
if (match) {
events.push(match[1]);
}
}
console.log(events.join(' '))
I highly doubt there's a way to do this in Firefox. Looking at Firebug's source code (particularly the attachAllListeners method), turns out that iterating through a list of event names is obviously the way to go, but this doesn't solve the bubbling issues.
There doesn't seem to be any 'easy-way' to do that.
My idea:
You know which are all the events, so you can handle all events for every DOM element:
var events =
[
"onabort",
"onafterprint",
"onbeforeprint",
"onbeforeunload",
...
];
var root = document.body;
var elms = root.childNodes;
for(var i = 0; i < elms.length; i++)
{
for(var j = 0; j < events.length; j++)
{
elms[i][events[j]] = globalHandler;
}
}
function globalHandler()
{
alert("Global handler called");
}
That's the 'intuitive idea' but doesn't seem to be very efficient. However, it should work.
Good luck.
How to listen for all events on a specific target Element 👾
For all native events, we can retrieve a list of supported events by iterating over the target.onevent properties and installing our listener for all of them.
for (const key in target) {
if(/^on/.test(key)) {
const eventType = key.substr(2);
target.addEventListener(eventType, listener);
}
}
The only other way that events are emitted which I know of is via EventTarget.dispatchEvent, which every Node and thefore every Element inherits.
To listen for all these manually triggered events, we can proxy the dispatchEvent method globally and install our listener just-in-time for the event whose name we just saw ✨ ^^
const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
EventTarget.prototype.dispatchEvent = function (event) {
if (!alreadyListenedEventTypes.has(event.type)) {
target.addEventListener(event.type, listener, ...otherArguments);
alreadyListenedEventTypes.add(event.type);
}
dispatchEvent_original.apply(this, arguments);
};
🔥 function snippet 🔥
function addEventListenerAll(target, listener, ...otherArguments) {
// install listeners for all natively triggered events
for (const key in target) {
if (/^on/.test(key)) {
const eventType = key.substr(2);
target.addEventListener(eventType, listener, ...otherArguments);
}
}
// dynamically install listeners for all manually triggered events, just-in-time before they're dispatched ;D
const dispatchEvent_original = EventTarget.prototype.dispatchEvent;
function dispatchEvent(event) {
target.addEventListener(event.type, listener, ...otherArguments); // multiple identical listeners are automatically discarded
dispatchEvent_original.apply(this, arguments);
}
EventTarget.prototype.dispatchEvent = dispatchEvent;
if (EventTarget.prototype.dispatchEvent !== dispatchEvent) throw new Error(`Browser is smarter than you think!`);
}
// usage example
addEventListenerAll(window, (evt) => {
console.log(evt.type);
});
document.body.click();
document.body.dispatchEvent(new Event('omg!', { bubbles: true }));
// usage example with `useCapture`
// (also receives `bubbles: false` events, but in reverse order)
addEventListenerAll(
window,
(evt) => { console.log(evt.type); },
true
);
document.body.dispatchEvent(new Event('omfggg!', { bubbles: false }));
A bit late to the party but I did create something that might be useful for others here.
https://codepen.io/phreaknation/pen/QmJjEa
This is an ES6 Class that captures all events from an element that is known to that element. This demo allows you to change the element time in the page, as well as read out the events with clickable links to their MDN page as well as interact with the element and see how the events are triggered with time stamps.
I hope this helps
Class code
class EventSystem {
constructor(element) {
this._ = {
element: null
}
return this;
}
getAllEventTypes({blacklist = [], whitelist = []} = {}) {
const events = [];
for (let property in this._.element) {
const match = property.match(/^on(.*)/);
if (match) {
if ((whitelist.length > 0 ? whitelist.indexOf(match) !== -1 : true) &&
(blacklist.length > 0 ? blacklist.indexOf(match) === -1 : true)) {
events.push(match[1]);
}
}
}
return events;
}
getElementType() {
return this._.element.tagName.toLowerCase();
}
setElement(element) {
this._.element = element;
return this;
}
applyEvents(events, callback) {
events.forEach((event) => {
this._.element.addEventListener(event, (ev) => {
if (typeof callback === 'function') {
callback(event, ev);
}
})
})
}
}
My solution to this problem. I loop through all datatypes on the global context (window, in this case), check if the type extends EventTarget, and then extracts them via checking for the "on" prefix.
const getEventNames = (root) => {
let events = [ ];
const objectHasSubPrototype = (object, comp) => {
let proto = Object.getPrototypeOf(object);
while(proto !== null && proto !== EventTarget) {
proto = Object.getPrototypeOf(proto);
}
return (proto !== null);
};
const addEventNames = (propNames) => {
propNames.filter(x => x.match(/^on\w+$/)).forEach((propName) => {
propName = propName.substr(2);
if(events.indexOf(propName) === -1) {
events.push(propName);
}
});
};
Object.getOwnPropertyNames(root).forEach((name) => {
let value = root[name];
if(value) {
if(objectHasSubPrototype(value, EventTarget)) {
let propNames = Object.getOwnPropertyNames(Object.getPrototypeOf(value).prototype);
addEventNames(propNames);
propNames = Object.getOwnPropertyNames(window);
addEventNames(propNames);
}
}
});
return events;
};
// Attach all events to the window
getEventNames(window).forEach((eventName) => {
window.addEventListener(eventName, (event) => console.log(eventName, event));
});
For the last version of the MDN website:
(function getAllEventTypes(){
if(location.href !='https://developer.mozilla.org/en-US/docs/Web/Events') return;
var types = {};
$('.standard-table').map(function(){
if($(this).find('caption').length > 0){
var type = $(this).find('caption')[0].innerHTML || 'OtherEvent';
types[type] = types[type] || [];
$(this).find('tbody tr td code a').each(function(el){
if(this.innerText) types[type].push(this.innerText);
});
}
});
for(var t in types) types[t] = types[t].join(' ');
return "var DOMEvents = "+JSON.stringify(types, null, 4).replace(/"(\w+)\":/ig, '$1:');
})();

Categories