Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/twbs/mq4-hover-shim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Rebert <github@rebertia.com>2015-01-10 00:15:18 +0300
committerChris Rebert <github@rebertia.com>2015-01-10 00:15:18 +0300
commit705395ece0251ab09ae432c75b0cb15b48e81a95 (patch)
treee21a9be0aa6776cbc3d3d0a378c37a08910174dd
parentead19f2517d55627186fb766dcf40935eae8434c (diff)
parent507566200dcd9221a1cb109878c9837e0376b4c8 (diff)
Merge pull request #6 from cvrebert/events
Listen for dynamic changes to media query results
-rw-r--r--Gruntfile.js5
-rw-r--r--README.md17
-rw-r--r--src/browser/mq4-hover-hover-shim.js116
3 files changed, 106 insertions, 32 deletions
diff --git a/Gruntfile.js b/Gruntfile.js
index 3c2343a..52c0a25 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -32,7 +32,8 @@ module.exports = function (grunt) {
options: {
banner: '<%= banner %>',
browserifyOptions: {
- standalone: 'mq4HoverShim'
+ standalone: 'mq4HoverShim',
+ bundleExternal: false
}
},
dist: {
@@ -59,7 +60,7 @@ module.exports = function (grunt) {
src: '<%= jshint.gruntfile.src %>'
},
lib: {
- src: '<%= jshint.lib.src %>'
+ src: ['src/**/*.js', '!src/browser/mq4-hover-hover-shim.js']
},
test: {
src: '<%= jshint.test.src %>'
diff --git a/README.md b/README.md
index 09dc745..1a1f863 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,10 @@ Obviously, this requires JavaScript to be enabled in the browser, and would defa
[hover-pseudo]: https://developer.mozilla.org/en-US/docs/Web/CSS/:hover
+## Client-side dependencies
+
+The browser-side portion of the shim depends on jQuery for firing events. Pull requests to add support for other browser event libraries would be welcomed.
+
## Browser compatibility
The following is a summary of the results of testing the library in various browsers. [Try out the Live Testcase](http://jsfiddle.net/cvrhulu/5vszkpmg/).
@@ -103,10 +107,21 @@ The module exports one public function:
* Arguments: none
* Side-effects: none
* Return type: `boolean`
- * Returns a `boolean` value indicating if the browser's primary pointer supports true hovering or if the browser at least does not try to quirkily emulate hovering, such that [`:hover`](hover-pseudo) CSS styles are appropriate.
+ * Returns a `boolean` value indicating if the browser's primary pointer currently supports true hovering or if the browser at least does not try to quirkily emulate hovering, such that [`:hover`](hover-pseudo) CSS styles are appropriate.
* In other words, returns `true` if `@media (hover: hover)` would evaluate to `true` were the browser to natively correctly implement Media Queries Level 4; otherwise, returns `false`.
* If the browser does not natively support the `hover` media feature, but does support touch via some pointing input device, then we define this touch-based pointer to be the "primary pointer". Hence, if said browser has multiple pointing input devices, one supporting touch and another supporting true hovering (e.g. the computer has both a mouse and a touchscreen), this function will return `false`, since the user could use the touch input device at any time and since `:hover` should only be used for progressive enhancement anyway.
+The module has one public event:
+* Event name: `mq4hsChange`
+ * Fired whenever the primary pointer's support for true hovering changes.
+ * This may be due to a different pointer becoming the primary pointer, although that's not the only possible cause.
+ * This event isn't fired merely if a different pointer becomes the primary pointer. The new primary pointer must also differ from the old primary pointer in its support for true hovering. For example, switching from one mouse to another mouse, or from one touchscreen to another touchscreen won't cause this event to fire.
+ * Target: the `document` object
+ * Extra properties:
+ * `canTrulyHover`
+ * Type: `boolean`
+ * Value: Same as `supportsTrueHover()`'s return value at the time of firing the event
+
## Grunt
Use [grunt-postcss](https://github.com/nDmitry/grunt-postcss) to invoke the mq4-hover-hover-shim CSS postprocessor via [Grunt](http://gruntjs.com/) task.
diff --git a/src/browser/mq4-hover-hover-shim.js b/src/browser/mq4-hover-hover-shim.js
index 654141d..c0a7129 100644
--- a/src/browser/mq4-hover-hover-shim.js
+++ b/src/browser/mq4-hover-hover-shim.js
@@ -1,14 +1,37 @@
/*eslint-env browser */
/* jshint browser: true, esnext: true */
+/* jshint -W080 */
+/**
+* @module mq4HoverShim
+* @requires jquery
+*/
+let $ = (function () {
+ try {
+ import * as jQuery from 'jquery';
+ return jQuery;
+ }
+ catch (importErr) {
+ const globaljQuery = window.$ || window.jQuery || window.Zepto;
+ if (!globaljQuery) {
+ throw new Error('mq4HoverShim needs jQuery (or similar)');
+ }
+ return globaljQuery;
+ }
+})();
+
+/** @type {boolean|undefined} */
+let canTrulyHover = undefined;
/**
-* Does this UA's primary pointer support true hovering
-* OR does the UA at least not try to quirkily emulate hovering,
-* such that :hover CSS styles are appropriate?
-* Essentially tries to shim the `@media (hover: hover)` CSS media query feature.
-* @type {boolean}
+* @private
+* @fires mq4HoverShim#mq4hsChange
*/
-export function supportsTrueHover() {
+function triggerEvent() {
+ $(document).trigger($.Event('mq4hsChange', {bubbles: false, trueHover: canTrulyHover}));
+}
+
+// IIFE so we can use `return`s to avoid deeply-nested if-s
+(function () {
if (!window.matchMedia) {
// Opera Mini, IE<=9, Android<=2.3, ancient, or obscure; per http://caniuse.com/#feat=matchmedia
@@ -22,49 +45,84 @@ export function supportsTrueHover() {
// IE Mobile <9 seems to always have "Windows CE", "Windows Phone", or "IEMobile" in its UA string.
// IE Mobile 9 in desktop view doesn't include "IEMobile" or "Windows Phone" in the UA string,
// but it instead includes "XBLWP7" and/or "ZuneWP7".
- return !/Opera Mini|Android|IEMobile|Windows (Phone|CE)|(XBL|Zune)WP7/.test(navigator.userAgent);
+ canTrulyHover = !/Opera Mini|Android|IEMobile|Windows (Phone|CE)|(XBL|Zune)WP7/.test(navigator.userAgent);
+
+ // Since there won't be any event handlers to fire our events, do the one-and-only firing of it here and now.
+ triggerEvent();
+ return;
}
// CSSWG Media Queries Level 4 draft
// http://drafts.csswg.org/mediaqueries/#hover
- if (window.matchMedia(
- '(hover: none),(-moz-hover: none),(-ms-hover: none),(-webkit-hover: none),' +
- '(hover: on-demand),(-moz-hover: on-demand),(-ms-hover: on-demand),(-webkit-hover: on-demand)'
- ).matches) {
- // true hovering explicitly not supported by primary pointer
- return false;
- }
- if (window.matchMedia('(hover: hover),(-moz-hover: hover),(-ms-hover: hover),(-webkit-hover: hover)').matches) {
- // true hovering explicitly supported by primary pointer
- return true;
+ const HOVER_NONE = '(hover: none),(-moz-hover: none),(-ms-hover: none),(-webkit-hover: none)';
+ const HOVER_ON_DEMAND = '(hover: on-demand),(-moz-hover: on-demand),(-ms-hover: on-demand),(-webkit-hover: on-demand)';
+ const HOVER_HOVER = '(hover: hover),(-moz-hover: hover),(-ms-hover: hover),(-webkit-hover: hover)';
+ if (window.matchMedia(`${HOVER_NONE},${HOVER_ON_DEMAND},${HOVER_HOVER}`).matches) {
+ // Browser understands the `hover` media feature
+ const hoverCallback = function (mql) {
+ const doesMatch = mql.matches;
+ if (doesMatch !== canTrulyHover) {
+ canTrulyHover = doesMatch;
+ triggerEvent();
+ }
+ };
+ const atHoverQuery = window.matchMedia(HOVER_HOVER);
+ atHoverQuery.addListener(hoverCallback);
+ hoverCallback(atHoverQuery);
+ return;
}
- // `hover` media feature not implemented by this browser; keep probing
+ // Check for touch support instead.
// Touch generally implies that hovering is merely emulated,
// which doesn't count as true hovering support for our purposes
// due to the quirkiness of the emulation (e.g. :hover being sticky).
- // W3C Pointer Events LC WD, 13 November 2014
- // http://www.w3.org/TR/2014/WD-pointerevents-20141113/
+ // W3C Pointer Events PR, 16 December 2014
+ // http://www.w3.org/TR/2014/PR-pointerevents-20141216/
// Prefixed in IE10, per http://caniuse.com/#feat=pointer
- const supportsPointerEvents = window.PointerEvent || window.MSPointerEvent;
- if (supportsPointerEvents) {
- const pointerEventsIsTouch = (window.navigator.maxTouchPoints || window.navigator.msMaxTouchPoints) > 0;
- return !pointerEventsIsTouch;
+ if (window.PointerEvent || window.MSPointerEvent) {
+ // Browser supports Pointer Events
+
+ // Browser supports touch if it has touch points
+ /* jshint -W018 */
+ canTrulyHover = !((window.navigator.maxTouchPoints || window.navigator.msMaxTouchPoints) > 0);
+ /* jshint +W018 */
+ triggerEvent();
+ return;
}
// Mozilla's -moz-touch-enabled
// https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Media_queries#-moz-touch-enabled
- if (window.matchMedia('(touch-enabled),(-moz-touch-enabled),(-ms-touch-enabled),(-webkit-touch-enabled)').matches) {
- return false;
+ const touchEnabledQuery = window.matchMedia('(touch-enabled),(-moz-touch-enabled),(-ms-touch-enabled),(-webkit-touch-enabled)');
+ if (touchEnabledQuery.matches) {
+ canTrulyHover = false;
+ triggerEvent();
+ return;
}
- // W3C Touch Events
+ // W3C Touch Events REC, 10 October 2013
// http://www.w3.org/TR/2013/REC-touch-events-20131010/
if ('ontouchstart' in window) {
- return false;
+ canTrulyHover = false;
+ triggerEvent();
+ return;
}
// UA's pointer is non-touch and thus likely either supports true hovering or at least does not try to emulate it.
- return true;
+ canTrulyHover = true;
+ triggerEvent();
+})();
+
+
+/**
+* Does this UA's primary pointer support true hovering
+* OR does the UA at least not try to quirkily emulate hovering,
+* such that :hover CSS styles are appropriate?
+* Essentially tries to shim the `@media (hover: hover)` CSS media query feature.
+* @public
+* @returns {boolean}
+* @since 0.0.1
+*/
+export function supportsTrueHover() {
+ return canTrulyHover;
}