├── .eslintignore
├── .prettierignore
├── .github
├── FUNDING.yml
└── workflows
│ ├── main.yml
│ └── publish.yml
├── .gitignore
├── .prettierrc.json
├── CHANGELOG.md
├── .eslintrc.json
├── index.html
├── script
├── buildModernizr.js
└── featureList.json
├── LICENSE
├── README.md
├── src
├── style.scss
├── index.js
└── modernizr.js
├── package.json
└── webpack.config.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | /src/modernizr.js
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | /src/modernizr.js
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: surunzi
2 | open_collective: eruda
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | eruda-features.js
3 | eruda-features.js.map
4 | package-lock.json
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "tabWidth": 2,
4 | "semi": false
5 | }
6 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## v2.1.0 (5 Aug 2024)
2 |
3 | * feat: remove html5test link
4 |
5 | ## v2.0.0 (5 Jan 2020)
6 |
7 | * feat: theme support
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true,
5 | "amd": true,
6 | "commonjs": true
7 | },
8 | "extends": "eslint:recommended",
9 | "rules": {
10 | "indent": ["error", 2],
11 | "quotes": ["error", "single"],
12 | "no-extra-semi": "off"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Eruda-features
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - 'master'
8 | paths:
9 | - 'src/**/*'
10 |
11 | jobs:
12 | ci:
13 |
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | node-version: [16.x]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v2
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: npm i
27 | - run: npm run ci
28 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish to NPM
2 |
3 | on:
4 | workflow_dispatch:
5 | release:
6 | types: [created]
7 |
8 | jobs:
9 | publish:
10 |
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - name: Checkout
15 | uses: actions/checkout@v2
16 | - name: Setup Node
17 | uses: actions/setup-node@v2
18 | with:
19 | node-version: '18.x'
20 | registry-url: 'https://registry.npmjs.org'
21 | - name: Build eruda-features
22 | run: |
23 | npm i
24 | npm run build
25 | - name: Publish package on NPM
26 | run: npm publish
27 | env:
28 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
--------------------------------------------------------------------------------
/script/buildModernizr.js:
--------------------------------------------------------------------------------
1 | var modernizr = require('modernizr'),
2 | fs = require('fs'),
3 | path = require('path');
4 |
5 | var featureList = require('./featureList.json');
6 |
7 | modernizr.build(featureList, function (result)
8 | {
9 | result = result.replace(';(function(window, document, undefined){', '')
10 | .replace('window.Modernizr = Modernizr;', '')
11 | .replace('\'enableClasses\': true', '\'enableClasses\': false')
12 | .replace('testRunner();', 'Modernizr.testRunner = testRunner;')
13 | .replace('})(window, document);', '');
14 |
15 | result += '\nmodule.exports = Modernizr;';
16 | fs.writeFile(path.resolve(__dirname, '../src/modernizr.js'), result, 'utf8', function () {});
17 | });
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 liriliri
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # eruda-features
2 |
3 | [![NPM version][npm-image]][npm-url]
4 | [![Build status][ci-image]][ci-url]
5 | [![License][license-image]][npm-url]
6 |
7 | [npm-image]: https://img.shields.io/npm/v/eruda-features.svg
8 | [npm-url]: https://npmjs.org/package/eruda-features
9 | [ci-image]: https://img.shields.io/github/actions/workflow/status/liriliri/eruda-features/main.yml?branch=master&style=flat-square
10 | [ci-url]: https://github.com/liriliri/eruda-features/actions/workflows/main.yml
11 | [license-image]: https://img.shields.io/npm/l/eruda-features.svg
12 |
13 | Eruda plugin for browser feature detections, thanks to [modernizr](https://github.com/Modernizr/Modernizr) project.
14 |
15 | Red means unsupported, otherwise ok. All buttons is linked directly to related materials in [Can I Use](http://caniuse.com/) website.
16 |
17 | ## Demo
18 |
19 | Browse it on your phone:
20 | [https://eruda.liriliri.io/?plugin=features](https://eruda.liriliri.io/?plugin=features)
21 |
22 | ## Install
23 |
24 | ```bash
25 | npm install eruda-features --save
26 | ```
27 |
28 | ```javascript
29 | eruda.add(erudaFeatures);
30 | ```
31 |
32 | Make sure Eruda is loaded before this plugin, otherwise won't work.
--------------------------------------------------------------------------------
/src/style.scss:
--------------------------------------------------------------------------------
1 | @mixin overflow-auto($direction: 'both') {
2 | @if $direction == 'both' {
3 | overflow: auto;
4 | } @else {
5 | overflow-#{$direction}: auto;
6 | }
7 | -webkit-overflow-scrolling: touch;
8 | }
9 |
10 | @mixin clear-float {
11 | &:after {
12 | content: '';
13 | display: block;
14 | clear: both;
15 | }
16 | }
17 |
18 | $font-size-s: 12px;
19 |
20 | .features {
21 | ul {
22 | height: 100%;
23 | @include overflow-auto(y);
24 | @include clear-float();
25 | li {
26 | width: 33.3%;
27 | float: left;
28 | padding: 5px;
29 | .inner-wrapper {
30 | @include overflow-auto(x);
31 | font-size: $font-size-s;
32 | text-decoration: underline;
33 | display: block;
34 | padding: 10px;
35 | text-align: center;
36 | color: var(--console-error-foreground);
37 | background: var(--console-error-background);
38 | border: 1px solid var(--console-error-border);
39 | &.ok {
40 | background: var(--darker-background);
41 | border: 1px solid var(--border);
42 | color: var(--foreground);
43 | }
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eruda-features",
3 | "version": "2.1.0",
4 | "main": "eruda-features.js",
5 | "description": "Eruda plugin for browser feature detections",
6 | "browserslist": [
7 | "since 2015",
8 | "not dead"
9 | ],
10 | "files": [
11 | "eruda-features.js",
12 | "eruda-features.js.map"
13 | ],
14 | "scripts": {
15 | "dev": "webpack-dev-server --host 0.0.0.0 --mode development",
16 | "build": "webpack --mode production",
17 | "ci": "npm run lint && npm run build && npm run es5",
18 | "lint": "eslint src/**/*.js",
19 | "format": "lsla prettier \"src/*.{js,scss}\" \"*.json\" --write",
20 | "buildModernizr": "node script/buildModernizr",
21 | "es5": "es-check es5 eruda-features.js"
22 | },
23 | "keywords": [
24 | "eruda",
25 | "features",
26 | "plugin"
27 | ],
28 | "author": "redhoodsu",
29 | "license": "MIT",
30 | "bugs": {
31 | "url": "https://github.com/liriliri/eruda-features/issues"
32 | },
33 | "homepage": "https://github.com/liriliri/eruda-features#readme",
34 | "devDependencies": {
35 | "@babel/core": "^7.21.3",
36 | "@babel/plugin-transform-runtime": "^7.21.0",
37 | "@babel/preset-env": "^7.20.2",
38 | "autoprefixer": "^10.4.14",
39 | "babel-loader": "^9.1.2",
40 | "css-loader": "^3.4.2",
41 | "eruda": "^3.2.0",
42 | "es-check": "^7.2.1",
43 | "eslint": "^8.57.0",
44 | "licia": "^1.41.1",
45 | "modernizr": "^3.13.0",
46 | "postcss": "^8.4.21",
47 | "postcss-class-prefix": "^0.3.0",
48 | "postcss-loader": "^7.0.2",
49 | "sass": "^1.77.8",
50 | "sass-loader": "^14.2.1",
51 | "webpack": "^5.93.0",
52 | "webpack-cli": "^5.1.4",
53 | "webpack-dev-server": "^4.12.0"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | const map = require('licia/map')
2 | const modernizr = require('./modernizr')
3 |
4 | let featureList = require('../script/featureList.json')
5 |
6 | let featureNames = featureList['feature-detects'],
7 | specialNames = featureList['special-names']
8 |
9 | module.exports = function (eruda) {
10 | let { evalCss } = eruda.util
11 |
12 | class Features extends eruda.Tool {
13 | constructor() {
14 | super()
15 | this.name = 'features'
16 | this._style = evalCss(require('./style.scss'))
17 |
18 | this._features = {}
19 | this._isInit = false
20 | }
21 | show() {
22 | super.show()
23 |
24 | if (!this._isInit) this._initFeatures()
25 | }
26 | hide() {
27 | super.hide()
28 | }
29 | destroy() {
30 | super.destroy()
31 | evalCss.remove(this._style)
32 | }
33 | _initFeatures() {
34 | this._isInit = true
35 |
36 | modernizr.testRunner()
37 |
38 | let i = 0,
39 | featureNum = featureNames.length
40 |
41 | featureNames.forEach((feature) => {
42 | if (specialNames[feature]) feature = specialNames[feature]
43 | feature = feature.replace(/\//g, '')
44 |
45 | modernizr.on(feature, (result) => {
46 | this._features[feature] = result
47 | i++
48 | if (i === featureNum) this._render()
49 | })
50 | })
51 | }
52 | _render() {
53 | const features = map(this._features, (feature, key) => {
54 | const ok = feature ? 'eruda-ok' : ''
55 |
56 | return `
57 |
58 | ${key}
59 |
60 | `
61 | }).join('')
62 | const html = ``
63 | this._$el.html(html)
64 | }
65 | }
66 |
67 | return new Features()
68 | }
69 |
--------------------------------------------------------------------------------
/script/featureList.json:
--------------------------------------------------------------------------------
1 | {
2 | "feature-detects": [
3 | "audio",
4 | "canvas",
5 | "cookies",
6 | "css/animations",
7 | "css/boxshadow",
8 | "css/boxsizing",
9 | "css/calc",
10 | "css/flexbox",
11 | "css/transforms",
12 | "css/transforms3d",
13 | "css/transitions",
14 | "es6/promises",
15 | "file/api",
16 | "file/filesystem",
17 | "forms/placeholder",
18 | "fullscreen-api",
19 | "geolocation",
20 | "hashchange",
21 | "history",
22 | "img/webp",
23 | "img/webp-alpha",
24 | "indexeddb",
25 | "json",
26 | "network/fetch",
27 | "network/xhr2",
28 | "notification",
29 | "performance",
30 | "pointerevents",
31 | "queryselector",
32 | "script/async",
33 | "script/defer",
34 | "serviceworker",
35 | "storage/localstorage",
36 | "storage/sessionstorage",
37 | "storage/websqldatabase",
38 | "style/scoped",
39 | "svg",
40 | "templatestrings",
41 | "touchevents",
42 | "typed-arrays",
43 | "url/bloburls",
44 | "url/data-uri",
45 | "video",
46 | "webgl",
47 | "websockets"
48 | ],
49 | "special-names": {
50 | "css/boxshadow": "boxshadow",
51 | "css/boxsizing": "boxsizing",
52 | "css/flexbox": "flexbox",
53 | "es6/promises": "promises",
54 | "file/api": "filereader",
55 | "file/filesystem": "filesystem",
56 | "forms/placeholder": "placeholder",
57 | "fullscreen-api": "fullscreen",
58 | "img/webp": "webp",
59 | "img/webp-alpha": "webpalpha",
60 | "network/fetch": "fetch",
61 | "network/xhr2": "xhr2",
62 | "storage/localstorage": "localstorage",
63 | "storage/sessionstorage": "sessionstorage",
64 | "storage/websqldatabase": "websqldatabase",
65 | "typed-arrays": "typedarrays",
66 | "url/bloburls": "bloburls",
67 | "url/data-uri": "datauri"
68 | }
69 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const autoprefixer = require('autoprefixer')
2 | const postcss = require('postcss')
3 | const webpack = require('webpack')
4 | const path = require('path')
5 | const pkg = require('./package.json')
6 | const classPrefix = require('postcss-class-prefix')
7 | const TerserPlugin = require('terser-webpack-plugin')
8 |
9 | const banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage
10 |
11 | module.exports = (env, argv) => {
12 | const config = {
13 | devtool: 'source-map',
14 | entry: './src/index.js',
15 | devServer: {
16 | static: {
17 | directory: path.join(__dirname, './'),
18 | },
19 | port: 8080,
20 | },
21 | output: {
22 | path: __dirname,
23 | filename: 'eruda-features.js',
24 | publicPath: '/assets/',
25 | library: ['erudaFeatures'],
26 | libraryTarget: 'umd',
27 | },
28 | module: {
29 | rules: [
30 | {
31 | test: /\.js$/,
32 | exclude: /node_modules/,
33 | use: {
34 | loader: 'babel-loader',
35 | options: {
36 | sourceType: 'unambiguous',
37 | presets: ['@babel/preset-env'],
38 | plugins: ['@babel/plugin-transform-runtime'],
39 | },
40 | },
41 | },
42 | {
43 | test: /\.scss$/,
44 | use: [
45 | 'css-loader',
46 | {
47 | loader: 'postcss-loader',
48 | options: {
49 | postcssOptions: {
50 | plugins: [
51 | postcss.plugin('postcss-namespace', function () {
52 | // Add '.dev-tools .tools ' to every selector.
53 | return function (root) {
54 | root.walkRules(function (rule) {
55 | if (!rule.selectors) return rule
56 |
57 | rule.selectors = rule.selectors.map(function (
58 | selector
59 | ) {
60 | return '.dev-tools .tools ' + selector
61 | })
62 | })
63 | }
64 | }),
65 | classPrefix('eruda-'),
66 | autoprefixer,
67 | ],
68 | },
69 | },
70 | },
71 | 'sass-loader',
72 | ],
73 | },
74 | ],
75 | },
76 | plugins: [new webpack.BannerPlugin(banner)],
77 | }
78 |
79 | if (argv.mode === 'production') {
80 | config.optimization = {
81 | minimize: true,
82 | minimizer: [
83 | new TerserPlugin({
84 | terserOptions: {
85 | format: {
86 | comments: false,
87 | },
88 | },
89 | extractComments: false,
90 | }),
91 | ],
92 | }
93 | }
94 |
95 | return config
96 | }
97 |
--------------------------------------------------------------------------------
/src/modernizr.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * modernizr v3.13.0
3 | * 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
4 | *
5 | * Copyright (c)
6 | * Faruk Ates
7 | * Paul Irish
8 | * Alex Sexton
9 | * Ryan Seddon
10 | * Patrick Kettner
11 | * Stu Cox
12 | * Richard Herrera
13 | * Veeck
14 |
15 | * MIT License
16 | */
17 |
18 | /*
19 | * Modernizr tests which native CSS3 and HTML5 features are available in the
20 | * current UA and makes the results available to you in two ways: as properties on
21 | * a global `Modernizr` object, and as classes on the `` element. This
22 | * information allows you to progressively enhance your pages with a granular level
23 | * of control over the experience.
24 | */
25 |
26 | ;(function(scriptGlobalObject, window, document, undefined){
27 |
28 | var tests = [];
29 |
30 |
31 | /**
32 | * ModernizrProto is the constructor for Modernizr
33 | *
34 | * @class
35 | * @access public
36 | */
37 | var ModernizrProto = {
38 | _version: '3.13.0',
39 |
40 | // Any settings that don't work as separate modules
41 | // can go in here as configuration.
42 | _config: {
43 | 'classPrefix': '',
44 | 'enableClasses': false,
45 | 'enableJSClass': true,
46 | 'usePrefixes': true
47 | },
48 |
49 | // Queue of tests
50 | _q: [],
51 |
52 | // Stub these for people who are listening
53 | on: function(test, cb) {
54 | // I don't really think people should do this, but we can
55 | // safe guard it a bit.
56 | // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
57 | // This is in case people listen to synchronous tests. I would leave it out,
58 | // but the code to *disallow* sync tests in the real version of this
59 | // function is actually larger than this.
60 | var self = this;
61 | setTimeout(function() {
62 | cb(self[test]);
63 | }, 0);
64 | },
65 |
66 | addTest: function(name, fn, options) {
67 | tests.push({name: name, fn: fn, options: options});
68 | },
69 |
70 | addAsyncTest: function(fn) {
71 | tests.push({name: null, fn: fn});
72 | }
73 | };
74 |
75 |
76 |
77 | // Fake some of Object.create so we can force non test results to be non "own" properties.
78 | var Modernizr = function() {};
79 | Modernizr.prototype = ModernizrProto;
80 |
81 | // Leak modernizr globally when you `require` it rather than force it here.
82 | // Overwrite name so constructor name is nicer :D
83 | Modernizr = new Modernizr();
84 |
85 |
86 |
87 | var classes = [];
88 |
89 |
90 | /**
91 | * is returns a boolean if the typeof an obj is exactly type.
92 | *
93 | * @access private
94 | * @function is
95 | * @param {*} obj - A thing we want to check the type of
96 | * @param {string} type - A string to compare the typeof against
97 | * @returns {boolean} true if the typeof the first parameter is exactly the specified type, false otherwise
98 | */
99 | function is(obj, type) {
100 | return typeof obj === type;
101 | }
102 |
103 | ;
104 |
105 | /**
106 | * Run through all tests and detect their support in the current UA.
107 | *
108 | * @access private
109 | * @returns {void}
110 | */
111 | function testRunner() {
112 | var featureNames;
113 | var feature;
114 | var aliasIdx;
115 | var result;
116 | var nameIdx;
117 | var featureName;
118 | var featureNameSplit;
119 |
120 | for (var featureIdx in tests) {
121 | if (tests.hasOwnProperty(featureIdx)) {
122 | featureNames = [];
123 | feature = tests[featureIdx];
124 | // run the test, throw the return value into the Modernizr,
125 | // then based on that boolean, define an appropriate className
126 | // and push it into an array of classes we'll join later.
127 | //
128 | // If there is no name, it's an 'async' test that is run,
129 | // but not directly added to the object. That should
130 | // be done with a post-run addTest call.
131 | if (feature.name) {
132 | featureNames.push(feature.name.toLowerCase());
133 |
134 | if (feature.options && feature.options.aliases && feature.options.aliases.length) {
135 | // Add all the aliases into the names list
136 | for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
137 | featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
138 | }
139 | }
140 | }
141 |
142 | // Run the test, or use the raw value if it's not a function
143 | result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
144 |
145 | // Set each of the names on the Modernizr object
146 | for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
147 | featureName = featureNames[nameIdx];
148 | // Support dot properties as sub tests. We don't do checking to make sure
149 | // that the implied parent tests have been added. You must call them in
150 | // order (either in the test, or make the parent test a dependency).
151 | //
152 | // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
153 | // hashtag famous last words
154 | featureNameSplit = featureName.split('.');
155 |
156 | if (featureNameSplit.length === 1) {
157 | Modernizr[featureNameSplit[0]] = result;
158 | } else {
159 | // cast to a Boolean, if not one already or if it doesnt exist yet (like inputtypes)
160 | if (!Modernizr[featureNameSplit[0]] || Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
161 | Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
162 | }
163 |
164 | Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
165 | }
166 |
167 | classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
168 | }
169 | }
170 | }
171 | }
172 | ;
173 |
174 | /**
175 | * docElement is a convenience wrapper to grab the root element of the document
176 | *
177 | * @access private
178 | * @returns {HTMLElement|SVGElement} The root element of the document
179 | */
180 | var docElement = document.documentElement;
181 |
182 |
183 | /**
184 | * A convenience helper to check if the document we are running in is an SVG document
185 | *
186 | * @access private
187 | * @returns {boolean}
188 | */
189 | var isSVG = docElement.nodeName.toLowerCase() === 'svg';
190 |
191 |
192 |
193 | /**
194 | * createElement is a convenience wrapper around document.createElement. Since we
195 | * use createElement all over the place, this allows for (slightly) smaller code
196 | * as well as abstracting away issues with creating elements in contexts other than
197 | * HTML documents (e.g. SVG documents).
198 | *
199 | * @access private
200 | * @function createElement
201 | * @returns {HTMLElement|SVGElement} An HTML or SVG element
202 | */
203 | function createElement() {
204 | if (typeof document.createElement !== 'function') {
205 | // This is the case in IE7, where the type of createElement is "object".
206 | // For this reason, we cannot call apply() as Object is not a Function.
207 | return document.createElement(arguments[0]);
208 | } else if (isSVG) {
209 | return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
210 | } else {
211 | return document.createElement.apply(document, arguments);
212 | }
213 | }
214 |
215 | ;
216 | /*!
217 | {
218 | "name": "HTML5 Audio Element",
219 | "property": "audio",
220 | "caniuse": "audio",
221 | "tags": ["html5", "audio", "media"],
222 | "notes": [{
223 | "name": "MDN Docs",
224 | "href": "https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements"
225 | }]
226 | }
227 | !*/
228 | /* DOC
229 | Detects support of the audio element, as well as testing what types of content it supports.
230 |
231 | Subproperties are provided to describe support for `ogg`, `mp3`,`opus`, `wav` and `m4a` formats, e.g.:
232 |
233 | ```javascript
234 | Modernizr.audio // true
235 | Modernizr.audio.ogg // 'probably'
236 | ```
237 | */
238 |
239 | // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
240 | // thx to NielsLeenheer and zcorpan
241 |
242 | // Note: in some older browsers, "no" was a return value instead of empty string.
243 | // It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
244 | // It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
245 | (function() {
246 | var elem = createElement('audio');
247 |
248 | Modernizr.addTest('audio', function() {
249 | var bool = false;
250 | try {
251 | bool = !!elem.canPlayType;
252 | if (bool) {
253 | bool = new Boolean(bool);
254 | }
255 | } catch (e) {}
256 |
257 | return bool;
258 | });
259 |
260 | // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
261 | try {
262 | if (!!elem.canPlayType) {
263 | Modernizr.addTest('audio.ogg', elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''));
264 | Modernizr.addTest('audio.mp3', elem.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/, ''));
265 | Modernizr.addTest('audio.opus', elem.canPlayType('audio/ogg; codecs="opus"') ||
266 | elem.canPlayType('audio/webm; codecs="opus"').replace(/^no$/, ''));
267 | Modernizr.addTest('audio.wav', elem.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''));
268 | Modernizr.addTest('audio.m4a', (elem.canPlayType('audio/x-m4a;') ||
269 | elem.canPlayType('audio/aac;')).replace(/^no$/, ''));
270 | }
271 | } catch (e) {}
272 | })();
273 |
274 | /*!
275 | {
276 | "name": "Canvas",
277 | "property": "canvas",
278 | "caniuse": "canvas",
279 | "tags": ["canvas", "graphics"],
280 | "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
281 | }
282 | !*/
283 | /* DOC
284 | Detects support for the `