Skip to content

Loading…

Add support for pointerenter/pointerleave events in IE10 #1338

Open
wants to merge 3 commits into from

5 participants

@src-code

Adding a few lines of code to add support for MSPointerEnter/MSPointerLeave in IE10, which is identical in function to mouseenter/mouseleave. The Pointer Events spec (implemented in IE11) offers native pointerenter/pointerleave, but there's a gap in support for IE10. To be consistent with the naming conventions used for pointer events in IE10, I've implemented this with the MSPointer* prefix and camel-casing.

Wasn't sure how to best manage the tests, so I just copied the existing mouseenter/mouseleave manual tests and modified them for MSPointerEnter/MSPointerLeave. Let me know if you'd like something else done there.

(@tilomitra, this is the PR I previously suggested to you over email.)

@tilomitra

Thanks @scarls13. I'll pull this in and try it out locally tomorrow, and offer some feedback.

@tilomitra

@scarls13 I just pulled this in and it looks good to me. :+1: from my end. We'll have to wait for a reviewer to sign off on this.

@lsmith lsmith commented on the diff
src/event/js/mouseentermouseleave.js
@@ -1,7 +1,8 @@
/**
* <p>Adds subscription and delegation support for mouseenter and mouseleave
- * events. Unlike mouseover and mouseout, these events aren't fired from child
- * elements of a subscribed node.</p>
+ * events, as well as MSPointerEnter and MSPointerLeave in IE10. Unlike mouseover and mouseout
@lsmith
lsmith added a note
Are these not supported in IE11? Specific browser versions in comments can be misleading once the noted version isn't the latest. They are appropriate if only the specified version is relevant.
@lsmith
lsmith added a note

It helps to read the pull request description. Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith lsmith commented on the diff
src/event/tests/manual/pointerenter.html
((51 lines not shown))
+ }
+
+ .outline,
+ .container ul li.outline {
+ border-color: #f00;
+ }
+
+ .container.focus {
+ background-color: blue;
+ }
+
+ </style>
+
+ <!--script src="/sand/delegate_leak_files/heapsize.js"></script-->
+ <script type="text/javascript" src="../../../../build/yui/yui.js"></script>
+ <!--script type="text/javascript" src="http://yui.yahooapis.com/3.3.0/build/yui/yui.js"></script-->
@lsmith
lsmith added a note

This is a pretty old template :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith lsmith commented on the diff
src/event/tests/manual/pointerenter.html
((53 lines not shown))
+ .outline,
+ .container ul li.outline {
+ border-color: #f00;
+ }
+
+ .container.focus {
+ background-color: blue;
+ }
+
+ </style>
+
+ <!--script src="/sand/delegate_leak_files/heapsize.js"></script-->
+ <script type="text/javascript" src="../../../../build/yui/yui.js"></script>
+ <!--script type="text/javascript" src="http://yui.yahooapis.com/3.3.0/build/yui/yui.js"></script-->
+
+ <script type="text/javascript">
@lsmith
lsmith added a note

type="text/javascript" is unnecessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith lsmith commented on the diff
src/event/tests/manual/pointerenter.html
((57 lines not shown))
+
+ .container.focus {
+ background-color: blue;
+ }
+
+ </style>
+
+ <!--script src="/sand/delegate_leak_files/heapsize.js"></script-->
+ <script type="text/javascript" src="../../../../build/yui/yui.js"></script>
+ <!--script type="text/javascript" src="http://yui.yahooapis.com/3.3.0/build/yui/yui.js"></script-->
+
+ <script type="text/javascript">
+ YUI({
+ //base: '../../../../build/',
+ filter: 'raw'
+ }).use('event-custom', 'event', 'node-style', function (Y) {
@lsmith
lsmith added a note

Better to use('event-mouseenter', ...) specifically to lessen the likelihood of contaminating the test env.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith lsmith commented on the diff
src/event/tests/manual/pointerenter.html
((167 lines not shown))
+ var handle9 = Y.delegate("MSPointerEnter", addLIOutline, "#container-1", "li", Y, "outline");
+ var handle10 = Y.delegate("MSPointerLeave", removeLIOutline, "#container-1", "li", "outline");
+
+
+ Y.on("click", function () {
+
+ handle1.detach();
+ handle2.detach();
+ handle3.detach();
+ handle4.detach();
+ handle5.detach();
+ handle6.detach();
+ handle7.detach();
+ handle8.detach();
+ handle9.detach();
+ handle10.detach();
@lsmith
lsmith added a note

Here's a fun trick:

var handles = new Y.EventHandle([
    Y.on("MSPointerEnter", onContainerMSPointerEnter, "#container-1"),
    Y.on("MSPointerLeave", onContainerMSPointerLeave, "#container-1"),
    ...
]);
...
Y.one('#remove-listeners').on('click', handles.detach, handles);
@juandopazo YUI Library member

O_O How is it that I've never seen this before?

@lsmith
lsmith added a note

It's a little trick I devised a couple years back. It's kind of a "clever" use of the API more so than using it how it's intended to be used, but it is convenient. Y.EventHandle wasn't really meant to be called by implementers directly. But eh :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith lsmith commented on an outdated diff
src/event/js/mouseentermouseleave.js
@@ -122,3 +123,15 @@ Y.Event.define("mouseleave", Y.merge(config, {
proxyType: "mouseout",
relProperty: "toElement"
}), true);
+
+// Add MSPointerEnter/MSPointerLeave for IE10.
+if (navigator.msPointerEnabled) {
@lsmith
lsmith added a note

I expect this will fail in node because it assumes global navigator object.

@lsmith
lsmith added a note

is navigator.msPointerEnabled true in IE11?

@src-code
src-code added a note

Actually yes, it is - I suppose I could do something like "navigator.msPointerEnabled && typeof !navigator.pointerEnabled" if we want to avoid creating these in IE11+…

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@lsmith

Heh, just noticed your note about copying existing mouseenter tests. Yes indeed, they are old :)

@lsmith

You can ignore all the manual test page comments, since they aren't your work.

The navigator conditional needs to be fixed to at least test typeof navigator === 'object' && navigator && ....

Otherwise, I'm not sure why preserve the camel casing of the event names if the spec uses lc, and IE11 has implemented them as such. If this is filling a gap, that gap is named "pointerenter". MSPointerEnter won't likely ever exist.

@lsmith lsmith commented on an outdated diff
src/event/js/mouseentermouseleave.js
@@ -122,3 +123,15 @@ Y.Event.define("mouseleave", Y.merge(config, {
proxyType: "mouseout",
relProperty: "toElement"
}), true);
+
+// Add MSPointerEnter/MSPointerLeave for IE10.
+if (navigator.msPointerEnabled) {
+ Y.Event.define("MSPointerEnter", Y.merge(config, {
+ proxyType: "MSPointerOver"
+ }), true);
@lsmith
lsmith added a note

Passing true as the third arg is only necessary if the event name is already whitelisted in Y.Node.DOM_EVENTS, which "MSPointerEnter" wouldn't be.

If the event name is changed to pointerenter, then it would make (some) sense to leave true here. But that would override the native behavior for pointerenter, deferring to the proxy event. This would be necessary for delegation, but not for direct subscription. I think this problem exists for mouseenter as well, so maybe it would be fine. Better to make the events smarter, but that's beyond the scope of this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@src-code

Hi @lsmith,
Regarding the naming convention, the reason I went with the MS-prefixed names is because I had a use case where I was programmatically determining which pointer events to bind based on browser support, and translating the names as needed. It made sense to me then that I'd want the naming convention to be consistent for a given browser, so I can translate more easily. I can see the argument though that you'd want to avoid defining MS-specific event names here, especially since they're non-standard. (Although this polyfill will never make sense outside of the context of IE10 anyway, so not sure what's gained by using the more standard "pointer*" naming convention.) Anyway, just to provide a bit more context into my thinking…

@triptych

@scarls13 are there more changes you plan to make with this - incorporating @lsmith 's comments?
@lsmith do you see any blockers for this PR to move forward?

@src-code

@triptych I'll go ahead and make the changes suggested by @lsmith if that's what you guys think is best (regarding the namespacing of the events for IE10). Let me know if you had any further thoughts on this.

@src-code

I went ahead and made the edits suggested by @lsmith, let me know if you think there's anything else that should be done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
View
3 src/event/HISTORY.md
@@ -4,7 +4,8 @@ Event Infrastructure Change History
@VERSION@
------
-* No changes.
+ * Added `MSPointerEnter`/`MSPointerLeave` events to support IE10. These events
+ behave in exactly the same manner as `mouseenter` and `mouseleave`.
3.13.0
------
View
17 src/event/js/mouseentermouseleave.js
@@ -1,7 +1,8 @@
/**
* <p>Adds subscription and delegation support for mouseenter and mouseleave
- * events. Unlike mouseover and mouseout, these events aren't fired from child
- * elements of a subscribed node.</p>
+ * events, as well as MSPointerEnter and MSPointerLeave in IE10. Unlike mouseover and mouseout
@lsmith
lsmith added a note
Are these not supported in IE11? Specific browser versions in comments can be misleading once the noted version isn't the latest. They are appropriate if only the specified version is relevant.
@lsmith
lsmith added a note

It helps to read the pull request description. Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ * or MSPointerOver and MSPointerOut, these events aren't fired from child elements of a subscribed
+ * node.</p>
*
* <p>This avoids receiving three mouseover notifications from a setup like</p>
*
@@ -122,3 +123,15 @@ Y.Event.define("mouseleave", Y.merge(config, {
proxyType: "mouseout",
relProperty: "toElement"
}), true);
+
+// Add pointerenter/pointerleave for IE10 only
+if (typeof navigator === 'object' && navigator.msPointerEnabled && !navigator.pointerEnabled) {
+ Y.Event.define("pointerenter", Y.merge(config, {
+ proxyType: "MSPointerOver"
+ }), true);
+ Y.Event.define("pointerleave", Y.merge(config, {
+ proxyType: "MSPointerOut",
+ relProperty: "toElement"
+ }), true);
+}
+
View
234 src/event/tests/manual/pointerenter.html
@@ -0,0 +1,234 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+
+<html lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>MSPointerEnter and MSPointerLeave Event Tests</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../build/cssreset/reset-min.css">
+ <link rel="stylesheet" type="text/css" href="../../../../build/cssbase/base-min.css">
+ <style type="text/css">
+
+ .container {
+ background-color: #ccc;
+ padding: 20px;
+ margin: 10px 0;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #ccc;
+ }
+
+ .container.hover {
+ background-color: #fc0;
+ }
+
+ .container ul {
+ list-style: none;
+ padding: 10px;
+ margin: 0;
+ background-color: #333;
+ }
+
+ .container ul li {
+ margin: 10px;
+ padding: 1px;
+ background-color: #999;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #999;
+ }
+
+ .container ul li.hover {
+ background-color: #ff6;
+ }
+
+ .container ul li em {
+ display: block;
+ margin: 10px;
+ padding: 5px;
+ background-color: #666;
+ }
+
+ .outline,
+ .container ul li.outline {
+ border-color: #f00;
+ }
+
+ .container.focus {
+ background-color: blue;
+ }
+
+ </style>
+
+ <!--script src="/sand/delegate_leak_files/heapsize.js"></script-->
+ <script type="text/javascript" src="../../../../build/yui/yui.js"></script>
+ <!--script type="text/javascript" src="http://yui.yahooapis.com/3.3.0/build/yui/yui.js"></script-->
@lsmith
lsmith added a note

This is a pretty old template :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ <script type="text/javascript">
@lsmith
lsmith added a note

type="text/javascript" is unnecessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ YUI({
+ //base: '../../../../build/',
+ filter: 'raw'
+ }).use('event-custom', 'event', 'node-style', function (Y) {
@lsmith
lsmith added a note

Better to use('event-mouseenter', ...) specifically to lessen the likelihood of contaminating the test env.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ /*
+ var count = 0;
+ Y.one = (function (original) {
+ return function () {
+ count++;
+ return original.apply(Y, arguments);
+ };
+ })(Y.one);
+ */
+
+ //var memsnap = trackMemory(Y);
+
+ var onContainerMSPointerEnter = function (event) {
+
+ if (event.currentTarget == this) {
+ this.addClass("hover");
+ }
+
+ };
+
+ var onContainerMSPointerLeave = function (event) {
+
+ if (event.currentTarget == this) {
+ this.removeClass("hover");
+ }
+
+ };
+
+ var onLIMSPointerEnter = function (event) {
+
+ if (event.container.get("id") == "container-1") {
+ this.addClass("hover");
+ }
+
+ };
+
+ var onLIMSPointerLeave = function (event) {
+
+ if (event.container.get("id") == "container-1") {
+ this.removeClass("hover");
+ }
+
+ };
+
+ var addContainerOutline = function (event, className) {
+
+ event.currentTarget.addClass(className);
+
+ };
+
+ var removeContainerOutline = function (event) {
+
+ event.currentTarget.removeClass(this);
+
+ };
+
+
+ var addLIOutline = function (event, className) {
+
+ event.currentTarget.addClass(className);
+
+ };
+
+ var removeLIOutline = function (event) {
+
+ event.currentTarget.removeClass(this);
+
+ };
+
+ var setLIColor = function (event) {
+
+ this.setStyle("color", "#fff");
+
+ };
+
+ var removeLIColor = function (event) {
+
+ this.setStyle("color", "");
+
+ };
+
+ var handle1 = Y.on("MSPointerEnter", onContainerMSPointerEnter, "#container-1");
+ var handle2 = Y.on("MSPointerLeave", onContainerMSPointerLeave, "#container-1");
+
+ var handle3 = Y.on("MSPointerEnter", addContainerOutline, "#container-1", Y, "outline");
+ var handle4 = Y.on("MSPointerLeave", removeContainerOutline, "#container-1", "outline");
+
+ var handle5 = Y.on("MSPointerEnter", setLIColor, "#container-1 li");
+ var handle6 = Y.on("MSPointerLeave", removeLIColor, "#container-1 li");
+
+ var handle7 = Y.delegate("MSPointerEnter", onLIMSPointerEnter, "#container-1", "li");
+ var handle8 = Y.delegate("MSPointerLeave", onLIMSPointerLeave, "#container-1", "li");
+
+ var handle9 = Y.delegate("MSPointerEnter", addLIOutline, "#container-1", "li", Y, "outline");
+ var handle10 = Y.delegate("MSPointerLeave", removeLIOutline, "#container-1", "li", "outline");
+
+
+ Y.on("click", function () {
+
+ handle1.detach();
+ handle2.detach();
+ handle3.detach();
+ handle4.detach();
+ handle5.detach();
+ handle6.detach();
+ handle7.detach();
+ handle8.detach();
+ handle9.detach();
+ handle10.detach();
@lsmith
lsmith added a note

Here's a fun trick:

var handles = new Y.EventHandle([
    Y.on("MSPointerEnter", onContainerMSPointerEnter, "#container-1"),
    Y.on("MSPointerLeave", onContainerMSPointerLeave, "#container-1"),
    ...
]);
...
Y.one('#remove-listeners').on('click', handles.detach, handles);
@juandopazo YUI Library member

O_O How is it that I've never seen this before?

@lsmith
lsmith added a note

It's a little trick I devised a couple years back. It's kind of a "clever" use of the API more so than using it how it's intended to be used, but it is convenient. Y.EventHandle wasn't really meant to be called by implementers directly. But eh :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ }, "#remove-listeners");
+
+ document.getElementById('memsize').onclick = function () {
+ //memsnap();
+ //console.log(count);
+ console.log(Y.Object.keys(Y.Node._instances).length);
+ };
+ });
+ </script>
+
+</head>
+<body>
+
+ <h1>MSPointerEnter and MSPointerLeave Event Tests</h1>
+
+ <ul>
+ <li>The background color of the <code>div</code> element should turn
+ orange and have a red outline when you move the mouse over it.</li>
+ <li>The background color of each <code>li</code> should change to yellow
+ when you mouse over it and have a red outline.</li>
+ </ul>
+
+ <div id="container-1" class="container">
+ <ul id="ul-1">
+ <li id="li1">
+ <p><span>This</span></p>
+ <p><em>is</em></p>
+ <p><strong>a</strong></p>
+ <p><q>bunch</q></p>
+ <blockquote><p>of</p></blockquote>
+ <div>
+ <div>
+ <div>
+ <div>
+ <p>paragraphs</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ <em id="em1">Item Type One</em>
+ </li>
+ <li id="li2"><em id="em2">Item Type Two</em></li>
+ <li id="li3"><em id="em3">Item Type Three</em></li>
+ </ul>
+ </div>
+
+ <button id="remove-listeners">Remove Listeners</button>
+ <button id="memsize">Check memory</button>
+
+</body>
+</html>
View
198 src/event/tests/manual/pointerenter2.html
@@ -0,0 +1,198 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+
+<html lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>MSPointerEnter and MSPointerLeave Event Tests</title>
+
+ <link rel="stylesheet" type="text/css" href="../../../../build/reset/reset-min.css">
+ <link rel="stylesheet" type="text/css" href="../../../../build/base/base-min.css">
+
+ <style type="text/css">
+
+ .container {
+ background-color: #ccc;
+ padding: 20px;
+ margin: 10px 0;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #ccc;
+ }
+
+ .container.hover {
+ background-color: #fc0;
+ }
+
+ .container ul {
+ list-style: none;
+ padding: 10px;
+ margin: 0;
+ background-color: #333;
+ }
+
+ .container ul li {
+ margin: 10px;
+ padding: 1px;
+ background-color: #999;
+ border-width: 1px;
+ border-style: solid;
+ border-color: #999;
+ }
+
+ .container ul li.hover {
+ background-color: #ff6;
+ }
+
+ .container ul li em {
+ display: block;
+ margin: 10px;
+ padding: 5px;
+ background-color: #666;
+ }
+
+ .outline,
+ .container ul li.outline {
+ border-color: #f00;
+ }
+
+ .container.focus {
+ background-color: blue;
+ }
+
+ </style>
+
+</head>
+<body>
+
+ <h1>MSPointerEnter and MSPointerLeave Event Tests</h1>
+
+ <ul>
+ <li>The background color of the <code>div</code> element should turn
+ orange and have a red outline when you move the mouse over it.</li>
+ <li>The background color of each <code>li</code> should change to yellow
+ when you mouse over it and have a red outline.</li>
+ </ul>
+
+ <script type="text/javascript" src="../../../../build/yui/yui.js"></script>
+
+ <script type="text/javascript">
+ YUI({
+ lazyEventFacade: true
+ }).use('event', 'node-style', function (Y) {
+
+ // Build the content via a timer to test Event's mechanism to
+ // defer the attachment of listeners until they are available
+ // in the DOM
+
+ Y.Lang.later(3000, Y, function () {
+ Y.one('body').append('<div id="container-1" class="container"><ul id="ul-1"><li><em>Item Type One</em></li><li><em>Item Type Two</em></li><li><em>Item Type Three</em></li></ul></div><button id="remove-listeners">Remove Listeners</button>');
+ });
+
+
+ var onContainerMSPointerEnter = function (event) {
+
+ if (event.currentTarget == this) {
+ this.addClass("hover");
+ }
+
+ };
+
+ var onContainerMSPointerLeave = function (event) {
+
+ if (event.currentTarget == this) {
+ this.removeClass("hover");
+ }
+
+ };
+
+ var onLIMSPointerEnter = function (event) {
+
+ if (event.container.get("id") == "container-1") {
+ this.addClass("hover");
+ }
+
+ };
+
+ var onLIMSPointerLeave = function (event) {
+
+ if (event.container.get("id") == "container-1") {
+ this.removeClass("hover");
+ }
+
+ };
+
+ var addContainerOutline = function (event, className) {
+
+ event.currentTarget.addClass(className);
+
+ };
+
+ var removeContainerOutline = function (event) {
+
+ event.currentTarget.removeClass(this);
+
+ };
+
+
+ var addLIOutline = function (event, className) {
+
+ event.currentTarget.addClass(className);
+
+ };
+
+ var removeLIOutline = function (event) {
+
+ event.currentTarget.removeClass(this);
+
+ };
+
+ var setLIColor = function (event) {
+
+ this.setStyle("color", "#fff");
+
+ };
+
+ var removeLIColor = function (event) {
+
+ this.setStyle("color", "");
+
+ };
+
+ var handle1 = Y.on("MSPointerEnter", onContainerMSPointerEnter, "#container-1");
+ var handle2 = Y.on("MSPointerLeave", onContainerMSPointerLeave, "#container-1");
+
+ var handle3 = Y.on("MSPointerEnter", addContainerOutline, "#container-1", Y, "outline");
+ var handle4 = Y.on("MSPointerLeave", removeContainerOutline, "#container-1", "outline");
+
+ var handle5 = Y.on("MSPointerEnter", setLIColor, "#container-1 li");
+ var handle6 = Y.on("MSPointerLeave", removeLIColor, "#container-1 li");
+
+ var handle7 = Y.delegate("MSPointerEnter", onLIMSPointerEnter, "#container-1", "li");
+ var handle8 = Y.delegate("MSPointerLeave", onLIMSPointerLeave, "#container-1", "li");
+
+ var handle9 = Y.delegate("MSPointerEnter", addLIOutline, "#container-1", "li", Y, "outline");
+ var handle10 = Y.delegate("MSPointerLeave", removeLIOutline, "#container-1", "li", "outline");
+
+
+ Y.on("click", function () {
+
+ handle1.detach();
+ handle2.detach();
+ handle3.detach();
+ handle4.detach();
+ handle5.detach();
+ handle6.detach();
+ handle7.detach();
+ handle8.detach();
+ handle9.detach();
+ handle10.detach();
+
+ }, "#remove-listeners");
+
+ });
+
+ </script>
+
+</body>
+</html>
Something went wrong with that request. Please try again.