diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 86f7b40..0000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,14 +0,0 @@
-module.exports = {
- env: {
- browser: true,
- es6: true,
- commonjs: true
- },
- extends: 'eslint:recommended',
- rules: {
- quotes: ['error', 'single']
- },
- parserOptions: {
- sourceType: 'module'
- }
-}
diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 0000000..a278c2f
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,14 @@
+{
+ "env": {
+ "browser": true,
+ "es6": true,
+ "amd": true,
+ "commonjs": true
+ },
+ "extends": "eslint:recommended",
+ "rules": {
+ "indent": ["error", 2],
+ "quotes": ["error", "single"],
+ "no-extra-semi": "off"
+ }
+}
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..df64aa5
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,2 @@
+ko_fi: surunzi
+open_collective: eruda
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..d47b285
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,27 @@
+name: CI
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - 'master'
+ paths:
+ - 'src/**/*'
+
+jobs:
+ ci:
+
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [16.x]
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v2
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: npm i
+ - run: npm run ci
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..2712ef8
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,28 @@
+name: Publish to NPM
+
+on:
+ workflow_dispatch:
+ release:
+ types: [created]
+
+jobs:
+ publish:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Setup Node
+ uses: actions/setup-node@v2
+ with:
+ node-version: '18.x'
+ registry-url: 'https://registry.npmjs.org'
+ - name: Build eruda-features
+ run: |
+ npm i
+ npm run build
+ - name: Publish package on NPM
+ run: npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f55876c..b0ec138 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
/node_modules/
eruda-features.js
-eruda-features.js.map
\ No newline at end of file
+eruda-features.js.map
+package-lock.json
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..99955c6
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1 @@
+/src/modernizr.js
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f83a29..f161751 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## v2.1.0 (5 Aug 2024)
+
+* feat: remove html5test link
+
## v2.0.0 (5 Jan 2020)
* feat: theme support
\ No newline at end of file
diff --git a/README.md b/README.md
index b94c6ac..832b448 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
# eruda-features
[![NPM version][npm-image]][npm-url]
-[![Build status][travis-image]][travis-url]
+[![Build status][ci-image]][ci-url]
[![License][license-image]][npm-url]
[npm-image]: https://img.shields.io/npm/v/eruda-features.svg
[npm-url]: https://npmjs.org/package/eruda-features
-[travis-image]: https://img.shields.io/travis/liriliri/eruda-features.svg
-[travis-url]: https://travis-ci.org/liriliri/eruda-features
+[ci-image]: https://img.shields.io/github/actions/workflow/status/liriliri/eruda-features/main.yml?branch=master&style=flat-square
+[ci-url]: https://github.com/liriliri/eruda-features/actions/workflows/main.yml
[license-image]: https://img.shields.io/npm/l/eruda-features.svg
Eruda plugin for browser feature detections, thanks to [modernizr](https://github.com/Modernizr/Modernizr) project.
@@ -17,7 +17,7 @@ Red means unsupported, otherwise ok. All buttons is linked directly to related m
## Demo
Browse it on your phone:
-[http://eruda.liriliri.io/](http://eruda.liriliri.io/)
+[https://eruda.liriliri.io/?plugin=features](https://eruda.liriliri.io/?plugin=features)
## Install
diff --git a/package.json b/package.json
index 1ba5409..3b80a10 100644
--- a/package.json
+++ b/package.json
@@ -1,19 +1,24 @@
{
"name": "eruda-features",
- "version": "2.0.0",
- "description": "Eruda plugin for browser feature detections",
+ "version": "2.1.0",
"main": "eruda-features.js",
+ "description": "Eruda plugin for browser feature detections",
+ "browserslist": [
+ "since 2015",
+ "not dead"
+ ],
+ "files": [
+ "eruda-features.js",
+ "eruda-features.js.map"
+ ],
"scripts": {
- "dev": "webpack-dev-server --host 0.0.0.0",
- "build": "webpack && webpack -p",
- "ci": "npm run lint && npm run build",
+ "dev": "webpack-dev-server --host 0.0.0.0 --mode development",
+ "build": "webpack --mode production",
+ "ci": "npm run lint && npm run build && npm run es5",
"lint": "eslint src/**/*.js",
- "format": "prettier src/index.js src/style.scss *.js .*.js --write",
- "buildModernizr": "node script/buildModernizr"
- },
- "repository": {
- "type": "git",
- "url": "git+https://github.com/liriliri/eruda-features.git"
+ "format": "lsla prettier \"src/*.{js,scss}\" \"*.json\" --write",
+ "buildModernizr": "node script/buildModernizr",
+ "es5": "es-check es5 eruda-features.js"
},
"keywords": [
"eruda",
@@ -27,24 +32,24 @@
},
"homepage": "https://github.com/liriliri/eruda-features#readme",
"devDependencies": {
- "autoprefixer": "^7.2.2",
- "babel-core": "^6.26.0",
- "babel-loader": "^7.1.2",
- "babel-plugin-transform-runtime": "^6.23.0",
- "babel-preset-env": "^1.6.1",
- "css-loader": "^0.28.7",
- "eruda": "^2.0.0",
- "eslint": "^6.8.0",
- "handlebars": "^4.0.11",
- "handlebars-loader": "^1.6.0",
- "modernizr": "^3.5.0",
- "node-sass": "^4.7.2",
- "postcss": "^6.0.14",
+ "@babel/core": "^7.21.3",
+ "@babel/plugin-transform-runtime": "^7.21.0",
+ "@babel/preset-env": "^7.20.2",
+ "autoprefixer": "^10.4.14",
+ "babel-loader": "^9.1.2",
+ "css-loader": "^3.4.2",
+ "eruda": "^3.2.0",
+ "es-check": "^7.2.1",
+ "eslint": "^8.57.0",
+ "licia": "^1.41.1",
+ "modernizr": "^3.13.0",
+ "postcss": "^8.4.21",
"postcss-class-prefix": "^0.3.0",
- "postcss-loader": "^2.0.9",
- "prettier": "^1.19.1",
- "sass-loader": "^6.0.6",
- "webpack": "^3.10.0",
- "webpack-dev-server": "^2.9.7"
+ "postcss-loader": "^7.0.2",
+ "sass": "^1.77.8",
+ "sass-loader": "^14.2.1",
+ "webpack": "^5.93.0",
+ "webpack-cli": "^5.1.4",
+ "webpack-dev-server": "^4.12.0"
}
}
diff --git a/src/index.js b/src/index.js
index 90b3cef..c390d57 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,11 +1,12 @@
-import modernizr from './modernizr'
+const map = require('licia/map')
+const modernizr = require('./modernizr')
let featureList = require('../script/featureList.json')
let featureNames = featureList['feature-detects'],
specialNames = featureList['special-names']
-module.exports = function(eruda) {
+module.exports = function (eruda) {
let { evalCss } = eruda.util
class Features extends eruda.Tool {
@@ -14,14 +15,9 @@ module.exports = function(eruda) {
this.name = 'features'
this._style = evalCss(require('./style.scss'))
- this._tpl = require('./template.hbs')
this._features = {}
this._isInit = false
}
- init($el, container) {
- super.init($el, container)
- $el.html(require('./template.hbs')())
- }
show() {
super.show()
@@ -42,11 +38,11 @@ module.exports = function(eruda) {
let i = 0,
featureNum = featureNames.length
- featureNames.forEach(feature => {
+ featureNames.forEach((feature) => {
if (specialNames[feature]) feature = specialNames[feature]
feature = feature.replace(/\//g, '')
- modernizr.on(feature, result => {
+ modernizr.on(feature, (result) => {
this._features[feature] = result
i++
if (i === featureNum) this._render()
@@ -54,7 +50,17 @@ module.exports = function(eruda) {
})
}
_render() {
- this._$el.html(this._tpl({ features: this._features }))
+ const features = map(this._features, (feature, key) => {
+ const ok = feature ? 'eruda-ok' : ''
+
+ return `
+
+ ${key}
+
+ `
+ }).join('')
+ const html = ``
+ this._$el.html(html)
}
}
diff --git a/src/modernizr.js b/src/modernizr.js
index 1061cc5..641cea0 100644
--- a/src/modernizr.js
+++ b/src/modernizr.js
@@ -1,5 +1,5 @@
/*!
- * modernizr v3.5.0
+ * modernizr v3.13.0
* Build https://modernizr.com/download?-audio-bloburls-boxshadow-boxsizing-canvas-cookies-cssanimations-csscalc-csstransforms-csstransforms3d-csstransitions-datauri-fetch-filereader-filesystem-flexbox-fullscreen-geolocation-hashchange-history-indexeddb-json-localstorage-notification-performance-placeholder-pointerevents-promises-queryselector-scriptasync-scriptdefer-serviceworker-sessionstorage-stylescoped-svg-templatestrings-touchevents-typedarrays-video-webgl-webp-webpalpha-websockets-websqldatabase-xhr2-dontmin
*
* Copyright (c)
@@ -10,6 +10,7 @@
* Patrick Kettner
* Stu Cox
* Richard Herrera
+ * Veeck
* MIT License
*/
@@ -22,21 +23,19 @@
* of control over the experience.
*/
+;(function(scriptGlobalObject, window, document, undefined){
var tests = [];
/**
- *
* ModernizrProto is the constructor for Modernizr
*
* @class
* @access public
*/
-
var ModernizrProto = {
- // The current version, dummy
- _version: '3.5.0',
+ _version: '3.13.0',
// Any settings that don't work as separate modules
// can go in here as configuration.
@@ -95,20 +94,20 @@
* @function is
* @param {*} obj - A thing we want to check the type of
* @param {string} type - A string to compare the typeof against
- * @returns {boolean}
+ * @returns {boolean} true if the typeof the first parameter is exactly the specified type, false otherwise
*/
-
function is(obj, type) {
return typeof obj === type;
}
+
;
/**
* Run through all tests and detect their support in the current UA.
*
* @access private
+ * @returns {void}
*/
-
function testRunner() {
var featureNames;
var feature;
@@ -143,7 +142,6 @@
// Run the test, or use the raw value if it's not a function
result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
-
// Set each of the names on the Modernizr object
for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
featureName = featureNames[nameIdx];
@@ -158,8 +156,8 @@
if (featureNameSplit.length === 1) {
Modernizr[featureNameSplit[0]] = result;
} else {
- // cast to a Boolean, if not one already
- if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
+ // cast to a Boolean, if not one already or if it doesnt exist yet (like inputtypes)
+ if (!Modernizr[featureNameSplit[0]] || Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
}
@@ -179,7 +177,6 @@
* @access private
* @returns {HTMLElement|SVGElement} The root element of the document
*/
-
var docElement = document.documentElement;
@@ -189,8 +186,8 @@
* @access private
* @returns {boolean}
*/
-
var isSVG = docElement.nodeName.toLowerCase() === 'svg';
+
/**
@@ -203,7 +200,6 @@
* @function createElement
* @returns {HTMLElement|SVGElement} An HTML or SVG element
*/
-
function createElement() {
if (typeof document.createElement !== 'function') {
// This is the case in IE7, where the type of createElement is "object".
@@ -219,52 +215,61 @@
;
/*!
{
- "name" : "HTML5 Audio Element",
+ "name": "HTML5 Audio Element",
"property": "audio",
- "tags" : ["html5", "audio", "media"]
+ "caniuse": "audio",
+ "tags": ["html5", "audio", "media"],
+ "notes": [{
+ "name": "MDN Docs",
+ "href": "https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements"
+ }]
}
!*/
/* DOC
-Detects the audio element
+Detects support of the audio element, as well as testing what types of content it supports.
+
+Subproperties are provided to describe support for `ogg`, `mp3`,`opus`, `wav` and `m4a` formats, e.g.:
+
+```javascript
+Modernizr.audio // true
+Modernizr.audio.ogg // 'probably'
+```
*/
- // This tests evaluates support of the audio element, as well as
- // testing what types of content it supports.
- //
- // We're using the Boolean constructor here, so that we can extend the value
- // e.g. Modernizr.audio // true
- // Modernizr.audio.ogg // 'probably'
- //
// Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
// thx to NielsLeenheer and zcorpan
// Note: in some older browsers, "no" was a return value instead of empty string.
// It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
// It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
- Modernizr.addTest('audio', function() {
+ (function() {
var elem = createElement('audio');
- var bool = false;
+ Modernizr.addTest('audio', function() {
+ var bool = false;
+ try {
+ bool = !!elem.canPlayType;
+ if (bool) {
+ bool = new Boolean(bool);
+ }
+ } catch (e) {}
+
+ return bool;
+ });
+
+ // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
try {
- bool = !!elem.canPlayType
- if (bool) {
- bool = new Boolean(bool);
- bool.ogg = elem.canPlayType('audio/ogg; codecs="vorbis"') .replace(/^no$/, '');
- bool.mp3 = elem.canPlayType('audio/mpeg; codecs="mp3"') .replace(/^no$/, '');
- bool.opus = elem.canPlayType('audio/ogg; codecs="opus"') ||
- elem.canPlayType('audio/webm; codecs="opus"') .replace(/^no$/, '');
-
- // Mimetypes accepted:
- // developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
- // bit.ly/iphoneoscodecs
- bool.wav = elem.canPlayType('audio/wav; codecs="1"') .replace(/^no$/, '');
- bool.m4a = (elem.canPlayType('audio/x-m4a;') ||
- elem.canPlayType('audio/aac;')) .replace(/^no$/, '');
+ if (!!elem.canPlayType) {
+ Modernizr.addTest('audio.ogg', elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''));
+ Modernizr.addTest('audio.mp3', elem.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/, ''));
+ Modernizr.addTest('audio.opus', elem.canPlayType('audio/ogg; codecs="opus"') ||
+ elem.canPlayType('audio/webm; codecs="opus"').replace(/^no$/, ''));
+ Modernizr.addTest('audio.wav', elem.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''));
+ Modernizr.addTest('audio.m4a', (elem.canPlayType('audio/x-m4a;') ||
+ elem.canPlayType('audio/aac;')).replace(/^no$/, ''));
}
- } catch (e) { }
-
- return bool;
- });
+ } catch (e) {}
+ })();
/*!
{
@@ -314,7 +319,7 @@ Detects whether cookie support is enabled.
try {
// Create cookie
document.cookie = 'cookietest=1';
- var ret = document.cookie.indexOf('cookietest=') != -1;
+ var ret = document.cookie.indexOf('cookietest=') !== -1;
// Delete cookie
document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
return ret;
@@ -330,17 +335,16 @@ Detects whether cookie support is enabled.
* elem.style.WebkitBorderRadius
* instead of something like the following (which is technically incorrect):
* elem.style.webkitBorderRadius
-
+ *
* WebKit ghosts their properties in lowercase but Opera & Moz do not.
* Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
* erik.eae.net/archives/2008/03/10/21.48.10/
-
+ *
* More here: github.com/Modernizr/Modernizr/issues/issue/21
*
* @access private
* @returns {string} The string representing the vendor-specific style properties
*/
-
var omPrefixes = 'Moz O ms Webkit';
@@ -348,7 +352,6 @@ Detects whether cookie support is enabled.
ModernizrProto._cssomPrefixes = cssomPrefixes;
-
/**
* contains checks to see if a string contains another string
*
@@ -356,9 +359,8 @@ Detects whether cookie support is enabled.
* @function contains
* @param {string} str - The string we want to check for substrings
* @param {string} substr - The substring we want to search the first string for
- * @returns {boolean}
+ * @returns {boolean} true if and only if the first string 'str' contains the second string 'substr'
*/
-
function contains(str, substr) {
return !!~('' + str).indexOf(substr);
}
@@ -370,7 +372,6 @@ Detects whether cookie support is enabled.
*
* @access private
*/
-
var modElem = {
elem: createElement('modernizr')
};
@@ -403,7 +404,6 @@ Detects whether cookie support is enabled.
* @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
* artificially created element that stands in for the body
*/
-
function getBody() {
// After page load injecting a fake body doesn't work so check if body exists
var body = document.body;
@@ -425,12 +425,11 @@ Detects whether cookie support is enabled.
* @access private
* @function injectElementWithStyles
* @param {string} rule - String representing a css rule
- * @param {function} callback - A function that is used to test the injected element
+ * @param {Function} callback - A function that is used to test the injected element
* @param {number} [nodes] - An integer representing the number of additional nodes you want injected
* @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
- * @returns {boolean}
+ * @returns {boolean} the result of the specified callback test
*/
-
function injectElementWithStyles(rule, callback, nodes, testnames) {
var mod = 'modernizr';
var style;
@@ -478,7 +477,7 @@ Detects whether cookie support is enabled.
ret = callback(div, rule);
// If this is done after page load we don't want to remove the body so check if body exists
- if (body.fake) {
+ if (body.fake && body.parentNode) {
body.parentNode.removeChild(body);
docElement.style.overflow = docOverflow;
// Trigger layout so kinetic scrolling isn't disabled in iOS6+
@@ -489,26 +488,25 @@ Detects whether cookie support is enabled.
}
return !!ret;
-
}
;
/**
- * domToCSS takes a camelCase string and converts it to kebab-case
+ * domToCSS takes a camelCase string and converts it to hyphen-case
* e.g. boxSizing -> box-sizing
*
* @access private
* @function domToCSS
* @param {string} name - String name of camelCase prop we want to convert
- * @returns {string} The kebab-case version of the supplied name
+ * @returns {string} The hyphen-case version of the supplied name
*/
-
function domToCSS(name) {
return name.replace(/([A-Z])/g, function(str, m1) {
return '-' + m1.toLowerCase();
}).replace(/^ms-/, '-ms-');
}
+
;
@@ -518,11 +516,11 @@ Detects whether cookie support is enabled.
*
* @access private
* @function computedStyle
- * @param {HTMLElement|SVGElement} - The element we want to find the computed styles of
- * @param {string|null} [pseudoSelector]- An optional pseudo element selector (e.g. :before), of null if none
- * @returns {CSSStyleDeclaration}
+ * @param {HTMLElement|SVGElement} elem - The element we want to find the computed styles of
+ * @param {string|null} [pseudo] - An optional pseudo element selector (e.g. :before), of null if none
+ * @param {string} prop - A CSS property
+ * @returns {CSSStyleDeclaration} the value of the specified CSS property
*/
-
function computedStyle(elem, pseudo, prop) {
var result;
@@ -555,16 +553,15 @@ Detects whether cookie support is enabled.
*
* @access private
* @function nativeTestProps
- * @param {array} props - An array of property names
+ * @param {Array} props - An array of property names
* @param {string} value - A string representing the value we want to check via @supports
* @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
*/
-
// Accepts a list of property names and a single value
// Returns `undefined` if native detection not available
function nativeTestProps(props, value) {
var i = props.length;
- // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
+ // Start with the JS API: https://www.w3.org/TR/css3-conditional/#the-css-interface
if ('CSS' in window && 'supports' in window.CSS) {
// Try every prefixed variant of the property
while (i--) {
@@ -583,7 +580,7 @@ Detects whether cookie support is enabled.
}
conditionText = conditionText.join(' or ');
return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
- return computedStyle(node, null, 'position') == 'absolute';
+ return computedStyle(node, null, 'position') === 'absolute';
});
}
return undefined;
@@ -591,20 +588,20 @@ Detects whether cookie support is enabled.
;
/**
- * cssToDOM takes a kebab-case string and converts it to camelCase
+ * cssToDOM takes a hyphen-case string and converts it to camelCase
* e.g. box-sizing -> boxSizing
*
* @access private
* @function cssToDOM
- * @param {string} name - String name of kebab-case prop we want to convert
+ * @param {string} name - String name of hyphen-case prop we want to convert
* @returns {string} The camelCase version of the supplied name
*/
-
function cssToDOM(name) {
return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
return m1 + m2.toUpperCase();
}).replace(/^-/, '');
}
+
;
// testProps is a generic CSS / DOM property test.
@@ -618,7 +615,7 @@ Detects whether cookie support is enabled.
// on our modernizr element, but instead just testing undefined vs
// empty string.
- // Property names can be provided in either camelCase or kebab-case.
+ // Property names can be provided in either camelCase or hyphen-case.
function testProps(props, prefixed, value, skipValueTest) {
skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
@@ -635,12 +632,12 @@ Detects whether cookie support is enabled.
var afterInit, i, propsLength, prop, before;
// If we don't have a style element, that means we're running async or after
- // the core tests, so we'll need to create our own elements to use
+ // the core tests, so we'll need to create our own elements to use.
- // inside of an SVG element, in certain browsers, the `style` element is only
+ // Inside of an SVG element, in certain browsers, the `style` element is only
// defined for valid tags. Therefore, if `modernizr` does not have one, we
// fall back to a less used element and hope for the best.
- // for strict XHTML browsers the hardly used samp element is used
+ // For strict XHTML browsers the hardly used samp element is used.
var elems = ['modernizr', 'tspan', 'samp'];
while (!mStyle.style && elems.length) {
afterInit = true;
@@ -682,16 +679,16 @@ Detects whether cookie support is enabled.
// supported. If `value` is empty string, it'll fail here (because
// it hasn't changed), which matches how browsers have implemented
// CSS.supports()
- if (mStyle.style[prop] != before) {
+ if (mStyle.style[prop] !== before) {
cleanElems();
- return prefixed == 'pfx' ? prop : true;
+ return prefixed === 'pfx' ? prop : true;
}
}
// Otherwise just return true, or the property name if this is a
// `prefixed()` call
else {
cleanElems();
- return prefixed == 'pfx' ? prop : true;
+ return prefixed === 'pfx' ? prop : true;
}
}
}
@@ -704,7 +701,7 @@ Detects whether cookie support is enabled.
/**
* List of JavaScript DOM values used for tests
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr._domPrefixes
* @optionName Modernizr._domPrefixes
* @optionProp domPrefixes
@@ -712,13 +709,12 @@ Detects whether cookie support is enabled.
* @example
*
* Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
- * than kebab-case properties, all properties are their Capitalized variant
+ * than hyphen-case properties, all properties are their Capitalized variant
*
* ```js
* Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
* ```
*/
-
var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
ModernizrProto._domPrefixes = domPrefixes;
@@ -728,11 +724,10 @@ Detects whether cookie support is enabled.
*
* @access private
* @function fnBind
- * @param {function} fn - a function you want to change `this` reference to
+ * @param {Function} fn - a function you want to change `this` reference to
* @param {object} that - the `this` you want to call the function with
- * @returns {function} The wrapped version of the supplied function
+ * @returns {Function} The wrapped version of the supplied function
*/
-
function fnBind(fn, that) {
return function() {
return fn.apply(that, arguments);
@@ -747,10 +742,10 @@ Detects whether cookie support is enabled.
*
* @access private
* @function testDOMProps
- * @param {array.} props - An array of properties to test for
+ * @param {Array} props - An array of properties to test for
* @param {object} obj - An object or Element you want to use to test the parameters again
* @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
- * @returns {false|*} returns false if the prop is unsupported, otherwise the value that is supported
+ * @returns {boolean|*} returns `false` if the prop is unsupported, otherwise the value that is supported
*/
function testDOMProps(props, obj, elem) {
var item;
@@ -767,7 +762,7 @@ Detects whether cookie support is enabled.
// let's bind a function
if (is(item, 'function')) {
- // bind to obj unless overriden
+ // bind to obj unless overridden
return fnBind(item, elem || obj);
}
@@ -793,7 +788,7 @@ Detects whether cookie support is enabled.
* @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
* @param {string} [value] - A string of a css value
* @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
- * @returns {false|string} returns the string version of the property, or false if it is unsupported
+ * @returns {string|boolean} returns the string version of the property, or `false` if it is unsupported
*/
function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
@@ -823,15 +818,16 @@ Detects whether cookie support is enabled.
/**
* testAllProps determines whether a given CSS property is supported in the browser
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr.testAllProps
* @optionName Modernizr.testAllProps()
* @optionProp testAllProps
* @access public
* @function testAllProps
- * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
+ * @param {string} prop - String naming the property to test (either camelCase or hyphen-case)
* @param {string} [value] - String of the value to test
* @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
+ * @returns {string|boolean} returns the string version of the property, or `false` if it is unsupported
* @example
*
* testAllProps determines whether a given CSS property, in some prefixed form,
@@ -856,11 +852,12 @@ Detects whether cookie support is enabled.
* testAllProps('shapeOutside', 'content-box', true);
* ```
*/
-
function testAllProps(prop, value, skipValueTest) {
return testPropsAll(prop, undefined, undefined, value, skipValueTest);
}
+
ModernizrProto.testAllProps = testAllProps;
+
/*!
{
@@ -871,8 +868,8 @@ Detects whether cookie support is enabled.
"tags": ["css"],
"warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
"notes": [{
- "name" : "Article: 'Dispelling the Android CSS animation myths'",
- "href": "https://goo.gl/OGw5Gm"
+ "name": "Article: 'Dispelling the Android CSS animation myths'",
+ "href": "https://web.archive.org/web/20180602074607/https://daneden.me/2011/12/14/putting-up-with-androids-bullshit/"
}]
}
!*/
@@ -908,7 +905,7 @@ Detects whether or not elements can be animated using CSS
"notes": [{
"name": "MDN Docs",
"href": "https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing"
- },{
+ }, {
"name": "Related Github Issue",
"href": "https://github.com/Modernizr/Modernizr/issues/248"
}]
@@ -920,9 +917,9 @@ Detects whether or not elements can be animated using CSS
/**
* List of property values to set for css tests. See ticket #21
- * http://git.io/vUGl4
+ * https://github.com/modernizr/modernizr/issues/21
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr._prefixes
* @optionName Modernizr._prefixes
* @optionProp prefixes
@@ -931,7 +928,7 @@ Detects whether or not elements can be animated using CSS
*
* Modernizr._prefixes is the internal list of prefixes that we test against
* inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
- * an array of kebab-case vendor prefixes you can use within your code.
+ * an array of hyphen-case vendor prefixes you can use within your code.
*
* Some common use cases include
*
@@ -949,7 +946,6 @@ Detects whether or not elements can be animated using CSS
* rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
* ```
*/
-
// we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
// values in feature detects to continue to work
var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
@@ -996,7 +992,7 @@ Method of allowing calculated values for length units. For example:
"tags": ["css"],
"notes": [{
"name": "The _new_ flexbox",
- "href": "http://dev.w3.org/csswg/css3-flexbox"
+ "href": "https://www.w3.org/TR/css-flexbox-1/"
}],
"warnings": [
"A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
@@ -1019,72 +1015,12 @@ Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows
!*/
Modernizr.addTest('csstransforms', function() {
- // Android < 3.0 is buggy, so we sniff and blacklist
- // http://git.io/hHzL7w
+ // Android < 3.0 is buggy, so we sniff and reject it
+ // https://github.com/Modernizr/Modernizr/issues/903
return navigator.userAgent.indexOf('Android 2.') === -1 &&
testAllProps('transform', 'scale(1)', true);
});
-
- /**
- * testStyles injects an element with style element and some CSS rules
- *
- * @memberof Modernizr
- * @name Modernizr.testStyles
- * @optionName Modernizr.testStyles()
- * @optionProp testStyles
- * @access public
- * @function testStyles
- * @param {string} rule - String representing a css rule
- * @param {function} callback - A function that is used to test the injected element
- * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
- * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
- * @returns {boolean}
- * @example
- *
- * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
- * along with (possibly multiple) DOM elements. This lets you check for features
- * that can not be detected by simply checking the [IDL](https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Interface_development_guide/IDL_interface_rules).
- *
- * ```js
- * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
- * // elem is the first DOM node in the page (by default #modernizr)
- * // rule is the first argument you supplied - the CSS rule in string form
- *
- * addTest('widthworks', elem.style.width === '9px')
- * });
- * ```
- *
- * If your test requires multiple nodes, you can include a third argument
- * indicating how many additional div elements to include on the page. The
- * additional nodes are injected as children of the `elem` that is returned as
- * the first argument to the callback.
- *
- * ```js
- * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
- * document.getElementById('modernizr').style.width === '1px'; // true
- * document.getElementById('modernizr2').style.width === '2px'; // true
- * elem.firstChild === document.getElementById('modernizr2'); // true
- * }, 1);
- * ```
- *
- * By default, all of the additional elements have an ID of `modernizr[n]`, where
- * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
- * the second additional is `#modernizr3`, etc.).
- * If you want to have more meaningful IDs for your function, you can provide
- * them as the fourth argument, as an array of strings
- *
- * ```js
- * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
- * elem.firstChild === document.getElementById('foo'); // true
- * elem.lastChild === document.getElementById('bar'); // true
- * }, 2, ['foo', 'bar']);
- * ```
- *
- */
-
- var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
-
/*!
{
"name": "CSS Supports",
@@ -1093,14 +1029,14 @@ Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows
"tags": ["css"],
"builderAliases": ["css_supports"],
"notes": [{
- "name": "W3 Spec",
- "href": "http://dev.w3.org/csswg/css3-conditional/#at-supports"
- },{
+ "name": "W3C Spec (The @supports rule)",
+ "href": "https://dev.w3.org/csswg/css3-conditional/#at-supports"
+ }, {
"name": "Related Github Issue",
"href": "https://github.com/Modernizr/Modernizr/issues/648"
- },{
- "name": "W3 Info",
- "href": "http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
+ }, {
+ "name": "W3C Spec (The CSSSupportsRule interface)",
+ "href": "https://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
}]
}
!*/
@@ -1116,42 +1052,13 @@ Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows
"caniuse": "transforms3d",
"tags": ["css"],
"warnings": [
- "Chrome may occassionally fail this test on some systems; more info: https://code.google.com/p/chromium/issues/detail?id=129004"
+ "Chrome may occasionally fail this test on some systems; more info: https://bugs.chromium.org/p/chromium/issues/detail?id=129004"
]
}
!*/
Modernizr.addTest('csstransforms3d', function() {
- var ret = !!testAllProps('perspective', '1px', true);
- var usePrefix = Modernizr._config.usePrefixes;
-
- // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
- // It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
- // some conditions. As a result, Webkit typically recognizes the syntax but
- // will sometimes throw a false positive, thus we must do a more thorough check:
- if (ret && (!usePrefix || 'webkitPerspective' in docElement.style)) {
- var mq;
- var defaultStyle = '#modernizr{width:0;height:0}';
- // Use CSS Conditional Rules if available
- if (Modernizr.supports) {
- mq = '@supports (perspective: 1px)';
- } else {
- // Otherwise, Webkit allows this media query to succeed only if the feature is enabled.
- // `@media (transform-3d),(-webkit-transform-3d){ ... }`
- mq = '@media (transform-3d)';
- if (usePrefix) {
- mq += ',(-webkit-transform-3d)';
- }
- }
-
- mq += '{#modernizr{width:7px;height:18px;margin:0;padding:0;border:0}}';
-
- testStyles(defaultStyle + mq, function(elem) {
- ret = elem.offsetWidth === 7 && elem.offsetHeight === 18;
- });
- }
-
- return ret;
+ return !!testAllProps('perspective', '1px', true);
});
/*!
@@ -1176,12 +1083,12 @@ Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows
"notes": [{
"name": "The ES6 promises spec",
"href": "https://github.com/domenic/promises-unwrapping"
- },{
+ }, {
"name": "Chromium dashboard - ES6 Promises",
"href": "https://www.chromestatus.com/features/5681726336532480"
- },{
- "name": "JavaScript Promises: There and back again - HTML5 Rocks",
- "href": "http://www.html5rocks.com/en/tutorials/es6/promises/"
+ }, {
+ "name": "JavaScript Promises: an Introduction",
+ "href": "https://developers.google.com/web/fundamentals/primers/promises/"
}]
}
!*/
@@ -1212,7 +1119,7 @@ Check if browser implements ECMAScript 6 Promises per specification.
"property": "filereader",
"caniuse": "fileapi",
"notes": [{
- "name": "W3C Working Draft",
+ "name": "W3C Working Draft Spec",
"href": "https://www.w3.org/TR/FileAPI/"
}],
"tags": ["file"],
@@ -1235,7 +1142,7 @@ to be the File object's prototype.)
* atRule returns a given CSS property at-rule (eg @keyframes), possibly in
* some prefixed form, or false, in the case of an unsupported rule
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr.atRule
* @optionName Modernizr.atRule()
* @optionProp atRule
@@ -1255,9 +1162,7 @@ to be the File object's prototype.)
* // keyframes === `false`
* }
* ```
- *
*/
-
var atRule = function(prop) {
var length = prefixes.length;
var cssrule = window.CSSRule;
@@ -1301,7 +1206,7 @@ to be the File object's prototype.)
/**
* prefixed returns the prefixed or nonprefixed property name variant of your input
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr.prefixed
* @optionName Modernizr.prefixed()
* @optionProp prefixed
@@ -1310,12 +1215,12 @@ to be the File object's prototype.)
* @param {string} prop - String name of the property to test for
* @param {object} [obj] - An object to test for the prefixed properties on
* @param {HTMLElement} [elem] - An element used to test specific properties against
- * @returns {string|false} The string representing the (possibly prefixed) valid
+ * @returns {string|boolean} The string representing the (possibly prefixed) valid
* version of the property, or `false` when it is unsupported.
* @example
*
* Modernizr.prefixed takes a string css value in the DOM style camelCase (as
- * opposed to the css style kebab-case) form and returns the (possibly prefixed)
+ * opposed to the css style hyphen-case) form and returns the (possibly prefixed)
* version of that property that the browser actually supports.
*
* For example, in older Firefox...
@@ -1360,16 +1265,15 @@ to be the File object's prototype.)
* var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
* ```
*
- * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
+ * If you want a similar lookup, but in hyphen-case, you can use [prefixedCSS](#modernizr-prefixedcss).
*/
-
var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
if (prop.indexOf('@') === 0) {
return atRule(prop);
}
- if (prop.indexOf('-') != -1) {
- // Convert kebab-case to camelCase
+ if (prop.indexOf('-') !== -1) {
+ // Convert hyphen-case to camelCase
prop = cssToDOM(prop);
}
if (!obj) {
@@ -1387,8 +1291,8 @@ to be the File object's prototype.)
"property": "filesystem",
"caniuse": "filesystem",
"notes": [{
- "name": "W3 Draft",
- "href": "http://dev.w3.org/2009/dap/file-system/file-dir-sys.html"
+ "name": "W3C Spec",
+ "href": "https://www.w3.org/TR/file-system-api/"
}],
"authors": ["Eric Bidelman (@ebidel)"],
"tags": ["file"],
@@ -1419,7 +1323,7 @@ Tests for placeholder attribute in inputs and textareas
"property": "fullscreen",
"caniuse": "fullscreen",
"notes": [{
- "name": "MDN documentation",
+ "name": "MDN Docs",
"href": "https://developer.mozilla.org/en/API/Fullscreen"
}],
"polyfills": ["screenfulljs"],
@@ -1440,7 +1344,7 @@ Detects support for the ability to make the current website take over the user's
"caniuse": "geolocation",
"tags": ["media"],
"notes": [{
- "name": "MDN documentation",
+ "name": "MDN Docs",
"href": "https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation"
}],
"polyfills": [
@@ -1471,14 +1375,14 @@ Detects support for the Geolocation API for users to provide their location to w
/**
* Modernizr.hasEvent() detects support for a given event
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr.hasEvent
* @optionName Modernizr.hasEvent()
* @optionProp hasEvent
* @access public
* @function hasEvent
- * @param {string|*} eventName - the name of an event to test for (e.g. "resize")
- * @param {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
+ * @param {string|*} eventName - the name of an event to test for (e.g. "resize")
+ * @param {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
* @returns {boolean}
* @example
* `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
@@ -1494,14 +1398,12 @@ Detects support for the Geolocation API for users to provide their location to w
* ```js
* hasEvent('devicelight', window) // true;
* ```
- *
*/
-
var hasEvent = (function() {
// Detect whether event support can be detected via `in`. Test on a DOM element
// using the "blur" event b/c it should always exist. bit.ly/event-detection
- var needsFallback = !('onblur' in document.documentElement);
+ var needsFallback = !('onblur' in docElement);
function inner(eventName, element) {
@@ -1540,7 +1442,6 @@ Detects support for the Geolocation API for users to provide their location to w
return inner;
})();
-
ModernizrProto.hasEvent = hasEvent;
/*!
@@ -1550,8 +1451,8 @@ Detects support for the Geolocation API for users to provide their location to w
"caniuse": "hashchange",
"tags": ["history"],
"notes": [{
- "name": "MDN documentation",
- "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.onhashchange"
+ "name": "MDN Docs",
+ "href": "https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange"
}],
"polyfills": [
"jquery-hashchange",
@@ -1587,7 +1488,7 @@ Detects support for the `hashchange` event, fired when the current location frag
"name": "W3C Spec",
"href": "https://www.w3.org/TR/html51/browsers.html#the-history-interface"
}, {
- "name": "MDN documentation",
+ "name": "MDN Docs",
"href": "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
}],
"polyfills": ["historyjs", "html5historyapi"]
@@ -1603,6 +1504,12 @@ Detects support for the History API for manipulating the browser session history
// Unfortunately support is really buggy and there is no clean way to detect
// these bugs, so we fall back to a user agent sniff :(
var ua = navigator.userAgent;
+
+ // Some browsers allow to have empty userAgent.
+ // Therefore, we need to check ua before using "indexOf" on it.
+ if(!ua) {
+ return false;
+ }
// We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
// itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
@@ -1663,7 +1570,6 @@ Detects support for the History API for manipulating the browser session history
* @function setClasses
* @param {string[]} classes - Array of class names
*/
-
// Pass in an and array of class names, e.g.:
// ['no-webp', 'borderradius', ...]
function setClasses(classes) {
@@ -1683,20 +1589,21 @@ Detects support for the History API for manipulating the browser session history
if (Modernizr._config.enableClasses) {
// Add the new classes
- className += ' ' + classPrefix + classes.join(' ' + classPrefix);
+ if (classes.length > 0) {
+ className += ' ' + classPrefix + classes.join(' ' + classPrefix);
+ }
if (isSVG) {
docElement.className.baseVal = className;
} else {
docElement.className = className;
}
}
-
}
;
- // _l tracks listeners for async tests, as well as tests that execute after the initial run
+ // _l tracks listeners for async tests, as well as tests that execute after the initial run
ModernizrProto._l = {};
/**
@@ -1704,12 +1611,13 @@ Detects support for the History API for manipulating the browser session history
* asynchronous, they may not finish before your scripts run. As a result you
* will get a possibly false negative `undefined` value.
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr.on
* @access public
* @function on
* @param {string} feature - String name of the feature detect
- * @param {function} cb - Callback function returning a Boolean - true if feature is supported, false if not
+ * @param {Function} cb - Callback function returning a Boolean - true if feature is supported, false if not
+ * @returns {void}
* @example
*
* ```js
@@ -1722,7 +1630,6 @@ Detects support for the History API for manipulating the browser session history
* });
* ```
*/
-
ModernizrProto.on = function(feature, cb) {
// Create the list of listeners if it doesn't exist
if (!this._l[feature]) {
@@ -1745,15 +1652,15 @@ Detects support for the History API for manipulating the browser session history
* _trigger is the private function used to signal test completion and run any
* callbacks registered through [Modernizr.on](#modernizr-on)
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr._trigger
* @access private
* @function _trigger
* @param {string} feature - string name of the feature detect
- * @param {function|boolean} [res] - A feature detection function, or the boolean =
+ * @param {Function|boolean} [res] - A feature detection function, or the boolean =
* result of a feature detection function
+ * @returns {void}
*/
-
ModernizrProto._trigger = function(feature, res) {
if (!this._l[feature]) {
return;
@@ -1777,11 +1684,12 @@ Detects support for the History API for manipulating the browser session history
/**
* addTest allows you to define your own feature detects that are not currently
* included in Modernizr (under the covers it's the exact same code Modernizr
- * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)). Just like the offical detects, the result
+ * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)).
+ * Just like the official detects, the result
* will be added onto the Modernizr object, as well as an appropriate className set on
* the html element when configured to do so
*
- * @memberof Modernizr
+ * @memberOf Modernizr
* @name Modernizr.addTest
* @optionName Modernizr.addTest()
* @optionProp addTest
@@ -1789,8 +1697,9 @@ Detects support for the History API for manipulating the browser session history
* @function addTest
* @param {string|object} feature - The string name of the feature detect, or an
* object of feature detect names and test
- * @param {function|boolean} test - Function returning true if feature is supported,
+ * @param {Function|boolean} test - Function returning true if feature is supported,
* false if not. Otherwise a boolean representing the results of a feature detection
+ * @returns {object} the Modernizr object to allow chaining
* @example
*
* The most common way of creating your own feature detects is by calling
@@ -1815,7 +1724,7 @@ Detects support for the History API for manipulating the browser session history
* in a statement that will return a boolean value works just fine.
*
* ```js
- * Modernizr.addTest('hasJquery', 'jQuery' in window);
+ * Modernizr.addTest('hasjquery', 'jQuery' in window);
* ```
*
* Just like before, when the above runs `Modernizr.hasjquery` will be true if
@@ -1842,10 +1751,9 @@ Detects support for the History API for manipulating the browser session history
* There is really no difference between the first methods and this one, it is
* just a convenience to let you write more readable code.
*/
-
function addTest(feature, test) {
- if (typeof feature == 'object') {
+ if (typeof feature === 'object') {
for (var key in feature) {
if (hasOwnProp(feature, key)) {
addTest(key, feature[ key ]);
@@ -1858,11 +1766,11 @@ Detects support for the History API for manipulating the browser session history
var last = Modernizr[featureNameSplit[0]];
// Again, we don't check for parent test existence. Get that right, though.
- if (featureNameSplit.length == 2) {
+ if (featureNameSplit.length === 2) {
last = last[featureNameSplit[1]];
}
- if (typeof last != 'undefined') {
+ if (typeof last !== 'undefined') {
// we're going to quit if you're trying to overwrite an existing test
// if we were to allow it, we'd do this:
// var re = new RegExp("\\b(no-)?" + feature + "\\b");
@@ -1871,10 +1779,10 @@ Detects support for the History API for manipulating the browser session history
return Modernizr;
}
- test = typeof test == 'function' ? test() : test;
+ test = typeof test === 'function' ? test() : test;
// Set the value (this is the magic, right here).
- if (featureNameSplit.length == 1) {
+ if (featureNameSplit.length === 1) {
Modernizr[featureNameSplit[0]] = test;
} else {
// cast to a Boolean, if not one already
@@ -1886,7 +1794,7 @@ Detects support for the History API for manipulating the browser session history
}
// Set a single class (either `feature` or `no-feature`)
- setClasses([(!!test && test != false ? '' : 'no-') + featureNameSplit.join('-')]);
+ setClasses([(!!test && test !== false ? '' : 'no-') + featureNameSplit.join('-')]);
// Trigger the event
Modernizr._trigger(feature, test);
@@ -1907,6 +1815,7 @@ Detects support for the History API for manipulating the browser session history
"name": "Webp",
"async": true,
"property": "webp",
+ "caniuse": "webp",
"tags": ["image"],
"builderAliases": ["img_webp"],
"authors": ["Krister Kari", "@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
@@ -1914,16 +1823,16 @@ Detects support for the History API for manipulating the browser session history
"name": "Webp Info",
"href": "https://developers.google.com/speed/webp/"
}, {
- "name": "Chormium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
+ "name": "Chromium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
"href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
}, {
"name": "Webp Lossless Spec",
"href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
}, {
- "name": "Article about WebP support on Android browsers",
- "href": "http://www.wope-framework.com/en/2013/06/24/webp-support-on-android-browsers/"
+ "name": "Article about WebP support",
+ "href": "https://optimus.keycdn.com/support/webp-support/"
}, {
- "name": "Chormium WebP announcement",
+ "name": "Chromium WebP announcement",
"href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
}]
}
@@ -1964,13 +1873,13 @@ Tests for all forms of webp support (lossless, lossy, alpha, and animated)..
function addResult(event) {
// if the event is from 'onload', check the see if the image's width is
- // 1 pixel (which indiciates support). otherwise, it fails
+ // 1 pixel (which indicates support). otherwise, it fails
- var result = event && event.type === 'load' ? image.width == 1 : false;
+ var result = event && event.type === 'load' ? image.width === 1 : false;
var baseTest = name === 'webp';
// if it is the base test, and the result is false, just set a literal false
- // rather than use the Boolean contrsuctor
+ // rather than use the Boolean constructor
addTest(name, (baseTest && result) ? new Boolean(result) : result);
if (cb) {
@@ -2008,10 +1917,10 @@ Tests for all forms of webp support (lossless, lossy, alpha, and animated)..
"notes": [{
"name": "WebP Info",
"href": "https://developers.google.com/speed/webp/"
- },{
- "name": "Article about WebP support on Android browsers",
- "href": "http://www.wope-framework.com/en/2013/06/24/webp-support-on-android-browsers/"
- },{
+ }, {
+ "name": "Article about WebP support",
+ "href": "https://optimus.keycdn.com/support/webp-support/"
+ }, {
"name": "Chromium WebP announcement",
"href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
}]
@@ -2029,7 +1938,7 @@ Tests for transparent webp support.
};
image.onload = function() {
- addTest('webpalpha', image.width == 1, {aliases: ['webp-alpha']});
+ addTest('webpalpha', image.width === 1, {aliases: ['webp-alpha']});
};
image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==';
@@ -2064,13 +1973,20 @@ Detects support for the IndexedDB client-side storage API (final spec).
} catch (e) {
}
- if (!!indexeddb) {
+ if (indexeddb) {
var testDBName = 'modernizr-' + Math.random();
- var req = indexeddb.open(testDBName);
+ var req;
+ try {
+ req = indexeddb.open(testDBName);
+ } catch (e) {
+ addTest('indexeddb', false);
+ return;
+ }
- req.onerror = function() {
- if (req.error && req.error.name === 'InvalidStateError') {
+ req.onerror = function(event) {
+ if (req.error && (req.error.name === 'InvalidStateError' || req.error.name === 'UnknownError')) {
addTest('indexeddb', false);
+ event.preventDefault();
} else {
addTest('indexeddb', true);
detectDeleteDatabase(indexeddb, testDBName);
@@ -2103,7 +2019,7 @@ Detects support for the IndexedDB client-side storage API (final spec).
"property": "json",
"caniuse": "json",
"notes": [{
- "name": "MDN documentation",
+ "name": "MDN Docs",
"href": "https://developer.mozilla.org/en-US/docs/Glossary/JSON"
}],
"polyfills": ["json2"]
@@ -2125,7 +2041,7 @@ Detects native support for JSON handling functions.
"tags": ["network"],
"caniuse": "fetch",
"notes": [{
- "name": "Fetch Living Standard",
+ "name": "WHATWG Spec",
"href": "https://fetch.spec.whatwg.org/"
}],
"polyfills": ["fetch"]
@@ -2141,12 +2057,13 @@ Detects support for the fetch API, a modern replacement for XMLHttpRequest.
{
"name": "XML HTTP Request Level 2 XHR2",
"property": "xhr2",
+ "caniuse": "xhr2",
"tags": ["network"],
"builderAliases": ["network_xhr2"],
"notes": [{
- "name": "W3 Spec",
+ "name": "W3C Spec",
"href": "https://www.w3.org/TR/XMLHttpRequest2/"
- },{
+ }, {
"name": "Details on Related Github Issue",
"href": "https://github.com/Modernizr/Modernizr/issues/385"
}]
@@ -2168,18 +2085,16 @@ Tests for XHR2.
"caniuse": "notifications",
"authors": ["Theodoor van Donge", "Hendrik Beskow"],
"notes": [{
- "name": "HTML5 Rocks tutorial",
- "href": "http://www.html5rocks.com/en/tutorials/notifications/quick/"
- },{
- "name": "W3C spec",
+ "name": "HTML5 Rocks Tutorial",
+ "href": "https://www.html5rocks.com/en/tutorials/notifications/quick/"
+ }, {
+ "name": "W3C Spec",
"href": "https://www.w3.org/TR/notifications/"
}, {
"name": "Changes in Chrome to Notifications API due to Service Worker Push Notifications",
"href": "https://developers.google.com/web/updates/2015/05/Notifying-you-of-notificiation-changes"
}],
- "knownBugs": [
- "Possibility of false-positive on Chrome for Android if permissions we're granted for a website prior to Chrome 44."
- ],
+ "knownBugs": ["Possibility of false-positive on Chrome for Android if permissions we're granted for a website prior to Chrome 44."],
"polyfills": ["desktop-notify", "html5-notifications"]
}
!*/
@@ -2217,9 +2132,9 @@ Detects support for the Notifications API
"notes": [{
"name": "W3C Spec",
"href": "https://www.w3.org/TR/navigation-timing/"
- },{
- "name": "HTML5 Rocks article",
- "href": "http://www.html5rocks.com/en/tutorials/webperformance/basics/"
+ }, {
+ "name": "HTML5 Rocks Tutorial",
+ "href": "https://www.html5rocks.com/en/tutorials/webperformance/basics/"
}],
"polyfills": ["perfnow"]
}
@@ -2230,42 +2145,62 @@ Detects support for the Navigation Timing API, for measuring browser and connect
Modernizr.addTest('performance', !!prefixed('performance', window));
+
+ /**
+ * List of JavaScript DOM values used for tests including a NON-prefix
+ *
+ * @memberOf Modernizr
+ * @name Modernizr._domPrefixesAll
+ * @optionName Modernizr._domPrefixesAll
+ * @optionProp domPrefixesAll
+ * @access public
+ * @example
+ *
+ * Modernizr._domPrefixesAll is exactly the same as [_domPrefixes](#modernizr-_domPrefixes), but also
+ * adds an empty string in the array to test for a non-prefixed value
+ *
+ * ```js
+ * Modernizr._domPrefixesAll === [ "", "Moz", "O", "ms", "Webkit" ];
+ * ```
+ */
+ var domPrefixesAll = [''].concat(domPrefixes);
+ ModernizrProto._domPrefixesAll = domPrefixesAll;
+
/*!
{
"name": "DOM Pointer Events API",
"property": "pointerevents",
+ "caniuse": "pointer",
"tags": ["input"],
"authors": ["Stu Cox"],
- "notes": [
- {
- "name": "W3C spec",
- "href": "https://www.w3.org/TR/pointerevents/"
- }
- ],
+ "notes": [{
+ "name": "W3C Spec (Pointer Events)",
+ "href": "https://www.w3.org/TR/pointerevents/"
+ }, {
+ "name": "W3C Spec (Pointer Events Level 2)",
+ "href": "https://www.w3.org/TR/pointerevents2/"
+ }, {
+ "name": "MDN Docs",
+ "href": "https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent"
+ }],
"warnings": ["This property name now refers to W3C DOM PointerEvents: https://github.com/Modernizr/Modernizr/issues/548#issuecomment-12812099"],
- "polyfills": ["handjs","pep"]
+ "polyfills": ["pep"]
}
!*/
/* DOC
-Detects support for the DOM Pointer Events API, which provides a unified event interface for pointing input devices, as implemented in IE10+.
+Detects support for the DOM Pointer Events API, which provides a unified event interface for pointing input devices, as implemented in IE10+, Edge and Blink.
*/
// **Test name hijacked!**
// Now refers to W3C DOM PointerEvents spec rather than the CSS pointer-events property.
Modernizr.addTest('pointerevents', function() {
// Cannot use `.prefixed()` for events, so test each prefix
- var bool = false,
- i = domPrefixes.length;
-
- // Don't forget un-prefixed...
- bool = Modernizr.hasEvent('pointerdown');
-
- while (i-- && !bool) {
- if (hasEvent(domPrefixes[i] + 'pointerdown')) {
- bool = true;
+ for (var i = 0, len = domPrefixesAll.length; i < len; i++) {
+ if (hasEvent(domPrefixesAll[i] + 'pointerdown')) {
+ return true;
}
}
- return bool;
+ return false;
});
/*!
@@ -2276,7 +2211,7 @@ Detects support for the DOM Pointer Events API, which provides a unified event i
"tags": ["queryselector"],
"authors": ["Andrew Betts (@triblondon)"],
"notes": [{
- "name" : "W3C Selectors reference",
+ "name": "W3C Spec",
"href": "https://www.w3.org/TR/selectors-api/#queryselectorall"
}],
"polyfills": ["css-selector-engine"]
@@ -2326,6 +2261,7 @@ Detects support for the `defer` attribute on the `