Mouse Enter/Leave Polyfill for Chrome/Firefox - javascript

Is there a polyfill for the IE events mouseenter/mouseleave (or a conversion of the jQuery events) so it can be bound to raw JS events?
I.E. I is there a cross browser way to do this:
node.addEventListener('mouseenter', function() {
...
});
node.addEventListener('mouseleave', function() {
...
});
I know it should be possible custom events using:
var event = new Event('mouseenter');
node.addEventListener('mouseenter', function (e) { ... });
node.dispatchEvent(event);
etc

Ok, seems I figured out how to do it:
http://jsfiddle.net/HXwJH/5/
node.addEventListener('mouseover', function() {
if (!event.relatedTarget || (event.relatedTarget !== this && !(this.compareDocumentPosition(event.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY))) {
this.dispatchEvent(new Event('mouseenter'));
}
});
node.addEventListener('mouseout', function() {
if (!event.relatedTarget || (event.relatedTarget !== this && !(this.compareDocumentPosition(event.relatedTarget) & Node.DOCUMENT_POSITION_CONTAINED_BY))) {
this.dispatchEvent(new Event('mouseleave'));
}
});

Related

determine which event is currently triggered in jquery

if I'm fetching multiple events using jquery how can I determine which event is currently triggered so I can processed further, for example
$("#someId").on('paste blur', function (e) {
var data = '';
// if paste
data = e.originalEvent.clipboardData.getData('text')
// if blur
data = $("#someId").val();
});
You can use event.type to get the current event,
$("#someId").on('paste blur', function (e) {
if ('paste' == e.type) {
data = e.originalEvent.clipboardData.getData('text')
} else if ('blur' == e.type) {
data = $("#someId").val();
}
});
You can use Event.type.
$("#someId").on('paste blur', function (e) {
var data = '';
if(e.type == 'paste') {
data = e.originalEvent.clipboardData.getData('text')
}
if(e.type == 'blur') {
data = $("#someId").val();
}
});
You might wish to consider registering separate handlers depending on how different you're going to handle the events though.
To avoid unnecessary if conditions you can add only the events you actually needs:
// Bind up a couple of event handlers
$("#txt").on({
click: function() {
console.log("click")
},
mouseout: function() {
console.log("mouseout")
},
change: function() {
console.log("change")
}
});
//Lookup events for this particular Element
//prints out an object with all events on that element
console.log($._data($("#txt")[0], "events"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="txt" />

Javascript .one event equivalent? Need to check when first transform transitionEnd fires

Was wondering if there's a javascript .one equivalent? Basically I need to detect when my transform fires but only once, at the moment the transitionend event fires twice which is messing up my transitions. I was hoping to use the event.propertyName but this just reads 'transform' which doesn't help. Example snippet here:
loader.addEventListener("transitionend", function(event) {
console.log(event); // fires twice
//if (event.propertyName === 'transform') {
togglePages(page);
//}
}, false);
You can create one:
function one(element, eventName, callback) {
element.addEventListener(eventName, function handler(event) {
element.removeEventListener(eventName, handler);
callback(event);
});
}
Now you can do:
one(loader, "transitionend", function(event) {
console.log(event);
togglePages(page);
});
You can use a simple control variable:
var didHappen = false;
loader.addEventListener("transitionend", function(event) {
if (!didHappen) {
togglePages(page);
didHappen = true;
}
});
Try removeEventListener.
Example:
loader.addEventListener("transitionend",function transition(event) {
loader.removeEventListener("transitionend", transition, false);
//if (event.propertyName === 'transform') {
togglePages(page);
//}
}, false);
Or
var transition = function (event) {
loader.removeEventListener("transitionend", transition, false);
//if (event.propertyName === 'transform') {
togglePages(page);
//}
};
loader.addEventListener("transitionend", , false);

Custom "mouseenter" function doesn't fire

Here's the JSFiddle.
I'm trying to make mouseenter work on Chrome, Firefox, etc. using the following function:
var addMouseenter = (function () {
var contains = function (parent, elem) {
return parent.contains ? parent.contains(elem) :
!!(parent.compareDocumentPosition(elem) & 16);
},
wrap = function (elem, method) {
return function (e) {
if (elem === e.target && !contains(elem, e.relatedTarget)) {
method.call(elem, e);
}
};
};
return function (elem, listener) {
var listener2 = wrap(elem, listener);
elem.addEventListener('mouseover', listener2, false);
};
}());
Everything worked fine until I ran into this specific situation:
Element A has one of these custom mouseenter listeners
Element A contains Element B
Element B is right up against the edge of Element A
You enter Element A at that same edge
My expectation was that the mouseover event would be triggered on Element B and bubble up to Element A. However, that does not appear to be the case. I tested with Chrome 13 and Firefox 3.6 and got the same result. Did I mess something up?
If you don't oppose using jQuery:
$(document).ready(function() {
$('#first').mouseover(function (e) {
if ($(e.target).attr('id') != 'second') {
alert('hello');
}
});
});
Tried that in your JSFiddle and it works:
when you enter the green square it doesn't fire; when you enter red square from outside it fires; when you enter red square from green square it fires. That's what you wanted right?
new JSFiddle
Or keeping your javascript approach:
// Misc set-up stuff
var greet = function () { alert('Hi, my name is "' + this.id + '."'); },
first = document.getElementById('first'),
second = document.getElementById('second');
// The Actual Function
var addMouseenter = (function () {
var contains = function (parent, elem) {
return parent.contains ? parent.contains(elem) :
!!(parent.compareDocumentPosition(elem) & 16);
},
wrap = function (elem, method) {
return function (e) {
//if (elem === e.target && !contains(elem, e.relatedTarget)) {
if (elem === e.target && (e.target != second)) {
method.call(elem, e);
}
};
};
return function (elem, listener) {
var listener2 = wrap(elem, listener);
elem.addEventListener('mouseover', listener2, false);
};
}());
// GOGOGO
addMouseenter(first, greet);
http://jsfiddle.net/AUc88/
The reason my custom function wasn't firing is because it didn't work.
I updated the fiddle showing that all is as it should be.
My mistake was only checking to see if e.target was the same as the element I had attached the listener to. What I needed to be checking was if they were the same or if e.target was a child of the element.
When you mouse over the two squares really quickly, it only registers the mouseover event on the inner one, and because my listener was attached to the outer one, the elem === e.target test was failing.
So I changed the if code in the wrap function to this:
if ((elem === e.target || contains(elem, e.target)) &&
!contains(elem, e.relatedTarget)) {
e.stopPropagation();
method.call(elem, e);
}

How to detect if the event is a browser event or not

How would you test if an event is a browser event (e.g. click, load, blur etc) based on its name (e.g. click)? (and no I'm not using jQuery/mootools/prototype/dojo)
UPDATE:
In this function I attach browser events (click and load) for example:
observe: function(elements, eventName, callback) {
if (!(elements.length != null)) {
elements = [elements];
}
return this.each(elements, function(e) {
if (helper.hooks.eventObserved != null) {
helper.hooks.eventObserved(eventName, callback, e);
}
if (typeof e === 'string') {
e = this.el(e);
}
if (e.addEventListener) {
return e.addEventListener(eventName, callback, false);
} else if (e.attachEvent) {
return e.attachEvent("on" + eventName, callback);
}
});
},
And this fires the event:
fire: function(elements, eventName) {
if (!(elements.length != null)) {
elements = [elements];
}
return this.each(elements, function(e) {
var evt;
if (document.createEventObject != null) {
evt = document.createEventObject();
return e.fireEvent("on" + eventName);
} else {
evt = document.createEvent('HTMLEvents');
evt.initEvent(eventName, true, true);
return !e.dispatchEvent(evt);
}
});
},
But what I want is to test if the event exists for example click is a browser event but login isn't so how would I test that?
Check out this solution by Juriy Zaytsev (live demo).
jQuery itself uses it.
You could check to see if the function/object element["on"+event] exists:
test
<script>
function doesElementHaveEvent(element, event){
return (typeof element["on"+event] != typeof undefined);
}
alert(doesElementHaveEvent(document.getElementById("myAnchor"), "click")); // true
alert(doesElementHaveEvent(document.getElementById("myAnchor"), "login")); // false
</script>

Simulating "focus" and "blur" in jQuery .live() method

Update: As of jQuery 1.4, $.live() now supports focusin and focusout events.
jQuery currently1 doesn't support "blur" or "focus" as arguments for the $.live() method. What type of work-around could I implement to achieve the following:
$("textarea")
.live("focus", function() { foo = "bar"; })
.live("blur", function() { foo = "fizz"; });
1. 07/29/2009, version 1.3.2
Working solution:
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);
jQuery.event.special.focus = {
setup: function() {
var _self = this,
handler = function(e) {
e = jQuery.event.fix(e);
e.type = 'focus';
if (_self === document) {
jQuery.event.handle.call(_self, e);
}
};
jQuery(this).data(uid1, handler);
if (_self === document) {
/* Must be live() */
if (_self.addEventListener) {
_self.addEventListener('focus', handler, true);
} else {
_self.attachEvent('onfocusin', handler);
}
} else {
return false;
}
},
teardown: function() {
var handler = jQuery(this).data(uid1);
if (this === document) {
if (this.removeEventListener) {
this.removeEventListener('focus', handler, true);
} else {
this.detachEvent('onfocusin', handler);
}
}
}
};
jQuery.event.special.blur = {
setup: function() {
var _self = this,
handler = function(e) {
e = jQuery.event.fix(e);
e.type = 'blur';
if (_self === document) {
jQuery.event.handle.call(_self, e);
}
};
jQuery(this).data(uid2, handler);
if (_self === document) {
/* Must be live() */
if (_self.addEventListener) {
_self.addEventListener('blur', handler, true);
} else {
_self.attachEvent('onfocusout', handler);
}
} else {
return false;
}
},
teardown: function() {
var handler = jQuery(this).data(uid2);
if (this === document) {
if (this.removeEventListener) {
this.removeEventListener('blur', handler, true);
} else {
this.detachEvent('onfocusout', handler);
}
}
}
};
})();
Tested in IE/FF/Chrome. Should work exactly as you intended.
UPDATE: Teardowns now work.
This functionality is now included in jQuery core (as of 1.4.1).
live() is jQuery's shortcut to event delegation. To answer your question, see Delegating the focus and blur events.
It's pretty ingenious: for standards compliant browsers he uses event capturing to trap those events. For IE he uses IE's proprietary focusin (for focus) and focusout (for blur) events, which do bubble, allowing traditional event delegation.
I'll leave the porting of it to jQuery as an exercise.
they have been added on jquery 1.4.1 ... now .live() function supports fucus and blur events =) Greetings
Looks like the problem is when checking the event.type it returns "focusin" & "focusout"
$('input').live("focus blur", function(event){
if (event.type == "focusin") {
console.log(event.type);
}else{
console.log(event.type);
}
});
one more addition: this solution does not support more than one parameter.
i tried:
$(el).live("focus blur", function(e) {
if (e.type == "focus") {
etc.
and it only fired the blur event.
nevertheless this solution has been helpful.

Categories

Resources