Javascript mousup event triggers very late - javascript

I have a jquery sorting plugin which works pretty fine, but if I make few dragging operations the mouseup event starts to be very slow. It takes about 1 second while it triggers the event. If I dump end of mousemove event it stops immediately but mouseup event starts after the second. I added the console.log() for every method in the code but there is no call between drag stop and mouseup. What could be the
problem? How can I debug possible parallel processes in the browser? The code looks like:
....
state.doc
.on( 'mousemove', dragging )
.on( 'mouseup', endDrag );
}
/**
* #desc Start dragging
* #param e event obj.
*/
function dragging( e )
{
...
console.log('dragging end');
}
function endDrag( e )
{
var cEl = state.cEl,
hintNode = $( '#sortableListsHint', state.rootEl.el ),
hintStyle = hint[0].style,
targetEl = null, // hintNode/placeholderNode
isHintTarget = false, // if cEl will be placed to the hintNode
hintWrapperNode = $( '#sortableListsHintWrapper' );
if ( hintStyle.display == 'block' && hintNode.length && state.isAllowed )
{
targetEl = hintNode;
isHintTarget = true;
}
else
{
targetEl = state.placeholderNode;
isHintTarget = false;
}
offset = targetEl.offset();
cEl.el.animate( { left: offset.left - state.cEl.mL, top: offset.top - state.cEl.mT }, 250,
function() // complete callback
{
tidyCurrEl( cEl );
targetEl.after( cEl.el[0] );
targetEl[0].style.display = 'none';
hintStyle.display = 'none';
// This has to be document node, not hint as a part of documentFragment.
hintNode.remove();
hintWrapperNode
.removeAttr( 'id' )
.removeClass( setting.hintWrapperClass );
if ( hintWrapperNode.length )
{
hintWrapperNode.prev( 'div' ).append( opener.clone( true ) );
}
var placeholderNode = state.placeholderNode;
// Directly removed placeholder looks bad. It jumps up if the hint is below.
if ( isHintTarget )
{
placeholderNode.slideUp( 150, function()
{
var placeholderParent = placeholderNode.parent();
var placeholderParentLi = ( ! placeholderParent.is( state.rootEl.el ) ) ? placeholderParent.closest( 'li' ) : null;
placeholderNode.remove();
tidyEmptyLists();
setting.onChange( cEl.el );
setting.complete( cEl.el ); // Have to be here cause is necessary to remove placeholder before complete call.
state.isDragged = false;
if( setting.maxLevels !== false ) // Has to be after placeholder remove.
{
recountLevels( cEl.el );
if( placeholderParentLi ) recountLevels( placeholderParentLi );
}
});
}
else
{
state.placeholderNode.remove();
tidyEmptyLists();
setting.complete( cEl.el );
state.isDragged = false;
}
} );
scrollStop( state );
state.doc
.unbind( "mousemove", dragging )
.unbind( "mouseup", endDrag );
}
....
Here https://camo.publicvm.com/ I made an example with dumps for all methods in the code. Look at the latency of endDragggggggggggggggggggggggggggggg log. Also I checked this issue in Opera browser and it has no problem with it.
EDIT: I think the problem was in local variables in the closure in animate call. var placeholderNode, var placeholderParent and var placeholderParentL. As I rewrite it to global state object problem is gone.

A classic user click triggers mousedown and mouseup.
The time between the two is usually somewhere ~50ms.
In that short period of time, the browser might be busy due to processes fired by mousedown and event bubbling and propagation, specially if you bound too much handlers far up in the DOM tree like to document or "html, body". Avoid that.
Also, mouseup might end up being never registered.
If some processes are taking too much time or you're simply too fast with your mouse, the mouseup might not be over the target element at the time it's triggered, therefore never firing that event.

I think the problem was in local variables in the closure in animate call. var placeholderNode, var placeholderParent and var placeholderParentL. As I rewrite it to global state object problem seem to be less visible. But I am not sure if this is the root of issue.

make it synchronous with the use of promise or async/await.
This link below contains documentation on async.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Related

click through overlay div to canvas with delegating click event over coordinates

I have a canvas-application that has no built-in zoom&pan solution.
My workaround is an overlay over the canvas with pointer-events:all and opacity: 0, so you can zoom and pan around.
My Problem now is to delegate a click from the overlay to the canvas. Now my idea was to take the coordinates of the touch-click and simulate this click again with pointer-events:none but its not working..
$(document).on('touchstart', function (event) {
showCoordinates(event);
});
function showCoordinates(event) {
var x = event.touches[0].clientX;
var y = event.touches[0].clientY;
console.log(x);
console.log(y);
$('#overlay').css('pointer-events','none');
var myEvent = $.Event( "touchstart", { pageX:x, pageY:y } );
$("body").trigger( myEvent );
$('#overlay').css('pointer-events','all');
}
and my main problem is the part where i simulate the click here
var myEvent = $.Event( "touchstart", { pageX:x, pageY:y } );
$("body").trigger( myEvent );
it even doesnt work in google chrome console.
What am I doing wrong here?
First problem is that the event you created does not have event.touches[0].clientX and event.touches[0].clientY props which are used in the showCoordinates function. Change
var myEvent = $.Event( "touchstart", { pageX:x, pageY:y } );
to
var myEvent = $.Event( "touchstart", { touches: [{clientX: x, clientY: y}] } );
. And in the last line, give values to x and y. Most probably, you will run into new problems, like infinite recursion. Give some HTML code so you can better help. I guess, there is a simpler solution.

How to hook on library function (Golden Layout) and call additional methods

I'm using a library called Golden Layout, it has a function called destroy which will close all the application window, on window close or refesh
I need to add additional method to the destroy function. I need to removeall the localstorage aswell.
How do i do it ? Please help
Below is the plugin code.
lm.LayoutManager = function( config, container ) {
....
destroy: function() {
if( this.isInitialised === false ) {
return;
}
this._onUnload();
$( window ).off( 'resize', this._resizeFunction );
$( window ).off( 'unload beforeunload', this._unloadFunction );
this.root.callDownwards( '_$destroy', [], true );
this.root.contentItems = [];
this.tabDropPlaceholder.remove();
this.dropTargetIndicator.destroy();
this.transitionIndicator.destroy();
this.eventHub.destroy();
this._dragSources.forEach( function( dragSource ) {
dragSource._dragListener.destroy();
dragSource._element = null;
dragSource._itemConfig = null;
dragSource._dragListener = null;
} );
this._dragSources = [];
},
I can access the destroy method in the component like this
this.layout = new GoldenLayout(this.config, this.layoutElement.nativeElement);
this.layout.destroy();`
My code
#HostListener('window:beforeunload', ['$event'])
beforeunloadHandler(event) {
var originalDestroy = this.layout.destroy;
this.layout.destroy = function() {
// Call the original
originalDestroy.apply(this, arguments);
localStorage.clear();
};
}
Looking at the documentation, GoldenLayout offers an itemDestroyed event you could hook to do your custom cleanup. The description is:
Fired whenever an item gets destroyed.
If for some reason you can't, the general answer is that you can easily wrap the function:
var originalDestroy = this.layout.destroy;
this.layout.destroy = function() {
// Call the original
originalDestroy.apply(this, arguments);
// Do your additional work here
};
You may be able to do this for all instances if necessary by modifying GoldenLayout.prototype:
var originalDestroy = GoldenLayout.prototype.destroy;
GoldenLayout.prototype.destroy = function() {
// Call the original
originalDestroy.apply(this, arguments);
// Do your additional work here
};
Example:
// Stand-in for golden laout
function GoldenLayout() {
}
GoldenLayout.prototype.destroy = function() {
console.log("Standard functionality");
};
// Your override:
var originalDestroy = GoldenLayout.prototype.destroy;
GoldenLayout.prototype.destroy = function() {
// Call the original
originalDestroy.apply(this, arguments);
// Do your additional work here
console.log("Custom functionality");
};
// Use
var layout = new GoldenLayout();
layout.destroy();
Hooking into golden layout is the intended purpose for the events.
As briefly touched on by #T.J. Crowder, there is the itemDestroyed event which is called when an item in the layout is destroyed.
You can just listen for this event like such:
this.layout.on('itemDestroyed', function() {
localStorage.clear();
})
However, this event is called every time anything is destroyed, and propagates down the tree, even just by closing a tab. This means that if you call destroy on the layout root, you will get an event for every RowOrColumn, Stack and Component
I would recommend to check the item passed into the event and ignore if not the main window (root item)
this.layout.on('itemDestroyed', function(item) {
if (item.type === "root") {
localStorage.clear();
}
})

How to make ondblclick event works on phone?

I want to achieve the double click event on a specific div like this:
<div id="divID" ondblclick = 'alert("double click!!");' >
it worked on the google chrome browser but when I open it with phone it didn't work, by the way the single click worked.
ps: i added this two things
<meta name="viewport" content="width=device-width, initial scale=1,user-scalable=no">
and this
body {
-ms-touch-action: manipulation;
touch-action: manipulation;}
but it didnt work!
I got the same issue. On touch devices, if you want to detect a double-tap gesture and you use the ondblclick event in most cases it will not work and also the problem is it will also fire an onclick. One of the solution is to implement a double tap detection pattern using the following code sample:
var doubletapDeltaTime_ = 700;
var doubletap1Function_ = null;
var doubletap2Function_ = null;
var doubletapTimer = null;
function tap(singleTapFunc, doubleTapFunc) {
if (doubletapTimer==null) {
// First tap, we wait X ms to the second tap
doubletapTimer_ = setTimeout(doubletapTimeout_, doubletapDeltaTime_);
doubletap1Function_ = singleTapFunc;
doubletap2Function_ = doubleTapFunc;
} else {
// Second tap
clearTimeout(doubletapTimer);
doubletapTimer_ = null;
doubletap2Function_();
}
}
function doubletapTimeout() {
// Wait for second tap timeout
doubletap1Function_();
doubleTapTimer_ = null;
}
And you can call it like
<div id="divID" onclick="tap(tapOnce, tapTwice)" >
tapOnce and tapTwice are your functions which will be called in respective cases. This solution will work on browsers too.
Reference
Here is the external function 'doubletap' which can be helpful:
/*
* jQuery Double Tap
* Developer: Sergey Margaritov (sergey#margaritov.net)
* Date: 22.10.2013
* Based on jquery documentation http://learn.jquery.com/events/event-extensions/
*/
(function($){
$.event.special.doubletap = {
bindType: 'touchend',
delegateType: 'touchend',
handle: function(event) {
var handleObj = event.handleObj,
targetData = jQuery.data(event.target),
now = new Date().getTime(),
delta = targetData.lastTouch ? now - targetData.lastTouch : 0,
delay = delay == null ? 300 : delay;
if (delta < delay && delta > 30) {
targetData.lastTouch = null;
event.type = handleObj.origType;
['clientX', 'clientY', 'pageX', 'pageY'].forEach(function(property) {
event[property] = event.originalEvent.changedTouches[0][property];
})
// let jQuery handle the triggering of "doubletap" event handlers
handleObj.handler.apply(this, arguments);
} else {
targetData.lastTouch = now;
}
}
};
})(jQuery);
Load jQuery Mobile into your project and try using taphold or some of the other mobile specific touch events that are available to you through that API.
Here's the jQuery Mobile documentation with all the events you can use: http://api.jquerymobile.com/category/events/
Here is the snippet for TS React users. Pass in the click event, so that double click is only invoked if the same element is clicked twice
import React from "react";
type CallBack = () => any;
type TapParams = { onSingleTap?: CallBack; onDoubleTap?: CallBack };
var DELTA_TIME_THRESHOLD_MS = 700;
var timer: NodeJS.Timeout | null = null;
var target: EventTarget;
export function tap(
e: React.MouseEvent,
{ onSingleTap, onDoubleTap }: TapParams
) {
if (timer == null) {
// First tap
onSingleTap?.();
timer = setTimeout(() => {
timer = null;
}, DELTA_TIME_THRESHOLD_MS);
} else {
// Second tap
if (e.target === target) {
onDoubleTap?.();
}
clearTimeout(timer);
timer = null;
}
target = e.target;
}
Usage
<div
onClick={(e) => tap(e, { onSingleTap, onDoubleTap })}
>Tap or doubletap</div>
Using only JavaScript
You can use "touchstart" event for a single touch,
but with calculating the time when he should click again
I used 400 (0.4s) as it's the longer duration between two touches
It's only an estimate, but it's still a reasonable time
let expired
let doubleClick = function () {
console.log('double click')
}
let doubleTouch = function (e) {
if (e.touches.length === 1) {
if (!expired) {
expired = e.timeStamp + 400
} else if (e.timeStamp <= expired) {
// remove the default of this event ( Zoom )
e.preventDefault()
doubleClick()
// then reset the variable for other "double Touches" event
expired = null
} else {
// if the second touch was expired, make it as it's the first
expired = e.timeStamp + 400
}
}
}
let element = document.getElementById('btn')
element.addEventListener('touchstart', doubleTouch)
element.addEventListener('dblclick', doubleClick)
In case of this error :
Unable to preventDefault inside passive event listener due to target being treated as passive.
event.preventDefault( ) not working if element = "document" or "document.body"
So the solution of that, you should have a full page div container :
let element = document.getElementById('container')
element.style.minWidth = '100vw'
element.style.minHeight = '100vh'
document.body.style.margin = '0px'
element.addEventListener('touchstart', elementTouch)
element.addEventListener('dblclick', doubleClick)

How do you log all events fired by an element in jQuery?

I'd like to see all the events fired by an input field as a user interacts with it. This includes stuff like:
Clicking on it.
Clicking off it.
Tabbing into it.
Tabbing away from it.
Ctrl+C and Ctrl+V on the keyboard.
Right click -> Paste.
Right click -> Cut.
Right click -> Copy.
Dragging and dropping text from another application.
Modifying it with Javascript.
Modifying it with a debug tool, like Firebug.
I'd like to display it using console.log. Is this possible in Javascript/jQuery, and if so, how do I do it?
I have no idea why no-one uses this... (maybe because it's only a webkit thing)
Open console:
monitorEvents(document.body); // logs all events on the body
monitorEvents(document.body, 'mouse'); // logs mouse events on the body
monitorEvents(document.body.querySelectorAll('input')); // logs all events on inputs
$(element).on("click mousedown mouseup focus blur keydown change",function(e){
console.log(e);
});
That will get you a lot (but not all) of the information on if an event is fired... other than manually coding it like this, I can't think of any other way to do that.
There is a nice generic way using the .data('events') collection:
function getEventsList($obj) {
var ev = new Array(),
events = $obj.data('events'),
i;
for(i in events) { ev.push(i); }
return ev.join(' ');
}
$obj.on(getEventsList($obj), function(e) {
console.log(e);
});
This logs every event that has been already bound to the element by jQuery the moment this specific event gets fired. This code was pretty damn helpful for me many times.
Btw: If you want to see every possible event being fired on an object use firebug: just right click on the DOM element in html tab and check "Log Events". Every event then gets logged to the console (this is sometimes a bit annoying because it logs every mouse movement...).
$('body').on("click mousedown mouseup focus blur keydown change mouseup click dblclick mousemove mouseover mouseout mousewheel keydown keyup keypress textInput touchstart touchmove touchend touchcancel resize scroll zoom focus blur select change submit reset",function(e){
console.log(e);
});
I know the answer has already been accepted to this, but I think there might be a slightly more reliable way where you don't necessarily have to know the name of the event beforehand. This only works for native events though as far as I know, not custom ones that have been created by plugins. I opted to omit the use of jQuery to simplify things a little.
let input = document.getElementById('inputId');
Object.getOwnPropertyNames(input)
.filter(key => key.slice(0, 2) === 'on')
.map(key => key.slice(2))
.forEach(eventName => {
input.addEventListener(eventName, event => {
console.log(event.type);
console.log(event);
});
});
I hope this helps anyone who reads this.
EDIT
So I saw another question here that was similar, so another suggestion would be to do the following:
monitorEvents(document.getElementById('inputId'));
Old thread, I know. I needed also something to monitor events and wrote this very handy (excellent) solution. You can monitor all events with this hook (in windows programming this is called a hook). This hook does not affects the operation of your software/program.
In the console log you can see something like this:
Explanation of what you see:
In the console log you will see all events you select (see below "how to use") and shows the object-type, classname(s), id, <:name of function>, <:eventname>.
The formatting of the objects is css-like.
When you click a button or whatever binded event, you will see it in the console log.
The code I wrote:
function setJQueryEventHandlersDebugHooks(bMonTrigger, bMonOn, bMonOff)
{
jQuery.fn.___getHookName___ = function()
{
// First, get object name
var sName = new String( this[0].constructor ),
i = sName.indexOf(' ');
sName = sName.substr( i, sName.indexOf('(')-i );
// Classname can be more than one, add class points to all
if( typeof this[0].className === 'string' )
{
var sClasses = this[0].className.split(' ');
sClasses[0]='.'+sClasses[0];
sClasses = sClasses.join('.');
sName+=sClasses;
}
// Get id if there is one
sName+=(this[0].id)?('#'+this[0].id):'';
return sName;
};
var bTrigger = (typeof bMonTrigger !== "undefined")?bMonTrigger:true,
bOn = (typeof bMonOn !== "undefined")?bMonOn:true,
bOff = (typeof bMonOff !== "undefined")?bMonOff:true,
fTriggerInherited = jQuery.fn.trigger,
fOnInherited = jQuery.fn.on,
fOffInherited = jQuery.fn.off;
if( bTrigger )
{
jQuery.fn.trigger = function()
{
console.log( this.___getHookName___()+':trigger('+arguments[0]+')' );
return fTriggerInherited.apply(this,arguments);
};
}
if( bOn )
{
jQuery.fn.on = function()
{
if( !this[0].__hooked__ )
{
this[0].__hooked__ = true; // avoids infinite loop!
console.log( this.___getHookName___()+':on('+arguments[0]+') - binded' );
$(this).on( arguments[0], function(e)
{
console.log( $(this).___getHookName___()+':'+e.type );
});
}
var uResult = fOnInherited.apply(this,arguments);
this[0].__hooked__ = false; // reset for another event
return uResult;
};
}
if( bOff )
{
jQuery.fn.off = function()
{
if( !this[0].__unhooked__ )
{
this[0].__unhooked__ = true; // avoids infinite loop!
console.log( this.___getHookName___()+':off('+arguments[0]+') - unbinded' );
$(this).off( arguments[0] );
}
var uResult = fOffInherited.apply(this,arguments);
this[0].__unhooked__ = false; // reset for another event
return uResult;
};
}
}
Examples how to use it:
Monitor all events:
setJQueryEventHandlersDebugHooks();
Monitor all triggers only:
setJQueryEventHandlersDebugHooks(true,false,false);
Monitor all ON events only:
setJQueryEventHandlersDebugHooks(false,true,false);
Monitor all OFF unbinds only:
setJQueryEventHandlersDebugHooks(false,false,true);
Remarks/Notice:
Use this for debugging only, turn it off when using in product final
version
If you want to see all events, you have to call this function
directly after jQuery is loaded
If you want to see only less events, you can call the function on the time you need it
If you want to auto execute it, place ( )(); around function
Hope it helps! ;-)
https://github.com/robertleeplummerjr/wiretap.js
new Wiretap({
add: function() {
//fire when an event is bound to element
},
before: function() {
//fire just before an event executes, arguments are automatic
},
after: function() {
//fire just after an event executes, arguments are automatic
}
});
Just add this to the page and no other worries, will handle rest for you:
$('input').live('click mousedown mouseup focus keydown change blur', function(e) {
console.log(e);
});
You can also use console.log('Input event:' + e.type) to make it easier.
STEP 1: Check the events for an HTML element on the developer console:
STEP 2: Listen to the events we want to capture:
$(document).on('ch-ui-container-closed ch-ui-container-opened', function(evt){
console.log(evt);
});
Good Luck...
I recently found and modified this snippet from an existing SO post that I have not been able to find again but I've found it very useful
// specify any elements you've attached listeners to here
const nodes = [document]
// https://developer.mozilla.org/en-US/docs/Web/Events
const logBrowserEvents = () => {
const AllEvents = {
AnimationEvent: ['animationend', 'animationiteration', 'animationstart'],
AudioProcessingEvent: ['audioprocess'],
BeforeUnloadEvent: ['beforeunload'],
CompositionEvent: [
'compositionend',
'compositionstart',
'compositionupdate',
],
ClipboardEvent: ['copy', 'cut', 'paste'],
DeviceLightEvent: ['devicelight'],
DeviceMotionEvent: ['devicemotion'],
DeviceOrientationEvent: ['deviceorientation'],
DeviceProximityEvent: ['deviceproximity'],
DragEvent: [
'drag',
'dragend',
'dragenter',
'dragleave',
'dragover',
'dragstart',
'drop',
],
Event: [
'DOMContentLoaded',
'abort',
'afterprint',
'beforeprint',
'cached',
'canplay',
'canplaythrough',
'change',
'chargingchange',
'chargingtimechange',
'checking',
'close',
'dischargingtimechange',
'downloading',
'durationchange',
'emptied',
'ended',
'error',
'fullscreenchange',
'fullscreenerror',
'input',
'invalid',
'languagechange',
'levelchange',
'loadeddata',
'loadedmetadata',
'noupdate',
'obsolete',
'offline',
'online',
'open',
'open',
'orientationchange',
'pause',
'play',
'playing',
'pointerlockchange',
'pointerlockerror',
'ratechange',
'readystatechange',
'reset',
'seeked',
'seeking',
'stalled',
'submit',
'success',
'suspend',
'timeupdate',
'updateready',
'visibilitychange',
'volumechange',
'waiting',
],
FocusEvent: [
'DOMFocusIn',
'DOMFocusOut',
'Unimplemented',
'blur',
'focus',
'focusin',
'focusout',
],
GamepadEvent: ['gamepadconnected', 'gamepaddisconnected'],
HashChangeEvent: ['hashchange'],
KeyboardEvent: ['keydown', 'keypress', 'keyup'],
MessageEvent: ['message'],
MouseEvent: [
'click',
'contextmenu',
'dblclick',
'mousedown',
'mouseenter',
'mouseleave',
'mousemove',
'mouseout',
'mouseover',
'mouseup',
'show',
],
// https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events
MutationNameEvent: ['DOMAttributeNameChanged', 'DOMElementNameChanged'],
MutationEvent: [
'DOMAttrModified',
'DOMCharacterDataModified',
'DOMNodeInserted',
'DOMNodeInsertedIntoDocument',
'DOMNodeRemoved',
'DOMNodeRemovedFromDocument',
'DOMSubtreeModified',
],
OfflineAudioCompletionEvent: ['complete'],
OtherEvent: ['blocked', 'complete', 'upgradeneeded', 'versionchange'],
UIEvent: [
'DOMActivate',
'abort',
'error',
'load',
'resize',
'scroll',
'select',
'unload',
],
PageTransitionEvent: ['pagehide', 'pageshow'],
PopStateEvent: ['popstate'],
ProgressEvent: [
'abort',
'error',
'load',
'loadend',
'loadstart',
'progress',
],
SensorEvent: ['compassneedscalibration', 'Unimplemented', 'userproximity'],
StorageEvent: ['storage'],
SVGEvent: [
'SVGAbort',
'SVGError',
'SVGLoad',
'SVGResize',
'SVGScroll',
'SVGUnload',
],
SVGZoomEvent: ['SVGZoom'],
TimeEvent: ['beginEvent', 'endEvent', 'repeatEvent'],
TouchEvent: [
'touchcancel',
'touchend',
'touchenter',
'touchleave',
'touchmove',
'touchstart',
],
TransitionEvent: ['transitionend'],
WheelEvent: ['wheel'],
}
const RecentlyLoggedDOMEventTypes = {}
Object.keys(AllEvents).forEach((DOMEvent) => {
const DOMEventTypes = AllEvents[DOMEvent]
if (Object.prototype.hasOwnProperty.call(AllEvents, DOMEvent)) {
DOMEventTypes.forEach((DOMEventType) => {
const DOMEventCategory = `${DOMEvent} ${DOMEventType}`
nodes.forEach((node) => {
node.addEventListener(
DOMEventType,
(e) => {
if (RecentlyLoggedDOMEventTypes[DOMEventCategory]) return
RecentlyLoggedDOMEventTypes[DOMEventCategory] = true
// NOTE: throttle continuous events
setTimeout(() => {
RecentlyLoggedDOMEventTypes[DOMEventCategory] = false
}, 1000)
const isActive = e.target === document.activeElement
// https://developer.mozilla.org/en-US/docs/Web/API/DocumentOrShadowRoot/activeElement
const hasActiveElement = document.activeElement !== document.body
const msg = [
DOMEventCategory,
'target:',
e.target,
...(hasActiveElement
? ['active:', document.activeElement]
: []),
]
if (isActive) {
console.info(...msg)
}
},
true,
)
})
})
}
})
}
logBrowserEvents()
// export default logBrowserEvents
function bindAllEvents (el) {
for (const key in el) {
if (key.slice(0, 2) === 'on') {
el.addEventListener(key.slice(2), e => console.log(e.type));
}
}
}
bindAllEvents($('.yourElement'))
This uses a bit of ES6 for prettiness, but can easily be translated for legacy browsers as well. In the function attached to the event listeners, it's currently just logging out what kind of event occurred but this is where you could print out additional information, or using a switch case on the e.type, you could only print information on specific events
Here is a non-jquery way to monitor events in the console with your code and without the use of monitorEvents() because that only works in Chrome Developer Console. You can also choose to not monitor certain events by editing the no_watch array.
function getEvents(obj) {
window["events_list"] = [];
var no_watch = ['mouse', 'pointer']; // Array of event types not to watch
var no_watch_reg = new RegExp(no_watch.join("|"));
for (var prop in obj) {
if (prop.indexOf("on") === 0) {
prop = prop.substring(2); // remove "on" from beginning
if (!prop.match(no_watch_reg)) {
window["events_list"].push(prop);
window.addEventListener(prop, function() {
console.log(this.event); // Display fired event in console
} , false);
}
}
}
window["events_list"].sort(); // Alphabetical order
}
getEvents(document); // Put window, document or any html element here
console.log(events_list); // List every event on element
How to listen for all events on an Element (Vanilla JS)
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
const input = document.querySelector('input');
addEventListenerAll(input, (evt) => {
console.log(evt.type);
});
input.focus();
input.click();
input.dispatchEvent(new Event('omg!', { bubbles: true }));
// usage example with `useCapture`
// (also receives `bubbles: false` events, but in reverse order)
addEventListenerAll(
input,
(evt) => { console.log(evt.type); },
true
);
document.body.dispatchEvent(new Event('omfggg!', { bubbles: false }));

Jquery bind not working while within a javascript recursive loop

I am writing a piece of code that changes some lights on a screen from red to green randomly and waits for the user to hit the key that corresponds to the light lit.
When I run this code you are able to hit the a,d,j or l key and an alert will pop up. However, as soon as I click the start button no keys are recognised. And when the loop has finished the bind still seems to become disabled. I have tried moving the bind to other places but I have had no joy. Your help is much appreciated.
$( function() {
$('#start').bind('click', function() { main(); });
$(document).bind('keypress', function(e) { keyPress(e); } );
} );
function getRand(val) {
return Math.floor(Math.random()*val)+1;
}
function main() {
preD = new Date;
preDs = preD.getTime();
randTime=Math.floor(Math.random()*1001)+1500;
playSound();
flash();
}
function flash() {
zone = getZone();
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_grn.jpg)");
setTimeout(function() {
$('#r'+zone).css("background-image", "url(images/rea_red.jpg)");
if(cond[1] < 8) {
main();
}
} , 200);
} , randTime);
}
function getZone() {
if(condition==1) {
zone = getRand(2);
if( test[1][zone] < 8 ) {
test[1][zone] += 1;
cond[1] += 1;
return zone;
} else {
getZone();
}
}
}
function keyPress(e) {
var evtobj=window.event? event : e //distinguish between IE's explicit event object (window.event) and Firefox's implicit.
var unicode=evtobj.charCode? evtobj.charCode : evtobj.keyCode
var actualkey=String.fromCharCode(unicode)
if (actualkey=="a" || actualkey=="d" || actualkey=="j" || actualkey=="l" ) {
dd = new Date;
reat = dd.getTime();
alert(1);
//keypressed[condition][zone]['k']=actualkey;
//keypressed[condition][zone]['t']=(reat-preDs);
}
}
The reason that this could be happening is, when you generate code dynamically or alter any existing code the bind needs to be done again, because the function to bind just runs once and only for the members already created. So when you create dynamically code, you are forced to run the binding function to recognize the new elements.
this ways is not very recommended, instead of this, you could bind a container like 'div' or something and inside of this validate which element is calling you. This will work because your container is created once and the binding is properly assigned and doesn't matter if the content of your container changes, the binding always work.
Regards
Using a jquery sound plugin was the answer.
Fixed it with this : plugins.jquery.com/project/sound_plugin

Categories

Resources