From 2d649777361da7235f20128523d92be61c58dc26 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 28 Feb 2018 11:14:00 -0500 Subject: [PATCH 001/371] fix(package): update videojs-vtt.js to version 0.12.6 (#4954) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6552e84017..a1e5f38e3a 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "tsml": "1.0.1", "videojs-font": "2.1.0", "videojs-ie8": "1.1.2", - "videojs-vtt.js": "0.12.5", + "videojs-vtt.js": "0.12.6", "xhr": "2.4.0" }, "devDependencies": { From 270a23196a524045db726e099ba1d713026236c2 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Wed, 28 Feb 2018 11:15:25 -0500 Subject: [PATCH 002/371] =?UTF-8?q?chore(package):=20update=20grunt-access?= =?UTF-8?q?ibility=20to=20version=206.0.0=20=F0=9F=9A=80=20(#4968)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(package): update grunt-accessibility to version 6.0.0 * chore(package): update lockfile https://npm.im/greenkeeper-lockfile --- package-lock.json | 592 ++++++++++++++++++++++------------------------ package.json | 2 +- 2 files changed, 287 insertions(+), 307 deletions(-) diff --git a/package-lock.json b/package-lock.json index f51560ad87..88a0d723d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,10 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "HTML_CodeSniffer": { - "version": "github:squizlabs/HTML_CodeSniffer#d209ce54876657858a8a01528ad812cd234f37f0", - "dev": true - }, "JSONStream": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", @@ -41,26 +37,85 @@ } }, "access-sniff": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/access-sniff/-/access-sniff-3.0.1.tgz", - "integrity": "sha1-IJ4W63DAlaA79/yCnsrLfHeS9e4=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/access-sniff/-/access-sniff-3.2.0.tgz", + "integrity": "sha512-HLvH8e5g312urx6ZRo+nxSHjhVHEcuUxbpjFaFQ1LZOtN19L0CSb5ppwxtxy0QZ05zYAcWmXH6lVurdb+mGuUw==", "dev": true, "requires": { - "HTML_CodeSniffer": "github:squizlabs/HTML_CodeSniffer#d209ce54876657858a8a01528ad812cd234f37f0", - "axios": "0.9.1", + "axios": "0.18.0", "bluebird": "3.5.1", - "chalk": "1.1.3", - "commander": "2.11.0", + "chalk": "2.3.1", + "commander": "2.14.1", "glob": "7.1.2", - "jsdom": "9.12.0", + "html_codesniffer": "2.1.1", + "jsdom": "11.6.2", "mkdirp": "0.5.1", - "phantomjs-prebuilt": "2.1.15", - "rc": "1.2.1", + "phantomjs-prebuilt": "2.1.16", + "rc": "1.2.5", "underscore": "1.8.3", - "unixify": "0.2.1", - "validator": "5.7.0" + "unixify": "1.0.0", + "validator": "9.4.1" }, "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz", + "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "5.2.0" + } + }, + "commander": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.14.1.tgz", + "integrity": "sha512-+YR16o3rK53SmWHU3rEM3tPAh2rwb1yPcQX5irVn7mb0gXbwuCCrnkbV5+PBfETdfg1vui07nM6PCG1zndcjQw==", + "dev": true + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "rc": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.5.tgz", + "integrity": "sha1-J1zWh/bjs2zHVrqibf7oCnkDAf0=", + "dev": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + }, + "supports-color": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.2.0.tgz", + "integrity": "sha512-F39vS48la4YvTZUPVeTqsjsFNrvcMwrV3RLZINsmHo+7djCvuUzSIeXOnZ5hmjef4bajL1dNccN+tg5XAliO5Q==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", @@ -76,20 +131,12 @@ "dev": true }, "acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz", + "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", "dev": true, "requires": { - "acorn": "4.0.13" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "dev": true - } + "acorn": "5.1.2" } }, "acorn-jsx": { @@ -548,12 +595,13 @@ "dev": true }, "axios": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.9.1.tgz", - "integrity": "sha1-lWCLFkR+4psDNYmFTD/H7iwGv24=", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "dev": true, "requires": { - "follow-redirects": "0.0.7" + "follow-redirects": "1.4.1", + "is-buffer": "1.1.5" } }, "babel-cli": { @@ -1555,6 +1603,12 @@ "umd": "3.0.1" } }, + "browser-process-hrtime": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz", + "integrity": "sha1-Ql1opY00R/AqBKqJQYf86K+Le44=", + "dev": true + }, "browser-resolve": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", @@ -2533,9 +2587,9 @@ "dev": true }, "content-type-parser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.1.tgz", - "integrity": "sha1-w+VpiMU8ZRJ/tG1AMqOpACRv3JQ=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", + "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", "dev": true }, "conventional-changelog": { @@ -3468,6 +3522,15 @@ "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", "dev": true }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "4.0.2" + } + }, "domhandler": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz", @@ -3797,9 +3860,9 @@ } }, "es6-promise": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.0.5.tgz", - "integrity": "sha1-eILzCt3lskDM+n99eMVIMwlRrkI=", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", "dev": true }, "es6-set": { @@ -4302,26 +4365,17 @@ } }, "extract-zip": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.5.tgz", - "integrity": "sha1-maBnNbbqIOqbcF13ms/8yHz/BEA=", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", + "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", "dev": true, "requires": { "concat-stream": "1.6.0", - "debug": "2.2.0", + "debug": "2.6.9", "mkdirp": "0.5.0", "yauzl": "2.4.1" }, "dependencies": { - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "dev": true, - "requires": { - "ms": "0.7.1" - } - }, "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", @@ -4336,12 +4390,6 @@ "requires": { "minimist": "0.0.8" } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", - "dev": true } } }, @@ -4538,13 +4586,23 @@ "dev": true }, "follow-redirects": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-0.0.7.tgz", - "integrity": "sha1-NLkLqyqRGqNHVx2pDyK9NuzYqRk=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", + "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", "dev": true, "requires": { - "debug": "2.6.9", - "stream-consume": "0.1.0" + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } } }, "for-each": { @@ -6051,12 +6109,12 @@ } }, "grunt-accessibility": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/grunt-accessibility/-/grunt-accessibility-5.0.0.tgz", - "integrity": "sha1-/uK+5WHjPOl8lfk/7ogEPfFFokk=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/grunt-accessibility/-/grunt-accessibility-6.0.0.tgz", + "integrity": "sha512-5Y7MMYzpzMICkspvmUOU+YC/VE5eiB5TV8k9u43ZFrzLIoYDulKce8KX0fyi2EXYEDKlUEyaVI/W4rLDqqy3/Q==", "dev": true, "requires": { - "access-sniff": "3.0.1" + "access-sniff": "3.2.0" } }, "grunt-banner": { @@ -6239,6 +6297,17 @@ "maxmin": "2.1.0" } }, + "grunt-contrib-jshint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz", + "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "hooker": "0.2.3", + "jshint": "2.9.5" + } + }, "grunt-contrib-uglify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-2.3.0.tgz", @@ -6696,12 +6765,26 @@ "dev": true }, "html-encoding-sniffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz", - "integrity": "sha1-eb96eF6klf5mFl5zQVPzY/9UN9o=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", "dev": true, "requires": { - "whatwg-encoding": "1.0.1" + "whatwg-encoding": "1.0.3" + } + }, + "html_codesniffer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/html_codesniffer/-/html_codesniffer-2.1.1.tgz", + "integrity": "sha512-ms7RxMbIPunkyyZIsU22HV1lTBRrmDov+FlCYTu9ONTSyP5Yj2V8cg27p1e2qL1zxhMl/yLx8P9/b7a9O8gcXQ==", + "dev": true, + "requires": { + "grunt": "1.0.1", + "grunt-contrib-copy": "1.0.0", + "grunt-contrib-jshint": "1.1.0", + "grunt-contrib-uglify": "2.3.0", + "grunt-contrib-watch": "1.0.0", + "load-grunt-tasks": "3.5.2" } }, "htmlescape": { @@ -7793,37 +7876,55 @@ } }, "jsdom": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", - "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", + "version": "11.6.2", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.6.2.tgz", + "integrity": "sha512-pAeZhpbSlUp5yQcS6cBQJwkbzmv4tWFaYxHbFVSxzXefqjvtRA851Z5N2P+TguVG9YeUDcgb8pdeVQRJh0XR3Q==", "dev": true, "requires": { "abab": "1.0.4", - "acorn": "4.0.13", - "acorn-globals": "3.1.0", + "acorn": "5.4.1", + "acorn-globals": "4.1.0", "array-equal": "1.0.0", - "content-type-parser": "1.0.1", + "browser-process-hrtime": "0.1.2", + "content-type-parser": "1.0.2", "cssom": "0.3.2", "cssstyle": "0.2.37", + "domexception": "1.0.1", "escodegen": "1.9.0", - "html-encoding-sniffer": "1.0.1", - "nwmatcher": "1.4.2", - "parse5": "1.5.1", + "html-encoding-sniffer": "1.0.2", + "left-pad": "1.2.0", + "nwmatcher": "1.4.3", + "parse5": "4.0.0", + "pn": "1.1.0", "request": "2.83.0", + "request-promise-native": "1.0.5", "sax": "1.2.4", "symbol-tree": "3.2.2", "tough-cookie": "2.3.3", + "w3c-hr-time": "1.0.1", "webidl-conversions": "4.0.2", - "whatwg-encoding": "1.0.1", - "whatwg-url": "4.8.0", - "xml-name-validator": "2.0.1" + "whatwg-encoding": "1.0.3", + "whatwg-url": "6.4.0", + "ws": "4.0.0", + "xml-name-validator": "3.0.0" }, "dependencies": { "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz", + "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ==", "dev": true + }, + "ws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-4.0.0.tgz", + "integrity": "sha512-QYslsH44bH8O7/W2815u5DpnCpXWpEK44FmaHffNwgJI4JMaSZONgPBTOfrxJ29mXKbXak+LsJ2uAkDTYq2ptQ==", + "dev": true, + "requires": { + "async-limiter": "1.0.0", + "safe-buffer": "5.1.1", + "ultron": "1.1.1" + } } } }, @@ -8487,6 +8588,12 @@ "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", "dev": true }, + "left-pad": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.2.0.tgz", + "integrity": "sha1-0wpzxrggHY99jnlWupYWCHpo4O4=", + "dev": true + }, "levenshtein-edit-distance": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/levenshtein-edit-distance/-/levenshtein-edit-distance-1.0.0.tgz", @@ -8716,6 +8823,12 @@ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "lodash.template": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", @@ -10122,9 +10235,9 @@ "dev": true }, "nwmatcher": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.2.tgz", - "integrity": "sha512-QMkCGQFYp5p+zwU3INntLmz1HMfSx9dMVJMYKmE1yuSf/22Wjo6VPFa405mCLUuQn9lbQvH2DZN9lt10ZNvtAg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.3.tgz", + "integrity": "sha512-IKdSTiDWCarf2JTS5e9e2+5tPZGdkRJ79XjYV0pzK8Q9BpsFyBq1RGKxzs7Q8UBushGw7m6TzVKz6fcY99iSWw==", "dev": true }, "oauth-sign": { @@ -10499,9 +10612,9 @@ "dev": true }, "parse5": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", "dev": true }, "parseqs": { @@ -10650,184 +10763,20 @@ "dev": true }, "phantomjs-prebuilt": { - "version": "2.1.15", - "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.15.tgz", - "integrity": "sha1-IPhugtM0nFBZF1J3RbekEeCLOQM=", + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", "dev": true, "requires": { - "es6-promise": "4.0.5", - "extract-zip": "1.6.5", + "es6-promise": "4.2.4", + "extract-zip": "1.6.6", "fs-extra": "1.0.0", "hasha": "2.2.0", "kew": "0.7.0", "progress": "1.1.8", - "request": "2.81.0", + "request": "2.83.0", "request-progress": "2.0.1", - "which": "1.2.14" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true - }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "form-data": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", - "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "har-schema": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", - "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", - "dev": true - }, - "har-validator": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", - "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", - "dev": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", - "dev": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - } - }, - "performance-now": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", - "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", - "dev": true - }, - "qs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", - "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", - "dev": true - }, - "request": { - "version": "2.81.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", - "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", - "dev": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", - "dev": true - }, - "which": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", - "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", - "dev": true, - "requires": { - "isexe": "2.0.0" - } - } + "which": "1.3.0" } }, "pify": { @@ -10872,6 +10821,12 @@ "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", "dev": true }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, "portscanner": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", @@ -11842,6 +11797,26 @@ "throttleit": "1.0.0" } }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "dev": true, + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "1.1.1", + "tough-cookie": "2.3.3" + } + }, "requestretry": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", @@ -12767,6 +12742,12 @@ "readable-stream": "2.3.3" } }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, "stream-browserify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", @@ -12807,12 +12788,6 @@ } } }, - "stream-consume": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz", - "integrity": "sha1-pB6tGm1ggc63n2WwYZAbbY89HQ8=", - "dev": true - }, "stream-http": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", @@ -13310,10 +13285,21 @@ } }, "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true + } + } }, "traverse": { "version": "0.3.9", @@ -13731,9 +13717,9 @@ "dev": true }, "unixify": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/unixify/-/unixify-0.2.1.tgz", - "integrity": "sha1-SGQwPCbsyuEWDZHQRvZUc/Aivtw=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", + "integrity": "sha1-OmQcjC/7zk2mg6XHDwOkYpQMIJA=", "dev": true, "requires": { "normalize-path": "2.1.1" @@ -14005,9 +13991,9 @@ } }, "validator": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-5.7.0.tgz", - "integrity": "sha1-eoelgUa2laxIYHEUHAxJ1n2gXlw=", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", + "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==", "dev": true }, "verror": { @@ -14179,6 +14165,15 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "0.1.2" + } + }, "watchify": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz", @@ -14382,38 +14377,23 @@ "dev": true }, "whatwg-encoding": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz", - "integrity": "sha1-PGxFGhmO567FWx7GHQkgxngBpfQ=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", + "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", "dev": true, "requires": { - "iconv-lite": "0.4.13" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=", - "dev": true - } + "iconv-lite": "0.4.19" } }, "whatwg-url": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", - "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.4.0.tgz", + "integrity": "sha512-Z0CVh/YE217Foyb488eo+iBv+r7eAQ0wSTyApi9n06jhcA3z6Nidg/EGvl0UFkg7kMdKxfBzzr+o9JF+cevgMg==", "dev": true, "requires": { - "tr46": "0.0.3", - "webidl-conversions": "3.0.1" - }, - "dependencies": { - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - } + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" } }, "when": { @@ -14545,9 +14525,9 @@ } }, "xml-name-validator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", "dev": true }, "xmlcreate": { diff --git a/package.json b/package.json index a1e5f38e3a..e7592dd044 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "filesize": "^3.5.11", "gh-release": "^3.2.0", "grunt": "^1.0.1", - "grunt-accessibility": "^5.0.0", + "grunt-accessibility": "^6.0.0", "grunt-banner": "^0.6.0", "grunt-browserify": "5.2.0", "grunt-cli": "~1.2.0", From 5b5cc50608ad7a05a71aa0a9bfc4fc09993fb6dc Mon Sep 17 00:00:00 2001 From: Pat O'Neill Date: Mon, 5 Mar 2018 14:44:34 -0500 Subject: [PATCH 003/371] fix: Fix an issue where disabling the progress control would throw an error. (#4986) --- src/js/control-bar/progress-control/seek-bar.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js index 11199de476..7c9e077141 100644 --- a/src/js/control-bar/progress-control/seek-bar.js +++ b/src/js/control-bar/progress-control/seek-bar.js @@ -247,7 +247,9 @@ class SeekBar extends Slider { super.handleMouseUp(event); // Stop event propagation to prevent double fire in progress-control.js - event.stopPropagation(); + if (event) { + event.stopPropagation(); + } this.player_.scrubbing(false); /** From 9c4ded88999911a033c9f41fbb67e1515ff0f25d Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 5 Mar 2018 16:42:06 -0500 Subject: [PATCH 004/371] fix(events): triggering with an object had incorrect target property on event object (#4993) Currently, trigger an event with an object rather than a string will have the document as a target on the event object rather than the element. --- src/js/utils/events.js | 3 +++ test/unit/events.test.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/js/utils/events.js b/src/js/utils/events.js index 541d67cd28..dfc9a16622 100644 --- a/src/js/utils/events.js +++ b/src/js/utils/events.js @@ -413,7 +413,10 @@ export function trigger(elem, event, hash) { // If an event name was passed as a string, creates an event out of it if (typeof event === 'string') { event = {type: event, target: elem}; + } else if (!event.target) { + event.target = elem; } + // Normalizes the event properties. event = fixEvent(event); diff --git a/test/unit/events.test.js b/test/unit/events.test.js index 5c82e3b17b..cb42c1509c 100644 --- a/test/unit/events.test.js +++ b/test/unit/events.test.js @@ -284,3 +284,40 @@ QUnit.test('should execute remaining handlers after an exception in an event han log.error = oldLogError; }); + +QUnit.test('trigger with an object should set the correct target property', function(assert) { + const el = document.createElement('div'); + + Events.on(el, 'click', function(e) { + assert.equal(e.target, el, 'the event object target should be our element'); + }); + Events.trigger(el, { type: 'click'}); +}); + +QUnit.test('retrigger with a string should use the new element as target', function(assert) { + const el1 = document.createElement('div'); + const el2 = document.createElement('div'); + + Events.on(el2, 'click', function(e) { + assert.equal(e.target, el2, 'the event object target should be the new element'); + }); + Events.on(el1, 'click', function(e) { + Events.trigger(el2, 'click'); + }); + Events.trigger(el1, 'click'); + Events.trigger(el1, {type: 'click'}); +}); + +QUnit.test('retrigger with an object should use the old element as target', function(assert) { + const el1 = document.createElement('div'); + const el2 = document.createElement('div'); + + Events.on(el2, 'click', function(e) { + assert.equal(e.target, el1, 'the event object target should be the old element'); + }); + Events.on(el1, 'click', function(e) { + Events.trigger(el2, e); + }); + Events.trigger(el1, 'click'); + Events.trigger(el1, {type: 'click'}); +}); From 7facc448935883344ed990b52ed3a0b26f31acd2 Mon Sep 17 00:00:00 2001 From: ookami125 Date: Mon, 5 Mar 2018 17:11:51 -0500 Subject: [PATCH 005/371] fix(text-tracks): keep showing captions even if the text track settings were disabled (#4974) If a user disabled the text track setting component, trying to play emulated captions would crash. Add a null check before applying the text track settings. Fixes #4964. --- src/js/tracks/text-track-display.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/js/tracks/text-track-display.js b/src/js/tracks/text-track-display.js index 4edd55cd50..0ffe1332ed 100644 --- a/src/js/tracks/text-track-display.js +++ b/src/js/tracks/text-track-display.js @@ -270,7 +270,6 @@ class TextTrackDisplay extends Component { return; } - const overrides = this.player_.textTrackSettings.getValues(); const cues = []; for (let i = 0; i < track.activeCues.length; i++) { @@ -279,6 +278,12 @@ class TextTrackDisplay extends Component { window.WebVTT.processCues(window, cues, this.el_); + if (!this.player_.textTrackSettings) { + return; + } + + const overrides = this.player_.textTrackSettings.getValues(); + let i = cues.length; while (i--) { From 5d689041fb65f2e78c22c2bf763a7b38bf864926 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 5 Mar 2018 17:32:08 -0500 Subject: [PATCH 006/371] 6.7.4 --- CHANGELOG.md | 14 ++++++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fcbb69788..aee49dbafc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ + +## [6.7.4](https://github.com/videojs/video.js/compare/v6.7.3...v6.7.4) (2018-03-05) + +### Bug Fixes + +* Fix an issue where disabling the progress control would throw an error. ([#4986](https://github.com/videojs/video.js/issues/4986)) ([5b5cc50](https://github.com/videojs/video.js/commit/5b5cc50)) +* **events:** triggering with an object had incorrect target property on event object ([#4993](https://github.com/videojs/video.js/issues/4993)) ([9c4ded8](https://github.com/videojs/video.js/commit/9c4ded8)) +* **package:** update videojs-vtt.js to version 0.12.6 ([#4954](https://github.com/videojs/video.js/issues/4954)) ([2d64977](https://github.com/videojs/video.js/commit/2d64977)) +* **text-tracks:** keep showing captions even if the text track settings were disabled ([#4974](https://github.com/videojs/video.js/issues/4974)) ([7facc44](https://github.com/videojs/video.js/commit/7facc44)), closes [#4964](https://github.com/videojs/video.js/issues/4964) + +### Chores + +* **package:** update grunt-accessibility to version 6.0.0 🚀 ([#4968](https://github.com/videojs/video.js/issues/4968)) ([270a231](https://github.com/videojs/video.js/commit/270a231)) + ## [6.7.3](https://github.com/videojs/video.js/compare/v6.7.2...v6.7.3) (2018-02-22) diff --git a/package-lock.json b/package-lock.json index 88a0d723d3..e5103d66a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "video.js", - "version": "6.7.3", + "version": "6.7.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e7592dd044..6ec0d02b93 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "video.js", "description": "An HTML5 and Flash video player with a common API and skin for both.", - "version": "6.7.3", + "version": "6.7.4", "main": "./dist/video.cjs.js", "style": "./dist/video-js.css", "copyright": "Copyright Brightcove, Inc. ", From 1fa9dfbee2289ba5947393b1be1ad571481bff7f Mon Sep 17 00:00:00 2001 From: Edward Hummerston Date: Thu, 8 Mar 2018 04:09:06 +1100 Subject: [PATCH 007/371] docs(react guide): update guide to prevent memory leaks when components are disposed of (#4998) When a component is disposed of, without calling ReactDOM.unmountComponentAtNode() on the data-reactroot in the destroyed component, the React.Component and videojs.Component (here EpisodeList and vjsEpisodeList) remain in memory. The videojs.Component should listen for its dispose event and unmount its React root in the corresponding React.Component. --- docs/guides/react.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/guides/react.md b/docs/guides/react.md index 5b784fdeb9..83f96f0f77 100644 --- a/docs/guides/react.md +++ b/docs/guides/react.md @@ -105,6 +105,11 @@ class vjsEpisodeList extends vjsComponent { player.ready(() => { this.mount(); }); + + /* Remove React root when component is destroyed */ + this.on("dispose", () => { + ReactDOM.unmountComponentAtNode(this.el()) + }); } /** From df96a74f6b03e6532383ebe21e503f66ad914c0a Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Wed, 7 Mar 2018 14:28:37 -0500 Subject: [PATCH 008/371] feat: sourceset event (#4660) Trigger a sourceset event whenever the source is set in the Html5 tech, including initial source. We override the video element's src and setAttribute methods so that we can trigger the sourceset event when people change the src with both the video element and our API methods. The event object for sourceset will contain the src string that was provided at the time the sourceset was triggered. This is mostly important if a source is being set while a tech is changing. A Tech has a featuresSourceset option that it can set to for sourceset handling. It can then call the helper triggerSourceset(src) to trigger the sourceset. --- src/js/player.js | 35 +++ src/js/tech/html5.js | 116 ++++++++ src/js/tech/tech.js | 40 +++ test/unit/sourceset.test.js | 550 +++++++++++++++++++++++++++++++++++ test/unit/tech/html5.test.js | 6 +- 5 files changed, 745 insertions(+), 2 deletions(-) create mode 100644 test/unit/sourceset.test.js diff --git a/src/js/player.js b/src/js/player.js index c258abe3f0..faae8f3bb1 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -964,6 +964,7 @@ class Player extends Component { this.on(this.tech_, event, this[`handleTech${toTitleCase(event)}_`]); }); this.on(this.tech_, 'loadstart', this.handleTechLoadStart_); + this.on(this.tech_, 'sourceset', this.handleTechSourceset_); this.on(this.tech_, 'waiting', this.handleTechWaiting_); this.on(this.tech_, 'canplay', this.handleTechCanPlay_); this.on(this.tech_, 'canplaythrough', this.handleTechCanPlayThrough_); @@ -1173,6 +1174,40 @@ class Player extends Component { } } + /** + * Fired when the source is set or changed on the {@link Tech} + * causing the media element to reload. + * + * It will fire for the initial source and each subsequent source. + * This event is a custom event from Video.js and is triggered by the {@link Tech}. + * + * The event object for this event contains a `src` property that will contain the source + * that was available when the event was triggered. This is generally only necessary if Video.js + * is switching techs while the source was being changed. + * + * It is also fired when `load` is called on the player (or media element) + * because the {@link https://html.spec.whatwg.org/multipage/media.html#dom-media-load|specification for `load`} + * says that the resource selection algorithm + * needs to be aborted and restarted. + * + * @event Player#sourceset + * @type {EventTarget~Event} + * @prop {string} src The source url available when the `sourceset` was triggered + */ + /** + * Retrigger the `sourceset` event that was triggered by the {@link Tech}. + * + * @fires Player#sourceset + * @listens Tech#sourceset + * @private + */ + handleTechSourceset_(event) { + this.trigger({ + src: event.src, + type: 'sourceset' + }); + } + /** * Add/remove the vjs-has-started class * diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 212d1c0b7c..fcdb86a7f5 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -34,6 +34,8 @@ class Html5 extends Tech { constructor(options, ready) { super(options, ready); + this.setupSourcesetHandling_(); + const source = options.source; let crossoriginTracks = false; @@ -119,6 +121,86 @@ class Html5 extends Tech { super.dispose(); } + /** + * Modify the media element so that we can detect when + * the source is changed. Fires `sourceset` just after the source has changed + */ + setupSourcesetHandling_() { + if (!this.featuresSourceset) { + return; + } + + const el = this.el(); + + // we need to fire sourceset when the player is ready + // if we find that the media element had a src when it was + // given to us and that tech element is not in a stalled state + if (el.src || el.currentSrc && this.el().initNetworkState_ !== 3) { + this.triggerSourceset(el.src || el.currentSrc); + } + + const proto = window.HTMLMediaElement.prototype; + let srcDescriptor = {}; + + // preserve getters/setters already on `el.src` if they exist + if (Object.getOwnPropertyDescriptor(el, 'src')) { + srcDescriptor = Object.getOwnPropertyDescriptor(el, 'src'); + } else if (Object.getOwnPropertyDescriptor(proto, 'src')) { + srcDescriptor = mergeOptions(srcDescriptor, Object.getOwnPropertyDescriptor(proto, 'src')); + } + + if (!srcDescriptor.get) { + srcDescriptor.get = function() { + return proto.getAttribute.call(this, 'src'); + }; + } + + if (!srcDescriptor.set) { + srcDescriptor.set = function(v) { + return proto.setAttribute.call(this, 'src', v); + }; + } + + if (typeof srcDescriptor.enumerable === 'undefined') { + srcDescriptor.enumerable = true; + } + + Object.defineProperty(el, 'src', { + get: srcDescriptor.get.bind(el), + set: (v) => { + const retval = srcDescriptor.set.call(el, v); + + this.triggerSourceset(v); + + return retval; + }, + configurable: true, + enumerable: srcDescriptor.enumerable + }); + + const oldSetAttribute = el.setAttribute; + + el.setAttribute = (n, v) => { + const retval = oldSetAttribute.call(el, n, v); + + if (n === 'src') { + this.triggerSourceset(v); + } + + return retval; + }; + + const oldLoad = el.load; + + el.load = () => { + const retval = oldLoad.call(el); + + this.triggerSourceset(el.src || el.currentSrc); + + return retval; + }; + } + /** * When a captions track is enabled in the iOS Safari native player, all other * tracks are disabled (including metadata tracks), which nulls all of their @@ -897,6 +979,32 @@ Html5.canControlPlaybackRate = function() { } }; +/** + * Check if we can override a video/audio elements attributes, with + * Object.defineProperty. + * + * @return {boolean} + * - True if builtin attributes can be overriden + * - False otherwise + */ +Html5.canOverrideAttributes = function() { + if (browser.IS_IE8) { + return false; + } + // if we cannot overwrite the src property, there is no support + // iOS 7 safari for instance cannot do this. + try { + const noop = () => {}; + + Object.defineProperty(document.createElement('video'), 'src', {get: noop, set: noop}); + Object.defineProperty(document.createElement('audio'), 'src', {get: noop, set: noop}); + } catch (e) { + return false; + } + + return true; +}; + /** * Check to see if native `TextTrack`s are supported by this browser/device. * @@ -981,6 +1089,14 @@ Html5.prototype.featuresVolumeControl = Html5.canControlVolume(); */ Html5.prototype.featuresPlaybackRate = Html5.canControlPlaybackRate(); +/** + * Boolean indicating wether the `Tech` supports the `sourceset` event. + * + * @type {boolean} + * @default + */ +Html5.prototype.featuresSourceset = Html5.canOverrideAttributes(); + /** * Boolean indicating whether the `HTML5` tech currently supports the media element * moving in the DOM. iOS breaks if you move the media element, so this is set this to diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index c13067c32a..04c9e4bc34 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -155,6 +155,34 @@ class Tech extends Component { } } + /** + * A special function to trigger source set in a way that will allow player + * to re-trigger if the player or tech are not ready yet. + * + * @fires Tech#sourceset + * @param {string} src The source string at the time of the source changing. + */ + triggerSourceset(src) { + if (!this.isReady_) { + // on initial ready we have to trigger source set + // 1ms after ready so that player can watch for it. + this.one('ready', () => this.setTimeout(() => this.triggerSourceset(src), 1)); + } + + /** + * Fired when the source is set on the tech causing the media element + * to reload. + * + * @see {@link Player#event:sourceset} + * @event Tech#sourceset + * @type {EventTarget~Event} + */ + this.trigger({ + src, + type: 'sourceset' + }); + } + /* Fallbacks for unsupported event types ================================================================================ */ @@ -989,6 +1017,18 @@ Tech.prototype.featuresPlaybackRate = false; */ Tech.prototype.featuresProgressEvents = false; +/** + * Boolean indicating wether the `Tech` supports the `sourceset` event. + * + * A tech should set this to `true` and then use {@link Tech#triggerSourceset} + * to trigger a {@link Tech#event:sourceset} at the earliest time after getting + * a new source. + * + * @type {boolean} + * @default + */ +Tech.prototype.featuresSourceset = false; + /** * Boolean indicating wether the `Tech` supports the `timeupdate` event. This is currently * not triggered by video-js-swf. This will be used to determine if diff --git a/test/unit/sourceset.test.js b/test/unit/sourceset.test.js new file mode 100644 index 0000000000..b94751bfaa --- /dev/null +++ b/test/unit/sourceset.test.js @@ -0,0 +1,550 @@ +/* eslint-env qunit */ +import videojs from '../../src/js/video.js'; +import document from 'global/document'; +import window from 'global/window'; +import log from '../../src/js/utils/log.js'; +import sinon from 'sinon'; + +const Html5 = videojs.getTech('Html5'); +const wait = 1; +let qunitFn = 'module'; +const testSrc = { + src: 'http://vjs.zencdn.net/v/oceans.mp4', + type: 'video/mp4' +}; +const sourceOne = {src: 'http://example.com/one.mp4', type: 'video/mp4'}; +const sourceTwo = {src: 'http://example.com/two.mp4', type: 'video/mp4'}; + +if (!Html5.canOverrideAttributes()) { + qunitFn = 'skip'; +} + +const oldMovingMedia = Html5.prototype.movingMediaElementInDOM; +const validateSource = function(assert, player, sources, checkMediaElSource = true) { + const tech = player.tech_; + const mediaEl = tech.el(); + + if (checkMediaElSource) { + assert.equal(mediaEl.src, sources[0].src, 'mediaEl.src is correct'); + assert.equal(mediaEl.getAttribute('src'), sources[0].src, 'mediaEl attribute is correct'); + assert.equal(tech.src(), sources[0].src, 'tech is correct'); + } +}; + +const setupEnv = function(env, testName) { + env.fixture = document.getElementById('qunit-fixture'); + + if (testName === 'change video el' || testName === 'change audio el') { + Html5.prototype.movingMediaElementInDOM = false; + } + + env.sourcesets = 0; + env.hook = (player) => player.on('sourceset', () => env.sourcesets++); + videojs.hook('setup', env.hook); + + if ((/audio/i).test(testName)) { + env.mediaEl = document.createElement('audio'); + } else { + env.mediaEl = document.createElement('video'); + } + env.testSrc = testSrc; + env.sourceOne = sourceOne; + env.sourceTwo = sourceTwo; + + env.mediaEl.className = 'video-js'; + env.fixture.appendChild(env.mediaEl); +}; + +const setupAfterEach = function(totalSourcesets) { + return function(assert) { + const done = assert.async(); + + if (typeof this.totalSourcesets === 'undefined') { + this.totalSourcesets = totalSourcesets; + } + + window.setTimeout(() => { + assert.equal(this.sourcesets, this.totalSourcesets, 'no additional sourcesets'); + + this.player.dispose(); + assert.equal(this.sourcesets, this.totalSourcesets, 'no source set on dispose'); + + videojs.removeHook('setup', this.hook); + Html5.prototype.movingMediaElementInDOM = oldMovingMedia; + log.error.restore(); + done(); + }, wait); + }; +}; + +const testTypes = ['video el', 'change video el', 'audio el', 'change audio el']; + +QUnit[qunitFn]('sourceset', function(hooks) { + QUnit.module('source before player', (subhooks) => testTypes.forEach((testName) => { + QUnit.module(testName, { + beforeEach() { + sinon.stub(log, 'error'); + + setupEnv(this, testName); + }, + afterEach: setupAfterEach(1) + }); + + QUnit.test('data-setup one source', function(assert) { + const done = assert.async(); + + this.mediaEl.setAttribute('data-setup', JSON.stringify({sources: [this.testSrc]})); + this.player = videojs(this.mediaEl); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + // TODO: unskip when https://github.com/videojs/video.js/pull/4861 is merged + QUnit.skip('data-setup preload auto', function(assert) { + const done = assert.async(); + + this.mediaEl.setAttribute('data-setup', JSON.stringify({sources: [this.testSrc]})); + this.mediaEl.setAttribute('preload', 'auto'); + this.player = videojs(this.mediaEl); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + QUnit.test('data-setup two sources', function(assert) { + const done = assert.async(); + + this.mediaEl.setAttribute('data-setup', JSON.stringify({sources: [this.sourceOne, this.sourceTwo]})); + this.player = videojs(this.mediaEl); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); + done(); + }); + }); + + QUnit.test('videojs({sources: [...]}) one source', function(assert) { + const done = assert.async(); + + this.player = videojs(this.mediaEl, {sources: [this.testSrc]}); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + QUnit.test('videojs({sources: [...]}) two sources', function(assert) { + const done = assert.async(); + + this.player = videojs(this.mediaEl, {sources: [this.sourceOne, this.sourceTwo]}); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); + done(); + }); + }); + + QUnit.test('player.src({...}) one source', function(assert) { + const done = assert.async(); + + this.player = videojs(this.mediaEl); + this.player.src(this.testSrc); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + // TODO: unskip when https://github.com/videojs/video.js/pull/4861 is merged + QUnit.skip('player.src({...}) preload auto', function(assert) { + const done = assert.async(); + + this.mediaEl.setAttribute('preload', 'auto'); + this.player = videojs(this.mediaEl); + this.player.src(this.testSrc); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + QUnit.test('player.src({...}) two sources', function(assert) { + const done = assert.async(); + + this.player = videojs(this.mediaEl); + this.player.src([this.sourceOne, this.sourceTwo]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); + done(); + }); + }); + + QUnit.test('mediaEl.src = ...;', function(assert) { + const done = assert.async(); + + this.mediaEl.src = this.testSrc.src; + this.player = videojs(this.mediaEl); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + QUnit.test('mediaEl.setAttribute("src", ...)"', function(assert) { + const done = assert.async(); + + this.mediaEl.setAttribute('src', this.testSrc.src); + this.player = videojs(this.mediaEl); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + QUnit.test(' one source', function(assert) { + const done = assert.async(); + + this.source = document.createElement('source'); + this.source.src = this.testSrc.src; + this.source.type = this.testSrc.type; + + this.mediaEl.appendChild(this.source); + + this.player = videojs(this.mediaEl); + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }); + + QUnit.test(' two sources', function(assert) { + const done = assert.async(); + + this.source = document.createElement('source'); + this.source.src = this.sourceOne.src; + this.source.type = this.sourceOne.type; + + this.source2 = document.createElement('source'); + this.source2.src = this.sourceTwo.src; + this.source2.type = this.sourceTwo.type; + + this.mediaEl.appendChild(this.source); + this.mediaEl.appendChild(this.source2); + + this.player = videojs(this.mediaEl); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); + done(); + }); + }); + + QUnit.test('no source', function(assert) { + const done = assert.async(); + + this.player = videojs(this.mediaEl); + + this.totalSourcesets = 0; + + window.setTimeout(() => { + assert.equal(this.sourcesets, 0, 'no sourceset'); + done(); + }, wait); + }); + })); + + QUnit.module('source change', (subhooks) => testTypes.forEach((testName) => { + QUnit.module(testName, { + beforeEach(assert) { + sinon.stub(log, 'error'); + const done = assert.async(); + + setupEnv(this, testName); + + this.mediaEl.src = this.testSrc.src; + this.player = videojs(this.mediaEl); + + this.player.ready(() => { + this.mediaEl = this.player.tech_.el(); + }); + + // intial sourceset should happen on player.ready + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + done(); + }); + }, + afterEach: setupAfterEach(3) + }); + + QUnit.test('player.src({...})', function(assert) { + const done = assert.async(); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne]); + done(); + }); + + this.player.src(this.sourceOne); + }); + + this.player.src(this.testSrc); + }); + + QUnit.test('player.src({...}) x2 at the same time', function(assert) { + const done = assert.async(); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceTwo]); + done(); + }); + }); + + this.player.src(this.sourceOne); + this.player.src(this.sourceTwo); + }); + + QUnit.test('mediaEl.src = ...', function(assert) { + const done = assert.async(); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne]); + done(); + }); + + this.mediaEl.src = this.sourceOne.src; + }); + + this.mediaEl.src = this.testSrc.src; + }); + + QUnit.test('mediaEl.src = ... x2 at the same time', function(assert) { + const done = assert.async(); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceTwo]); + done(); + }); + }); + + this.mediaEl.src = this.sourceOne.src; + this.mediaEl.src = this.sourceTwo.src; + }); + + QUnit.test('mediaEl.setAttribute("src", ...)', function(assert) { + const done = assert.async(); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne]); + done(); + }); + + this.mediaEl.setAttribute('src', this.sourceOne.src); + }); + + this.mediaEl.setAttribute('src', this.testSrc.src); + }); + + QUnit.test('mediaEl.setAttribute("src", ...) x2 at the same time', function(assert) { + const done = assert.async(); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne]); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceTwo]); + done(); + }); + }); + + this.mediaEl.setAttribute('src', this.sourceOne.src); + this.mediaEl.setAttribute('src', this.sourceTwo.src); + }); + + QUnit.test('mediaEl.load()', function(assert) { + const done = assert.async(); + const source = document.createElement('source'); + + source.src = this.testSrc.src; + source.type = this.testSrc.type; + + // the only way to unset a source, so that we use the source + // elements instead + this.mediaEl.removeAttribute('src'); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.testSrc], false); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne], false); + done(); + }); + + source.src = this.sourceOne.src; + source.type = this.sourceOne.type; + + this.mediaEl.load(); + }); + + this.mediaEl.appendChild(source); + this.mediaEl.load(); + }); + + QUnit.test('mediaEl.load() x2 at the same time', function(assert) { + const done = assert.async(); + const source = document.createElement('source'); + + source.src = this.sourceOne.src; + source.type = this.sourceOne.type; + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceOne], false); + + this.player.one('sourceset', () => { + validateSource(assert, this.player, [this.sourceTwo], false); + done(); + }); + }); + + // the only way to unset a source, so that we use the source + // elements instead + this.mediaEl.removeAttribute('src'); + this.mediaEl.appendChild(source); + this.mediaEl.load(); + + source.src = this.sourceTwo.src; + source.type = this.sourceTwo.type; + this.mediaEl.load(); + }); + + QUnit.test('adding a without load()', function(assert) { + const done = assert.async(); + const source = document.createElement('source'); + + source.src = this.testSrc.src; + source.type = this.testSrc.type; + + this.mediaEl.appendChild(source); + + this.totalSourcesets = 1; + + window.setTimeout(() => { + assert.equal(this.sourcesets, 1, 'does not trigger sourceset'); + done(); + }, wait); + }); + + QUnit.test('changing a s src without load()', function(assert) { + const done = assert.async(); + const source = document.createElement('source'); + + source.src = this.testSrc.src; + source.type = this.testSrc.type; + + this.mediaEl.appendChild(source); + + source.src = this.testSrc.src; + + this.totalSourcesets = 1; + + window.setTimeout(() => { + assert.equal(this.sourcesets, 1, 'does not trigger sourceset'); + done(); + }, wait); + }); + })); + + QUnit.test('sourceset event object has a src property', function(assert) { + const done = assert.async(); + const fixture = document.querySelector('#qunit-fixture'); + const vid = document.createElement('video'); + const Tech = videojs.getTech('Tech'); + const flashSrc = { + src: 'http://example.com/oceans.flv', + type: 'video/flv' + }; + let sourcesets = 0; + + class FakeFlash extends Html5 { + static isSupported() { + return true; + } + + static canPlayType(type) { + return type === 'video/flv' ? 'maybe' : ''; + } + + static canPlaySource(srcObj) { + return srcObj.type === 'video/flv'; + } + } + + videojs.registerTech('FakeFlash', FakeFlash); + + fixture.appendChild(vid); + + const player = videojs(vid, { + techOrder: ['fakeFlash', 'html5'] + }); + + player.src(flashSrc); + + player.ready(function() { + // the first sourceset comes from our FakeFlash because it extends Html5 tech + // which calls load() on dispose for various reasons + player.one('sourceset', function(e1) { + // ignore the first sourceset that gets called when disposing the original tech + + // the second sourceset ends up being the second source because when the first source is set + // the tech isn't ready so we delay it, then the second source comes and the tech is ready + // so it ends up being triggered immediately. + player.one('sourceset', function(e2) { + assert.equal(e2.src, sourceTwo.src, 'the second sourceset ends up being the second source'); + sourcesets++; + + // now that the tech is ready, we will re-trigger the original sourceset event + // and get the first source + player.one('sourceset', function(e3) { + assert.equal(e3.src, sourceOne.src, 'the third sourceset is the first source'); + sourcesets++; + + assert.equal(sourcesets, 2, 'two sourcesets'); + player.dispose(); + delete Tech.techs_.FakeFlash; + done(); + }); + }); + }); + + player.src(sourceOne); + player.src(sourceTwo); + }); + + }); +}); diff --git a/test/unit/tech/html5.test.js b/test/unit/tech/html5.test.js index 991f8d2fdf..887e614993 100644 --- a/test/unit/tech/html5.test.js +++ b/test/unit/tech/html5.test.js @@ -422,9 +422,11 @@ if (Html5.supportsNativeTextTracks()) { addEventListener: (type, fn) => events.push([type, fn]), removeEventListener: (type, fn) => events.push([type, fn]) }; - const el = document.createElement('div'); + const el = document.createElement('video'); - el.textTracks = tt; + Object.defineProperty(el, 'textTracks', { + get: () => tt + }); /* eslint-disable no-unused-vars */ const htmlTech = new Html5({el, nativeTextTracks: false}); From 8706941573052c4fff57c77862cd93054156c9eb Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 7 Mar 2018 20:31:50 +0100 Subject: [PATCH 009/371] feat: Allow techs to change poster if player option `techCanOverridePoster` is set (#4921) The option for the player techCanOverridePoster is introduced in this commit. It allows techs to update the post whenever they like. isPosterFromTech_ is introduced as a private player field in order to track when a poster was set by a tech. This allows us to clear the poster whenever the tech is disposed of by the player. Additionally, attempting to set the same poster more than once will have no effect / no changes will be made, since the poster is the same. This was done in order to stop triggering multiple posterchange events when calling player.poster(aPoster) with techCanOverridePoster set to true. When a tech is disposed and a poster was set by it, unset the poster. Pass a `canOverridePoster` option to techs to know whether techCanOverridePoster was set. Fixes #4910. --- docs/guides/options.md | 10 ++++ docs/guides/tech.md | 15 ++++++ src/js/player.js | 34 +++++++++++-- test/unit/player.test.js | 96 ++++++++++++++++++++++++++++++++++++ test/unit/tech/tech-faker.js | 1 + 5 files changed, 151 insertions(+), 5 deletions(-) diff --git a/docs/guides/options.md b/docs/guides/options.md index 72102dc06d..483979fbab 100644 --- a/docs/guides/options.md +++ b/docs/guides/options.md @@ -30,6 +30,7 @@ * [plugins](#plugins) * [sourceOrder](#sourceorder) * [sources](#sources) + * [techCanOverridePoster](#techCanOverridePoster) * [techOrder](#techorder) * [vtt.js](#vttjs) * [Component Options](#component-options) @@ -254,6 +255,15 @@ Using `` elements will have the same effect: ``` +### `techCanOverridePoster` + +> Type: `boolean` + +Gives the possibility to techs to override the player's poster +and integrate into the player's poster life-cycle. +This can be useful when multiple techs are used and each has to set their own poster + any time a new source is played. + ### `techOrder` > Type: `Array`, Default: `['html5']` diff --git a/docs/guides/tech.md b/docs/guides/tech.md index 89b4af6997..3eb896baba 100644 --- a/docs/guides/tech.md +++ b/docs/guides/tech.md @@ -57,6 +57,21 @@ videojs("videoID", { }); ``` +### Posters + +By default, techs will have to handle their own posters and are somewhat locked out of the player's poster lifecycle. +However, when the player is initialized with the `techCanOverridePoster` option +it will be possible for techs to integrate into that lifecycle and the player's `PosterImage` component to be used. + +Techs can check if they have this capability by checking the `canOverridePoster` boolean in their options. + +**`techCanOverridePoster` requirements** + + - `poster()` which returns the tech's current poster url + - `setPoster()` which updates the tech's poster url and triggers a `posterchange` event + which the player will handle + + ## Technology Ordering When Video.js is given an array of sources, which to use is determined by finding the first supported source / tech combination. Each tech will be queried in the order specified in `techOrder` whether it can play the first source. The first match wins. If no tech can play the first source, then the next will be tested. It's important to set the `type` of each source correctly for this test to be accurate. diff --git a/src/js/player.js b/src/js/player.js index faae8f3bb1..2447b2e001 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -317,6 +317,9 @@ class Player extends Component { // Run base component initializing with new options super(null, options, ready); + // Tracks when a tech changes the poster + this.isPosterFromTech_ = false; + // Turn off API access because we're loading a new tech that might load asynchronously this.isReady_ = false; @@ -513,6 +516,8 @@ class Player extends Component { if (this.tech_) { this.tech_.dispose(); + this.isPosterFromTech_ = false; + this.poster_ = ''; } if (this.playerElIngest_) { @@ -924,7 +929,8 @@ class Player extends Component { 'poster': this.poster(), 'language': this.language(), 'playerElIngest': this.playerElIngest_ || false, - 'vtt.js': this.options_['vtt.js'] + 'vtt.js': this.options_['vtt.js'], + 'canOverridePoster': !!this.options_.techCanOverridePoster }; TRACK_TYPES.names.forEach((name) => { @@ -1020,6 +1026,13 @@ class Player extends Component { this.tech_.dispose(); this.tech_ = false; + + if (this.isPosterFromTech_) { + this.poster_ = ''; + this.trigger('posterchange'); + } + + this.isPosterFromTech_ = false; } /** @@ -2692,12 +2705,18 @@ class Player extends Component { src = ''; } + if (src === this.poster_) { + return; + } + // update the internal poster variable this.poster_ = src; // update the tech's poster this.techCall_('setPoster', src); + this.isPosterFromTech_ = false; + // alert components that the poster has been set /** * This event fires when the poster image is changed on the player. @@ -2721,11 +2740,16 @@ class Player extends Component { * @private */ handleTechPosterChange_() { - if (!this.poster_ && this.tech_ && this.tech_.poster) { - this.poster_ = this.tech_.poster() || ''; + if ((!this.poster_ || this.options_.techCanOverridePoster) && this.tech_ && this.tech_.poster) { + const newPoster = this.tech_.poster() || ''; - // Let components know the poster has changed - this.trigger('posterchange'); + if (newPoster !== this.poster_) { + this.poster_ = newPoster; + this.isPosterFromTech_ = true; + + // Let components know the poster has changed + this.trigger('posterchange'); + } } } diff --git a/test/unit/player.test.js b/test/unit/player.test.js index b65e40b008..c81f81d847 100644 --- a/test/unit/player.test.js +++ b/test/unit/player.test.js @@ -1709,3 +1709,99 @@ QUnit.test('player.duration() sets the value of player.cache_.duration', functio player.duration(200); assert.equal(player.duration(), 200, 'duration() set and get integer duration value'); }); + +QUnit.test('setPoster in tech with `techCanOverridePoster` in player should override poster', function(assert) { + const player = TestHelpers.makePlayer({ + techCanOverridePoster: true + }); + const posterchangeSpy = sinon.spy(); + const firstPosterUrl = 'https://wherever.test/test.jpg'; + const techPosterUrl = 'https://somewhere.text/my/image.png'; + + assert.equal(player.options_.techCanOverridePoster, true, 'make sure player option was passed correctly'); + assert.equal(player.tech_.options_.canOverridePoster, true, 'make sure tech option was passed correctly'); + + player.on('posterchange', posterchangeSpy); + + player.poster(''); + assert.ok(posterchangeSpy.notCalled, 'posterchangeSpy not called when no change of poster'); + assert.equal(player.isPosterFromTech_, false, "ensure tech didn't change poster after empty call from player"); + + player.poster(firstPosterUrl); + assert.ok(posterchangeSpy.calledOnce, 'posterchangeSpy only called once on update'); + assert.equal(player.poster(), firstPosterUrl, "ensure tech didn't change poster after setting from player"); + assert.equal(player.isPosterFromTech_, false, "ensure player didn't mark poster as changed by the tech"); + + posterchangeSpy.reset(); + + player.tech_.setPoster(techPosterUrl); + assert.ok(posterchangeSpy.calledOnce, "posterchangeSpy should've been called"); + assert.equal(player.isPosterFromTech_, true, 'ensure player marked poster as set by tech after the fact'); + + player.dispose(); +}); + +QUnit.test('setPoster in tech WITHOUT `techCanOverridePoster` in player should NOT override poster', function(assert) { + const player = TestHelpers.makePlayer(); + const posterchangeSpy = sinon.spy(); + const firstPosterUrl = 'https://wherever.test/test.jpg'; + const techPosterUrl = 'https://somewhere.test/my/image.png'; + + assert.equal(player.options_.techCanOverridePoster, undefined, "ensure player option wasn't unwittingly set"); + assert.equal(player.tech_.options_.canOverridePoster, false, "ensure tech option wasn't unwittinyly set"); + + player.on('posterchange', posterchangeSpy); + + player.poster(firstPosterUrl); + assert.ok(posterchangeSpy.calledOnce, 'posterchangeSpy only called once on update'); + assert.equal(player.poster(), firstPosterUrl, "ensure tech didn't change poster after setting from player"); + assert.equal(player.isPosterFromTech_, false, "ensure player didn't mark poster as changed by the tech"); + + posterchangeSpy.reset(); + + player.tech_.setPoster(techPosterUrl); + assert.ok(posterchangeSpy.notCalled, "posterchangeSpy shouldn't have been called"); + assert.equal(player.isPosterFromTech_, false, "ensure tech didn't change poster because player option was false"); + + player.dispose(); +}); + +QUnit.test('disposing a tech that set a poster, should unset the poster', function(assert) { + const player = TestHelpers.makePlayer({ + techCanOverridePoster: true + }); + const techPosterUrl = 'https://somewhere.test/my/image.png'; + + assert.equal(player.options_.techCanOverridePoster, true, 'make sure player option was passed correctly'); + assert.equal(player.tech_.options_.canOverridePoster, true, 'make sure tech option was passed correctly'); + + player.tech_.setPoster(techPosterUrl); + assert.equal(player.poster(), techPosterUrl, 'player poster should equal tech poster'); + assert.equal(player.isPosterFromTech_, true, 'setting the poster with the tech should be remembered in the player'); + + player.unloadTech_(); + + assert.equal(player.poster(), '', 'ensure poster set by poster is unset after tech disposal'); + + player.dispose(); +}); + +QUnit.test('disposing a tech that dit NOT set a poster, should keep the poster', function(assert) { + const player = TestHelpers.makePlayer({ + techCanOverridePoster: true + }); + const posterUrl = 'https://myposter.test/lol.jpg'; + + assert.equal(player.options_.techCanOverridePoster, true, 'make sure player option was passed correctly'); + assert.equal(player.tech_.options_.canOverridePoster, true, 'make sure tech option was passed correctly'); + + player.poster(posterUrl); + assert.equal(player.poster(), posterUrl, 'player poster should NOT have changed'); + assert.equal(player.isPosterFromTech_, false, 'player should mark poster as set by itself'); + + player.unloadTech_(); + + assert.equal(player.poster(), posterUrl, 'player poster should stay the same after unloading / dispoing tech'); + + player.dispose(); +}); diff --git a/test/unit/tech/tech-faker.js b/test/unit/tech/tech-faker.js index 1b0ca50a27..b83beb5024 100644 --- a/test/unit/tech/tech-faker.js +++ b/test/unit/tech/tech-faker.js @@ -28,6 +28,7 @@ class TechFaker extends Tech { } setPoster(val) { this.el().poster = val; + this.trigger('posterchange'); } setControls(val) {} From 62ff3f66a50c0a908188de9c140011e7c5fd44dc Mon Sep 17 00:00:00 2001 From: David GG Date: Wed, 7 Mar 2018 20:34:16 +0100 Subject: [PATCH 010/371] feat: add mimetype type to source object when possible (#4469) (#4947) File mimetype is filled when the file extension is known and type is not provided. Fixes #4469, improves #4851. --- src/js/utils/filter-source.js | 25 +++++++++- src/js/utils/mimetypes.js | 19 ++++++++ test/unit/utils/filter-source.test.js | 66 +++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 src/js/utils/mimetypes.js diff --git a/src/js/utils/filter-source.js b/src/js/utils/filter-source.js index d8ab9df5a9..b5ede4ab3c 100644 --- a/src/js/utils/filter-source.js +++ b/src/js/utils/filter-source.js @@ -2,6 +2,8 @@ * @module filter-source */ import {isObject} from './obj'; +import {MimetypesKind} from './mimetypes'; +import * as Url from '../utils/url.js'; /** * Filter out single bad source objects or multiple source objects in an @@ -34,10 +36,10 @@ const filterSource = function(src) { src = newsrc; } else if (typeof src === 'string' && src.trim()) { // convert string into object - src = [{src}]; + src = [checkMimetype({src})]; } else if (isObject(src) && typeof src.src === 'string' && src.src && src.src.trim()) { // src is already valid - src = [src]; + src = [checkMimetype(src)]; } else { // invalid source, turn it into an empty array src = []; @@ -46,4 +48,23 @@ const filterSource = function(src) { return src; }; +/** + * Checks src mimetype, adding it when possible + * + * @param {Tech~SourceObject} src + * The src object to check + * @return {Tech~SourceObject} + * src Object with known type + */ +function checkMimetype(src) { + const ext = Url.getFileExtension(src.src); + const mimetype = MimetypesKind[ext.toLowerCase()]; + + if (!src.type && mimetype) { + src.type = mimetype; + } + + return src; +} + export default filterSource; diff --git a/src/js/utils/mimetypes.js b/src/js/utils/mimetypes.js new file mode 100644 index 0000000000..9a44c2d267 --- /dev/null +++ b/src/js/utils/mimetypes.js @@ -0,0 +1,19 @@ +/** + * Mimetypes + * + * @see http://hul.harvard.edu/ois/////systems/wax/wax-public-help/mimetypes.htm + * @typedef Mimetypes~Kind + * @enum + */ +export const MimetypesKind = { + opus: 'video/ogg', + ogv: 'video/ogg', + mp4: 'video/mp4', + mov: 'video/mp4', + m4v: 'video/mp4', + mkv: 'video/x-matroska', + mp3: 'audio/mpeg', + aac: 'audio/aac', + oga: 'audio/ogg', + m3u8: 'application/x-mpegURL' +}; diff --git a/test/unit/utils/filter-source.test.js b/test/unit/utils/filter-source.test.js index 1891fc41a0..86903c4886 100644 --- a/test/unit/utils/filter-source.test.js +++ b/test/unit/utils/filter-source.test.js @@ -122,3 +122,69 @@ QUnit.test('Dont filter extra object properties', function(assert) { ); }); + +QUnit.test('SourceObject type is filled with default values when extension is known', function(assert) { + assert.deepEqual( + filterSource('some-url.mp4'), + [{src: 'some-url.mp4', type: 'video/mp4'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource('some-url.ogv'), + [{src: 'some-url.ogv', type: 'video/ogg'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource('some-url.aac'), + [{src: 'some-url.aac', type: 'audio/aac'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource({src: 'some-url.mp4'}), + [{src: 'some-url.mp4', type: 'video/mp4'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource({src: 'some-url.ogv'}), + [{src: 'some-url.ogv', type: 'video/ogg'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource([{src: 'some-url.MP4'}, {src: 'some-url.OgV'}, {src: 'some-url.AaC'}]), + [{src: 'some-url.MP4', type: 'video/mp4'}, {src: 'some-url.OgV', type: 'video/ogg'}, {src: 'some-url.AaC', type: 'audio/aac'}], + 'string source filters to object' + ); +}); + +QUnit.test('SourceObject type is not filled when extension is unknown', function(assert) { + assert.deepEqual( + filterSource('some-url.ppp'), + [{src: 'some-url.ppp'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource('some-url.a'), + [{src: 'some-url.a'}], + 'string source filters to object' + ); + + assert.deepEqual( + filterSource('some-url.mp8'), + [{src: 'some-url.mp8'}], + 'string source filters to object' + ); +}); + +QUnit.test('SourceObject type is not changed when type exists', function(assert) { + assert.deepEqual( + filterSource({src: 'some-url.aac', type: 'video/zzz'}), + [{src: 'some-url.aac', type: 'video/zzz'}], + 'string source filters to object' + ); +}); From 2f96914b8e570fc16d19b546fa0bfe26ab0b727c Mon Sep 17 00:00:00 2001 From: twosmalltrees Date: Thu, 8 Mar 2018 06:37:10 +1100 Subject: [PATCH 011/371] feat(format time): add setFormatTime for overriding the time format (#4962) Add setFormatTime for Video.js to allow users to change the time format. Example usage: ```js videojs.setFormatTime((seconds, guide) => `${seconds}, ${guide}`)); ``` Add resetFormatTime to reset the time format to the default. Fixes #2931 --- src/js/utils/format-time.js | 30 +++++++++++++++++++++++++---- src/js/video.js | 25 +++++++++++++++++++++++- test/unit/utils/format-time.test.js | 19 ++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/js/utils/format-time.js b/src/js/utils/format-time.js index 5405f910c7..fe259d95da 100644 --- a/src/js/utils/format-time.js +++ b/src/js/utils/format-time.js @@ -1,9 +1,9 @@ /** * @file format-time.js - * @module Format-time + * @module format-time */ -/** + /** * Format seconds as a time string, H:MM:SS or M:SS. Supplying a guide (in seconds) * will force a number of leading zeros to cover the length of the guide. * @@ -16,7 +16,7 @@ * @return {string} * Time formatted as H:MM:SS or M:SS */ -function formatTime(seconds, guide = seconds) { +const defaultImplementation = function(seconds, guide) { seconds = seconds < 0 ? 0 : seconds; let s = Math.floor(seconds % 60); let m = Math.floor(seconds / 60 % 60); @@ -42,6 +42,28 @@ function formatTime(seconds, guide = seconds) { s = (s < 10) ? '0' + s : s; return h + m + s; +}; + +let implementation = defaultImplementation; + +/** + * Replaces the default formatTime implementation with a custom implementation. + * + * @param {Function} customImplementation + * A function which will be used in place of the default formatTime implementation. + * Will receive the current time in seconds and the guide (in seconds) as arguments. + */ +export function setFormatTime(customImplementation) { + implementation = customImplementation; } -export default formatTime; +/** + * Resets formatTime to the default implementation. + */ +export function resetFormatTime() { + implementation = defaultImplementation; +} + +export default function(seconds, guide = seconds) { + return implementation(seconds, guide); +} diff --git a/src/js/video.js b/src/js/video.js index 9f8aabba3c..8bebb496aa 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -19,7 +19,7 @@ import AudioTrack from './tracks/audio-track.js'; import VideoTrack from './tracks/video-track.js'; import { createTimeRanges } from './utils/time-ranges.js'; -import formatTime from './utils/format-time.js'; +import formatTime, { setFormatTime, resetFormatTime } from './utils/format-time.js'; import log from './utils/log.js'; import * as Dom from './utils/dom.js'; import * as browser from './utils/browser.js'; @@ -566,10 +566,33 @@ videojs.createTimeRange = videojs.createTimeRanges = createTimeRanges; */ videojs.formatTime = formatTime; +/** + * Replaces format-time with a custom implementation, to be used in place of the default. + * + * @borrows format-time:setFormatTime as videojs.setFormatTime + * + * @method setFormatTime + * + * @param {Function} customFn + * A custom format-time function which will be called with the current time and guide (in seconds) as arguments. + * Passed fn should return a string. + */ +videojs.setFormatTime = setFormatTime; + +/** + * Resets format-time to the default implementation. + * + * @borrows format-time:resetFormatTime as videojs.resetFormatTime + * + * @method resetFormatTime + */ +videojs.resetFormatTime = resetFormatTime; + /** * Resolve and parse the elements of a URL * * @borrows url:parseUrl as videojs.parseUrl + * */ videojs.parseUrl = Url.parseUrl; diff --git a/test/unit/utils/format-time.test.js b/test/unit/utils/format-time.test.js index ab070d540d..ec64aa5670 100644 --- a/test/unit/utils/format-time.test.js +++ b/test/unit/utils/format-time.test.js @@ -1,7 +1,9 @@ /* eslint-env qunit */ -import formatTime from '../../../src/js/utils/format-time.js'; +import formatTime, { setFormatTime, resetFormatTime } from '../../../src/js/utils/format-time.js'; -QUnit.module('format-time'); +QUnit.module('format-time standard implementation', { + afterEach: resetFormatTime() +}); QUnit.test('should format time as a string', function(assert) { assert.ok(formatTime(1) === '0:01'); @@ -33,3 +35,16 @@ QUnit.test('should format invalid times as dashes', function(assert) { assert.equal(formatTime(10, Infinity), '0:00:10'); assert.equal(formatTime(90, NaN), '1:30'); }); + +QUnit.test('setFormatTime', function(assert) { + setFormatTime((seconds, guide) => `custom:${seconds}:${guide}`); + assert.equal(formatTime(1, 2), 'custom:1:2', 'it should replace the default formatTime implementation'); +}); + +QUnit.test('resetFormatTime ', function(assert) { + setFormatTime((seconds, guide) => `custom:${seconds}:${guide}`); + assert.equal(formatTime(1, 2), 'custom:1:2'); + resetFormatTime(); + assert.equal(formatTime(1), '0:01', 'it should reset formatTime to the default implementation'); +}); + From 43b5a6dc5fa1579b652630a9d2e3867aec6c9092 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 12 Mar 2018 13:36:20 -0400 Subject: [PATCH 012/371] chore: make sure first-timers bot uses our template (#5001) --- .github/first-timers-issue-template.md | 2 +- .github/first-timers.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .github/first-timers.yml diff --git a/.github/first-timers-issue-template.md b/.github/first-timers-issue-template.md index f526f65c57..bbc9c7de55 100644 --- a/.github/first-timers-issue-template.md +++ b/.github/first-timers-issue-template.md @@ -13,7 +13,7 @@ Nothing. This issue is meant to welcome you to Open Source :) We are happy to wa - [ ] 🙋 **Claim this issue**: Comment below. - Once claimed, we'll add a 'claimed' label to the issue so others will know not to work on it. + Once claimed, we'll remove the 'unclaimed' label from the issue so others will know not to work on it. - [ ] 📝 **Update** the file [$FILENAME]($BRANCH_URL) in the `$REPO` repository (press the little pen Icon) and edit the line as shown below. diff --git a/.github/first-timers.yml b/.github/first-timers.yml new file mode 100644 index 0000000000..3aa3c28831 --- /dev/null +++ b/.github/first-timers.yml @@ -0,0 +1,5 @@ +labels: + - first-timers-only + - unclaimed +template: .github/first_timers_issue_template.md + From ba6a71eb0193341e11208853f4e53dcd867cbaa0 Mon Sep 17 00:00:00 2001 From: Viktor S <37144243+vsoren@users.noreply.github.com> Date: Tue, 13 Mar 2018 17:03:39 +0100 Subject: [PATCH 013/371] fix: don't add captions settings menu item when TextTrackSettings is disabled (#5002) Removes the CaptionsSettingsMenuItem when TextTrackSettings is not included. Fixes #4996 --- .../control-bar/text-track-controls/captions-button.js | 3 ++- .../control-bar/text-track-controls/subs-caps-button.js | 3 ++- test/unit/tracks/text-track-settings.test.js | 9 +++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/js/control-bar/text-track-controls/captions-button.js b/src/js/control-bar/text-track-controls/captions-button.js index 46f3f579c4..dc3a1a5834 100644 --- a/src/js/control-bar/text-track-controls/captions-button.js +++ b/src/js/control-bar/text-track-controls/captions-button.js @@ -51,7 +51,8 @@ class CaptionsButton extends TextTrackButton { createItems() { const items = []; - if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks)) { + if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && + this.player().getChild('textTrackSettings')) { items.push(new CaptionSettingsMenuItem(this.player_, {kind: this.kind_})); this.hideThreshold_ += 1; diff --git a/src/js/control-bar/text-track-controls/subs-caps-button.js b/src/js/control-bar/text-track-controls/subs-caps-button.js index ce3514a1a1..9452d34580 100644 --- a/src/js/control-bar/text-track-controls/subs-caps-button.js +++ b/src/js/control-bar/text-track-controls/subs-caps-button.js @@ -48,7 +48,8 @@ class SubsCapsButton extends TextTrackButton { createItems() { let items = []; - if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks)) { + if (!(this.player().tech_ && this.player().tech_.featuresNativeTextTracks) && + this.player().getChild('textTrackSettings')) { items.push(new CaptionSettingsMenuItem(this.player_, {kind: this.label_})); this.hideThreshold_ += 1; diff --git a/test/unit/tracks/text-track-settings.test.js b/test/unit/tracks/text-track-settings.test.js index cfcf5506ac..8afc2eb491 100644 --- a/test/unit/tracks/text-track-settings.test.js +++ b/test/unit/tracks/text-track-settings.test.js @@ -3,6 +3,7 @@ import TextTrackSettings from '../../../src/js/tracks/text-track-settings.js'; import TestHelpers from '../test-helpers.js'; import * as Events from '../../../src/js/utils/events.js'; import safeParseTuple from 'safe-json-parse/tuple'; +import sinon from 'sinon'; import window from 'global/window'; import Component from '../../../src/js/component.js'; @@ -174,26 +175,34 @@ QUnit.test('should restore default settings', function(assert) { }); QUnit.test('should open on click', function(assert) { + const clock = sinon.useFakeTimers(); const player = TestHelpers.makePlayer({ tracks }); + clock.tick(1); + Events.trigger(player.$('.vjs-texttrack-settings'), 'click'); assert.ok(!player.textTrackSettings.hasClass('vjs-hidden'), 'settings open'); player.dispose(); + clock.restore(); }); QUnit.test('should close on done click', function(assert) { + const clock = sinon.useFakeTimers(); const player = TestHelpers.makePlayer({ tracks }); + clock.tick(1); + Events.trigger(player.$('.vjs-texttrack-settings'), 'click'); Events.trigger(player.$('.vjs-done-button'), 'click'); assert.ok(player.textTrackSettings.hasClass('vjs-hidden'), 'settings closed'); player.dispose(); + clock.restore(); }); QUnit.test('if persist option is set, restore settings on init', function(assert) { From e833d3e3de3ed866e33d7d3ff18ca009ec956b1f Mon Sep 17 00:00:00 2001 From: Mayde Date: Wed, 14 Mar 2018 00:04:18 +0800 Subject: [PATCH 014/371] chore(dom.js): Fix misspellings (#5008) --- src/js/utils/dom.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/utils/dom.js b/src/js/utils/dom.js index 2bcdb7727f..d81512d04f 100644 --- a/src/js/utils/dom.js +++ b/src/js/utils/dom.js @@ -761,7 +761,7 @@ export function isSingleLeftClick(event) { // otherwise `mousedown` should be enough for a button if (event.button === undefined && event.buttons === undefined) { - // Why do we need `butttons` ? + // Why do we need `buttons` ? // Because, middle mouse sometimes have this: // e.button === 0 and e.buttons === 4 // Furthermore, we want to prevent combination click, something like From d2f63ad36434ef2eb0009a93f43a8f585b1e1e97 Mon Sep 17 00:00:00 2001 From: Kevin Reynolds Date: Tue, 13 Mar 2018 15:17:18 -0400 Subject: [PATCH 015/371] feat: Use CSS grid for Caption Settings dialog to begin making it more responsive (#4997) If CSS Grid is available, the Captions Settings Dialog will use it for the layout to begin making it more responsive. It will fallback to the current layout method if CSS Grid isn't available. --- src/css/components/_captions-settings.scss | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/css/components/_captions-settings.scss b/src/css/components/_captions-settings.scss index d6ee789d76..8f12143624 100644 --- a/src/css/components/_captions-settings.scss +++ b/src/css/components/_captions-settings.scss @@ -21,7 +21,37 @@ vertical-align: bottom; } +// code that will only run if CSS Grid is supported by the browser +@supports (display: grid) { + .vjs-text-track-settings .vjs-modal-dialog-content { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr auto; + } + + .vjs-text-track-settings .vjs-track-settings-colors { + display: block; + grid-column: 1; + grid-row: 1; + } + + .vjs-text-track-settings .vjs-track-settings-font { + grid-column: 2; + grid-row: 1; + } + + .vjs-text-track-settings .vjs-track-settings-controls { + grid-column: 2; + grid-row: 2; + + } +} + // Form elements +.vjs-track-setting > select { + margin-right: 5px; +} + .vjs-text-track-settings fieldset { margin: 5px; padding: 3px; @@ -30,7 +60,6 @@ .vjs-text-track-settings fieldset span { display: inline-block; - margin-left: 5px; } .vjs-text-track-settings legend { From 8d86afdb75c1061c8b340fa8cec4954b65a8c704 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Tue, 13 Mar 2018 16:01:18 -0400 Subject: [PATCH 016/371] revert: Revert "fix: force autoplay in Chrome (#4804)" (#5009) This reverts commit 6fe7a9a. The PR #4804, which fixes #4720, causes a regression #5005. When testing for the regression, the original issue is no longer reproducible so the fix should be backed out. If someone is still using the old version of chrome and seeing the behavior of #4720, they can continue using the versions of Video.js that contain the fixed made in #4804: 6.5.2, 6.6x, 6.7.x. Fixes #5005. --- src/js/player.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index 2447b2e001..a5a8ecbad9 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -475,8 +475,6 @@ class Player extends Component { this.changingSrc_ = false; this.playWaitingForReady_ = false; this.playOnLoadstart_ = null; - - this.forceAutoplayInChrome_(); } /** @@ -2616,29 +2614,11 @@ class Player extends Component { if (value !== undefined) { this.techCall_('setAutoplay', value); this.options_.autoplay = value; - this.ready(this.forceAutoplayInChrome_); return; } return this.techGet_('autoplay', value); } - /** - * chrome started pausing the video when moving in the DOM - * causing autoplay to not continue due to how Video.js functions. - * See #4720 for more info. - * - * @private - */ - forceAutoplayInChrome_() { - if (this.paused() && - // read from the video element or options - (this.autoplay() || this.options_.autoplay) && - // only target desktop chrome - (browser.IS_CHROME && !browser.IS_ANDROID)) { - this.play(); - } - } - /** * Set or unset the playsinline attribute. * Playsinline tells the browser that non-fullscreen playback is preferred. From 1532df32fb78f899cba716dd9400879f44401f51 Mon Sep 17 00:00:00 2001 From: Mayde Date: Thu, 15 Mar 2018 22:18:22 +0800 Subject: [PATCH 017/371] docs(component): fix misspellings (#5017) --- src/js/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/component.js b/src/js/component.js index 6759c42c96..35504b10a5 100644 --- a/src/js/component.js +++ b/src/js/component.js @@ -223,7 +223,7 @@ class Component { * Localize a string given the string in english. * * If tokens are provided, it'll try and run a simple token replacement on the provided string. - * The tokens it loooks for look like `{1}` with the index being 1-indexed into the tokens array. + * The tokens it looks for look like `{1}` with the index being 1-indexed into the tokens array. * * If a `defaultValue` is provided, it'll use that over `string`, * if a value isn't found in provided language files. From ebbe86812bf6f9d105c2f81b97496a5a2e00c217 Mon Sep 17 00:00:00 2001 From: Mayde Date: Thu, 15 Mar 2018 22:18:48 +0800 Subject: [PATCH 018/371] docs(component): fix misspelllings (#5019) --- src/js/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/component.js b/src/js/component.js index 35504b10a5..3b3e0e0ff0 100644 --- a/src/js/component.js +++ b/src/js/component.js @@ -630,7 +630,7 @@ class Component { triggerReady() { this.isReady_ = true; - // Ensure ready is triggerd asynchronously + // Ensure ready is triggered asynchronously this.setTimeout(function() { const readyQueue = this.readyQueue_; From 4e83cd3e3f0f6f824dc448a0a2c178e1adbee776 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Thu, 15 Mar 2018 11:16:42 -0400 Subject: [PATCH 019/371] test(ResizeManager): only listen for one playerresize to make test not flaky (#5022) --- test/unit/resize-manager.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/resize-manager.test.js b/test/unit/resize-manager.test.js index 689a0727ae..603144cae5 100644 --- a/test/unit/resize-manager.test.js +++ b/test/unit/resize-manager.test.js @@ -87,7 +87,7 @@ if (!browser.IS_IE8) { let playerresizeCalled = 0; const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver}); - this.player.on('playerresize', function() { + this.player.one('playerresize', function() { playerresizeCalled++; }); observer(); From 46d8b3738567c43a4818dd0abe086fc4bd041dbd Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Thu, 15 Mar 2018 15:05:41 -0400 Subject: [PATCH 020/371] fix(sourceset): set evt.src to empty string or src attr from load (#5016) If .load() is called, we don't know what the new source will be because of the asynchronous nature of the resource selection algorithm. However, we can know if the src attribute is set on the video element because that's what will be chosen. So, set the src property on the event object to be the src attribute or be the empty string. This matches how currentSrc works where it is an empty string when no source is set. So, when sourceset is triggered and src is "" in the event object, it means that the source is changing. In addition, we're going to be releasing sourceset as an experimental feature so we could improve the API and make changes in minor releases. --- src/js/player.js | 15 ++++++++--- src/js/tech/html5.js | 7 ++++- test/karma.conf.js | 2 +- test/unit/sourceset.test.js | 51 +++++++++++++++++++++++++------------ 4 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index a5a8ecbad9..04ade58938 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -1186,7 +1186,7 @@ class Player extends Component { } /** - * Fired when the source is set or changed on the {@link Tech} + * *EXPERIMENTAL* Fired when the source is set or changed on the {@link Tech} * causing the media element to reload. * * It will fire for the initial source and each subsequent source. @@ -1198,12 +1198,19 @@ class Player extends Component { * * It is also fired when `load` is called on the player (or media element) * because the {@link https://html.spec.whatwg.org/multipage/media.html#dom-media-load|specification for `load`} - * says that the resource selection algorithm - * needs to be aborted and restarted. + * says that the resource selection algorithm needs to be aborted and restarted. + * In this case, it is very likely that the `src` property will be set to the + * empty string `""` to indicate we do not know what the source will be but + * that it is changing. + * + * *This event is currently still experimental and may change in minor releases.* * * @event Player#sourceset * @type {EventTarget~Event} - * @prop {string} src The source url available when the `sourceset` was triggered + * @prop {string} src + * The source url available when the `sourceset` was triggered. + * It will be an empty string if we cannot know what the source is + * but know that the source will change. */ /** * Retrigger the `sourceset` event that was triggered by the {@link Tech}. diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index fcdb86a7f5..39b438b7e3 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -195,7 +195,12 @@ class Html5 extends Tech { el.load = () => { const retval = oldLoad.call(el); - this.triggerSourceset(el.src || el.currentSrc); + // if `el.src` is set, that source will be loaded + // otherwise, we can't know for sure what source will be set because + // source elements will be used but implementing the source selection algorithm + // is laborious and asynchronous, so, + // instead return an empty string to basically indicate source may change + this.triggerSourceset(el.src || ''); return retval; }; diff --git a/test/karma.conf.js b/test/karma.conf.js index b2bd7fdf88..83f6fdcd2c 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -169,7 +169,7 @@ function getCustomLaunchers(){ base: 'BrowserStack', browser: 'safari', os: 'OS X', - os_version: 'Yosemite' + os_version: 'El Capitan' }, edge_bs: { diff --git a/test/unit/sourceset.test.js b/test/unit/sourceset.test.js index b94751bfaa..27eb72c3c2 100644 --- a/test/unit/sourceset.test.js +++ b/test/unit/sourceset.test.js @@ -154,12 +154,12 @@ QUnit[qunitFn]('sourceset', function(hooks) { const done = assert.async(); this.player = videojs(this.mediaEl); - this.player.src(this.testSrc); - this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); done(); }); + + this.player.src(this.testSrc); }); // TODO: unskip when https://github.com/videojs/video.js/pull/4861 is merged @@ -168,24 +168,26 @@ QUnit[qunitFn]('sourceset', function(hooks) { this.mediaEl.setAttribute('preload', 'auto'); this.player = videojs(this.mediaEl); - this.player.src(this.testSrc); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); done(); }); + + this.player.src(this.testSrc); }); QUnit.test('player.src({...}) two sources', function(assert) { const done = assert.async(); this.player = videojs(this.mediaEl); - this.player.src([this.sourceOne, this.sourceTwo]); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); done(); }); + + this.player.src([this.sourceOne, this.sourceTwo]); }); QUnit.test('mediaEl.src = ...;', function(assert) { @@ -387,8 +389,28 @@ QUnit[qunitFn]('sourceset', function(hooks) { this.mediaEl.setAttribute('src', this.sourceTwo.src); }); - QUnit.test('mediaEl.load()', function(assert) { + QUnit.test('load() with a src attribute', function(assert) { const done = assert.async(); + + this.player = videojs(this.mediaEl); + + this.totalSourcesets = 1; + + window.setTimeout(() => { + this.sourcesets = 0; + this.totalSourcesets = 1; + + this.player.one('sourceset', (e) => { + assert.equal(e.src, this.mediaEl.src, "the sourceset event's src matches the src attribute"); + + done(); + }); + + this.player.load(); + }, wait); + }); + + QUnit.test('mediaEl.load()', function(assert) { const source = document.createElement('source'); source.src = this.testSrc.src; @@ -398,12 +420,11 @@ QUnit[qunitFn]('sourceset', function(hooks) { // elements instead this.mediaEl.removeAttribute('src'); - this.player.one('sourceset', () => { - validateSource(assert, this.player, [this.testSrc], false); + this.player.one('sourceset', (e1) => { + assert.equal(e1.src, '', 'we got a sourceset with an empty src'); - this.player.one('sourceset', () => { - validateSource(assert, this.player, [this.sourceOne], false); - done(); + this.player.one('sourceset', (e2) => { + assert.equal(e2.src, '', 'we got a sourceset with an empty src'); }); source.src = this.sourceOne.src; @@ -417,18 +438,16 @@ QUnit[qunitFn]('sourceset', function(hooks) { }); QUnit.test('mediaEl.load() x2 at the same time', function(assert) { - const done = assert.async(); const source = document.createElement('source'); source.src = this.sourceOne.src; source.type = this.sourceOne.type; - this.player.one('sourceset', () => { - validateSource(assert, this.player, [this.sourceOne], false); + this.player.one('sourceset', (e1) => { + assert.equal(e1.src, '', 'we got a sourceset with an empty src'); - this.player.one('sourceset', () => { - validateSource(assert, this.player, [this.sourceTwo], false); - done(); + this.player.one('sourceset', (e2) => { + assert.equal(e2.src, '', 'we got a sourceset with an empty src'); }); }); From bd6b31c48b26785e508e841ec6cf39335dcff9e8 Mon Sep 17 00:00:00 2001 From: Mayde Date: Fri, 16 Mar 2018 22:57:07 +0800 Subject: [PATCH 021/371] docs(time-ranges): fix misspellings (#5025) --- src/js/utils/time-ranges.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/utils/time-ranges.js b/src/js/utils/time-ranges.js index e848eade4a..84c390f478 100644 --- a/src/js/utils/time-ranges.js +++ b/src/js/utils/time-ranges.js @@ -30,7 +30,7 @@ * Returns the time offset at which a specified time range begins. * * @property {time-ranges:indexFunction} end - * Returns the time offset at which a specified time range begins. + * Returns the time offset at which a specified time range ends. * * @see https://developer.mozilla.org/en-US/docs/Web/API/TimeRanges */ @@ -83,7 +83,7 @@ function getRange(fnName, valueIndex, ranges, rangeIndex) { } /** - * Create a time range object givent ranges of time. + * Create a time range object given ranges of time. * * @param {Array} [ranges] * An array of time ranges. From d7f45bab89790fe84f8fcc162df2b9e2ff6d265b Mon Sep 17 00:00:00 2001 From: Mayde Date: Fri, 16 Mar 2018 22:58:37 +0800 Subject: [PATCH 022/371] docs(time-ranges): fix wrong comment for getRange function (#5026) --- src/js/utils/time-ranges.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/js/utils/time-ranges.js b/src/js/utils/time-ranges.js index 84c390f478..1351398522 100644 --- a/src/js/utils/time-ranges.js +++ b/src/js/utils/time-ranges.js @@ -56,7 +56,8 @@ function rangeCheck(fnName, index, maxIndex) { } /** - * Check if any of the time ranges are over the maximum index. + * Get the time for the specified index at the start or end + * of a TimeRange object. * * @param {string} fnName * The function name to use for logging From 1b3c827d5e6d125ef918581b289030c9880533cf Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 19 Mar 2018 13:47:45 -0400 Subject: [PATCH 023/371] feat: require enableSourceset option for event (#5031) While sourceset is experimental, require the option `enableSourceset`. This can easily be reversed in a minor update. --- src/js/player.js | 4 ++- src/js/tech/html5.js | 4 ++- test/unit/sourceset.test.js | 63 ++++++++++++++++++++++++++++--------- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index 04ade58938..4085c05c77 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -928,7 +928,8 @@ class Player extends Component { 'language': this.language(), 'playerElIngest': this.playerElIngest_ || false, 'vtt.js': this.options_['vtt.js'], - 'canOverridePoster': !!this.options_.techCanOverridePoster + 'canOverridePoster': !!this.options_.techCanOverridePoster, + 'enableSourceset': this.options_.enableSourceset }; TRACK_TYPES.names.forEach((name) => { @@ -1204,6 +1205,7 @@ class Player extends Component { * that it is changing. * * *This event is currently still experimental and may change in minor releases.* + * __To use this, pass `enableSourceset` option to the player.__ * * @event Player#sourceset * @type {EventTarget~Event} diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 39b438b7e3..02479d2ca3 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -34,7 +34,9 @@ class Html5 extends Tech { constructor(options, ready) { super(options, ready); - this.setupSourcesetHandling_(); + if (options.enableSourceset) { + this.setupSourcesetHandling_(); + } const source = options.source; let crossoriginTracks = false; diff --git a/test/unit/sourceset.test.js b/test/unit/sourceset.test.js index 27eb72c3c2..e542920ff6 100644 --- a/test/unit/sourceset.test.js +++ b/test/unit/sourceset.test.js @@ -94,7 +94,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { const done = assert.async(); this.mediaEl.setAttribute('data-setup', JSON.stringify({sources: [this.testSrc]})); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); @@ -108,7 +110,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { this.mediaEl.setAttribute('data-setup', JSON.stringify({sources: [this.testSrc]})); this.mediaEl.setAttribute('preload', 'auto'); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); @@ -120,7 +124,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { const done = assert.async(); this.mediaEl.setAttribute('data-setup', JSON.stringify({sources: [this.sourceOne, this.sourceTwo]})); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); @@ -131,7 +137,10 @@ QUnit[qunitFn]('sourceset', function(hooks) { QUnit.test('videojs({sources: [...]}) one source', function(assert) { const done = assert.async(); - this.player = videojs(this.mediaEl, {sources: [this.testSrc]}); + this.player = videojs(this.mediaEl, { + enableSourceset: true, + sources: [this.testSrc] + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); @@ -142,7 +151,10 @@ QUnit[qunitFn]('sourceset', function(hooks) { QUnit.test('videojs({sources: [...]}) two sources', function(assert) { const done = assert.async(); - this.player = videojs(this.mediaEl, {sources: [this.sourceOne, this.sourceTwo]}); + this.player = videojs(this.mediaEl, { + enableSourceset: true, + sources: [this.sourceOne, this.sourceTwo] + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); @@ -153,7 +165,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { QUnit.test('player.src({...}) one source', function(assert) { const done = assert.async(); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); done(); @@ -167,7 +181,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { const done = assert.async(); this.mediaEl.setAttribute('preload', 'auto'); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); @@ -180,7 +196,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { QUnit.test('player.src({...}) two sources', function(assert) { const done = assert.async(); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); @@ -194,7 +212,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { const done = assert.async(); this.mediaEl.src = this.testSrc.src; - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); @@ -206,7 +226,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { const done = assert.async(); this.mediaEl.setAttribute('src', this.testSrc.src); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); @@ -223,7 +245,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { this.mediaEl.appendChild(this.source); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.testSrc]); done(); @@ -244,7 +268,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { this.mediaEl.appendChild(this.source); this.mediaEl.appendChild(this.source2); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.one('sourceset', () => { validateSource(assert, this.player, [this.sourceOne, this.sourceTwo]); @@ -255,7 +281,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { QUnit.test('no source', function(assert) { const done = assert.async(); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.totalSourcesets = 0; @@ -275,7 +303,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { setupEnv(this, testName); this.mediaEl.src = this.testSrc.src; - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.player.ready(() => { this.mediaEl = this.player.tech_.el(); @@ -392,7 +422,9 @@ QUnit[qunitFn]('sourceset', function(hooks) { QUnit.test('load() with a src attribute', function(assert) { const done = assert.async(); - this.player = videojs(this.mediaEl); + this.player = videojs(this.mediaEl, { + enableSourceset: true + }); this.totalSourcesets = 1; @@ -529,6 +561,7 @@ QUnit[qunitFn]('sourceset', function(hooks) { fixture.appendChild(vid); const player = videojs(vid, { + enableSourceset: true, techOrder: ['fakeFlash', 'html5'] }); From 9519740ea77f6a8275efa79c8ed5d2faffbc8183 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 19 Mar 2018 14:50:34 -0400 Subject: [PATCH 024/371] chore: update package-lock.json --- package-lock.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5103d66a9..0f5943854d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6905,7 +6905,7 @@ "husky": { "version": "0.14.3", "resolved": "https://registry.npmjs.org/husky/-/husky-0.14.3.tgz", - "integrity": "sha512-e21wivqHpstpoiWA/Yi8eFti8E+sQDSS53cpJsPptPs295QTOQR0ZwnHo2TXy1XOpZFD9rPOd3NpmqTK6uMLJA==", + "integrity": "sha1-xp7XTi0neXaaF7qDmbVM4LY8EsM=", "dev": true, "requires": { "is-ci": "1.0.10", @@ -12115,7 +12115,7 @@ "rollup-watch": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/rollup-watch/-/rollup-watch-4.3.1.tgz", - "integrity": "sha512-6yjnIwfjpSrqA8IafyIu7fsEyeImNR4aDjA1bQ7KWeVuiA+Clfsx8+PGQkyABWIQzmauQ//tIJ5wAxLXsXs8qQ==", + "integrity": "sha1-WqHq6reHrd82iQXRArOdb8XOSos=", "dev": true, "requires": { "chokidar": "1.7.0", @@ -14137,9 +14137,9 @@ "dev": true }, "videojs-vtt.js": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.12.5.tgz", - "integrity": "sha1-MoUnMnQci056QxTKos2TZGqcLUA=", + "version": "0.12.6", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.12.6.tgz", + "integrity": "sha512-XFXeGBQiljnElMhwCcZst0RDbZn2n8LU7ZScXryd3a00OaZsHAjdZu/7/RdSr7Z1jHphd45FnOvOQkGK4YrWCQ==", "requires": { "global": "4.3.2" } From 874779402c1ae317308a5b272bdc144a1e2f5fbb Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 19 Mar 2018 14:50:48 -0400 Subject: [PATCH 025/371] 6.8.0 --- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aee49dbafc..69d720bfb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,42 @@ + +# [6.8.0](https://github.com/videojs/video.js/compare/v6.7.4...v6.8.0) (2018-03-19) + +### Features + +* add mimetype type to source object when possible ([#4469](https://github.com/videojs/video.js/issues/4469)) ([#4947](https://github.com/videojs/video.js/issues/4947)) ([62ff3f6](https://github.com/videojs/video.js/commit/62ff3f6)), closes [#4851](https://github.com/videojs/video.js/issues/4851) +* Allow techs to change poster if player option `techCanOverridePoster` is set ([#4921](https://github.com/videojs/video.js/issues/4921)) ([8706941](https://github.com/videojs/video.js/commit/8706941)), closes [#4910](https://github.com/videojs/video.js/issues/4910) +* **format time:** add setFormatTime for overriding the time format ([#4962](https://github.com/videojs/video.js/issues/4962)) ([2f96914](https://github.com/videojs/video.js/commit/2f96914)), closes [#2931](https://github.com/videojs/video.js/issues/2931) +* require enableSourceset option for event ([#5031](https://github.com/videojs/video.js/issues/5031)) ([1b3c827](https://github.com/videojs/video.js/commit/1b3c827)) +* sourceset event ([#4660](https://github.com/videojs/video.js/issues/4660)) ([df96a74](https://github.com/videojs/video.js/commit/df96a74)) +* Use CSS grid for Caption Settings dialog to begin making it more responsive ([#4997](https://github.com/videojs/video.js/issues/4997)) ([d2f63ad](https://github.com/videojs/video.js/commit/d2f63ad)) + +### Bug Fixes + +* don't add captions settings menu item when TextTrackSettings is disabled ([#5002](https://github.com/videojs/video.js/issues/5002)) ([ba6a71e](https://github.com/videojs/video.js/commit/ba6a71e)), closes [#4996](https://github.com/videojs/video.js/issues/4996) +* **sourceset:** set evt.src to empty string or src attr from load ([#5016](https://github.com/videojs/video.js/issues/5016)) ([46d8b37](https://github.com/videojs/video.js/commit/46d8b37)) + +### Chores + +* make sure first-timers bot uses our template ([#5001](https://github.com/videojs/video.js/issues/5001)) ([43b5a6d](https://github.com/videojs/video.js/commit/43b5a6d)) +* **dom.js:** Fix misspellings ([#5008](https://github.com/videojs/video.js/issues/5008)) ([e833d3e](https://github.com/videojs/video.js/commit/e833d3e)) +* update package-lock.json ([9519740](https://github.com/videojs/video.js/commit/9519740)) + +### Documentation + +* **component:** fix misspellings ([#5017](https://github.com/videojs/video.js/issues/5017)) ([1532df3](https://github.com/videojs/video.js/commit/1532df3)) +* **component:** fix misspelllings ([#5019](https://github.com/videojs/video.js/issues/5019)) ([ebbe868](https://github.com/videojs/video.js/commit/ebbe868)) +* **react guide:** update guide to prevent memory leaks when components are disposed of ([#4998](https://github.com/videojs/video.js/issues/4998)) ([1fa9dfb](https://github.com/videojs/video.js/commit/1fa9dfb)) +* **time-ranges:** fix misspellings ([#5025](https://github.com/videojs/video.js/issues/5025)) ([bd6b31c](https://github.com/videojs/video.js/commit/bd6b31c)) +* **time-ranges:** fix wrong comment for getRange function ([#5026](https://github.com/videojs/video.js/issues/5026)) ([d7f45ba](https://github.com/videojs/video.js/commit/d7f45ba)) + +### Reverts + +* Revert "fix: force autoplay in Chrome ([#4804](https://github.com/videojs/video.js/issues/4804))" ([#5009](https://github.com/videojs/video.js/issues/5009)) ([8d86afd](https://github.com/videojs/video.js/commit/8d86afd)), closes [#4720](https://github.com/videojs/video.js/issues/4720) [#5005](https://github.com/videojs/video.js/issues/5005) [#4720](https://github.com/videojs/video.js/issues/4720) [#5005](https://github.com/videojs/video.js/issues/5005) + +### Tests + +* **ResizeManager:** only listen for one playerresize to make test not flaky ([#5022](https://github.com/videojs/video.js/issues/5022)) ([4e83cd3](https://github.com/videojs/video.js/commit/4e83cd3)) + ## [6.7.4](https://github.com/videojs/video.js/compare/v6.7.3...v6.7.4) (2018-03-05) diff --git a/package-lock.json b/package-lock.json index 0f5943854d..1d8f3bfd63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "video.js", - "version": "6.7.4", + "version": "6.8.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 6ec0d02b93..6fe5d43819 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "video.js", "description": "An HTML5 and Flash video player with a common API and skin for both.", - "version": "6.7.4", + "version": "6.8.0", "main": "./dist/video.cjs.js", "style": "./dist/video-js.css", "copyright": "Copyright Brightcove, Inc. ", From 0a20d65c04dca032d89d2a05fd9345ef575ea8c4 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 19 Mar 2018 17:14:56 -0400 Subject: [PATCH 026/371] test: no longer test on IE8, IE9, or IE10 (#5032) --- build/grunt.js | 5 +---- test/karma.conf.js | 29 +---------------------------- 2 files changed, 2 insertions(+), 32 deletions(-) diff --git a/build/grunt.js b/build/grunt.js index b98cc0969b..dc09b591b1 100644 --- a/build/grunt.js +++ b/build/grunt.js @@ -205,10 +205,7 @@ module.exports = function(grunt) { firefox_bs: { browsers: ['firefox_bs'] }, safari_bs: { browsers: ['safari_bs'] }, edge_bs: { browsers: ['edge_bs'] }, - ie11_bs: { browsers: ['ie11_bs'] }, - ie10_bs: { browsers: ['ie10_bs'] }, - ie9_bs: { browsers: ['ie9_bs'] }, - ie8_bs: { browsers: ['ie8_bs'] } + ie11_bs: { browsers: ['ie11_bs'] } }, vjslanguages: { defaults: { diff --git a/test/karma.conf.js b/test/karma.conf.js index 83f6fdcd2c..f956310644 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -131,10 +131,7 @@ module.exports = function(config) { 'firefox_bs', 'safari_bs', 'edge_bs', - 'ie11_bs', - 'ie10_bs', - 'ie9_bs', - 'ie8_bs' + 'ie11_bs' ]; } else { settings.browsers = ['chrome_travis']; @@ -185,30 +182,6 @@ function getCustomLaunchers(){ browser_version: '11', os: 'Windows', os_version: '8.1' - }, - - ie10_bs: { - base: 'BrowserStack', - browser: 'ie', - browser_version: '10', - os: 'Windows', - os_version: '7' - }, - - ie9_bs: { - base: 'BrowserStack', - browser: 'ie', - browser_version: '9', - os: 'Windows', - os_version: '7' - }, - - ie8_bs: { - base: 'BrowserStack', - browser: 'ie', - browser_version: '8', - os: 'Windows', - os_version: '7' } }; } From bc2da7c67bfe1be6deb811269ed3b4a438f8c1a6 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Fri, 23 Mar 2018 13:25:12 -0400 Subject: [PATCH 027/371] refactor: remove IE8 specific changes (#5041) BREAKING CHANGE: remove IE8, IE9, and IE10 specific JavaScript and CSS code. Remove Android 2.3 workaround. --- .babelrc | 1 - build/assets.js | 2 +- build/grunt.js | 8 +- build/rollup.js | 1 - docs/guides/debugging.md | 12 - docs/guides/embeds.md | 5 - package-lock.json | 36 +-- package.json | 2 - sandbox/combined-tracks.html.example | 13 +- sandbox/descriptions.html.example | 17 +- sandbox/flash.html.example | 5 +- sandbox/index.html.example | 5 +- sandbox/language.html.example | 3 - sandbox/middleware-play.html.example | 3 - sandbox/plugin.html.example | 3 - src/css/components/_button.scss | 1 - src/css/components/_control-bar.scss | 2 +- src/css/components/_control.scss | 1 - src/css/components/_error.scss | 2 +- src/css/components/_layout.scss | 6 +- src/css/components/_poster.scss | 10 - src/css/components/_progress.scss | 9 - src/css/components/_text-track.scss | 2 - src/css/components/_time.scss | 6 - src/css/components/_volume.scss | 20 -- src/css/components/menu/_menu.scss | 8 +- src/css/ie8.css | 11 - src/js/component.js | 2 +- .../progress-control/play-progress-bar.js | 6 +- .../control-bar/progress-control/seek-bar.js | 6 +- src/js/menu/menu.js | 2 +- src/js/player.js | 30 +-- src/js/poster-image.js | 28 +- src/js/setup.js | 35 +-- src/js/tech/html5.js | 18 +- src/js/tracks/audio-track-list.js | 26 +- src/js/tracks/audio-track.js | 22 +- src/js/tracks/html-track-element-list.js | 25 +- src/js/tracks/html-track-element.js | 82 +++--- src/js/tracks/text-track-cue-list.js | 22 +- src/js/tracks/text-track-list.js | 31 --- src/js/tracks/text-track.js | 243 +++++++++--------- src/js/tracks/track-list.js | 28 +- src/js/tracks/track.js | 17 +- src/js/tracks/video-track-list.js | 28 +- src/js/tracks/video-track.js | 20 +- src/js/utils/browser.js | 7 - src/js/utils/computed-style.js | 4 +- src/js/utils/dom.js | 21 +- src/js/utils/log.js | 34 +-- src/js/video.js | 35 +-- test/index.html | 1 - test/karma.conf.js | 1 - test/unit/controls.test.js | 144 +++++------ test/unit/player.test.js | 2 +- test/unit/poster.test.js | 19 -- test/unit/resize-manager.test.js | 149 ++++++----- test/unit/test-helpers.js | 10 +- test/unit/tracks/text-track-controls.test.js | 53 ++-- test/unit/tracks/text-track.test.js | 62 ++--- test/unit/tracks/track-baseline.js | 5 - test/unit/utils/dom.test.js | 28 -- test/unit/utils/log.test.js | 21 -- test/unit/video.test.js | 11 - 64 files changed, 442 insertions(+), 1030 deletions(-) delete mode 100644 src/css/ie8.css diff --git a/.babelrc b/.babelrc index 4104471e0a..9631a8bb56 100644 --- a/.babelrc +++ b/.babelrc @@ -1,6 +1,5 @@ { "presets": [ - "es3", ["es2015", { "loose": true }] diff --git a/build/assets.js b/build/assets.js index 77f3653367..cabfc378fd 100644 --- a/build/assets.js +++ b/build/assets.js @@ -6,7 +6,7 @@ const filesize = require('filesize'); const Table = require('cli-table'); const files = klawSync('dist/', { - ignore: ['examples', 'lang', 'font', 'ie8', '*.zip', '*.gz'], + ignore: ['examples', 'lang', 'font', '*.zip', '*.gz'], nodir: true }); diff --git a/build/grunt.js b/build/grunt.js index dc09b591b1..3d0cce0a3b 100644 --- a/build/grunt.js +++ b/build/grunt.js @@ -151,7 +151,6 @@ module.exports = function(grunt) { ] }, fonts: { cwd: 'node_modules/videojs-font/fonts/', src: ['*'], dest: 'build/temp/font/', expand: true, filter: 'isFile' }, - ie8: { cwd: 'node_modules/videojs-ie8/dist/', src: ['**/**'], dest: 'build/temp/ie8/', expand: true, filter: 'isFile' }, dist: { cwd: 'build/temp/', src: ['**/**', '!test*'], dest: 'dist/', expand: true, filter: 'isFile' }, a11y: { src: 'sandbox/descriptions.html.example', dest: 'sandbox/descriptions.test-a11y.html' }, // Can only test a file with a .html or .htm extension examples: { cwd: 'docs/examples/', src: ['**/**'], dest: 'dist/examples/', expand: true, filter: 'isFile' } @@ -304,10 +303,6 @@ module.exports = function(grunt) { concat: { options: { separator: '\n' - }, - ie8_addition: { - src: ['build/temp/video-js.css', 'src/css/ie8.css'], - dest: 'build/temp/video-js.css' } }, concurrent: { @@ -445,7 +440,6 @@ module.exports = function(grunt) { 'cssmin', 'copy:fonts', - 'copy:ie8', 'vjslanguages' ]); @@ -457,7 +451,7 @@ module.exports = function(grunt) { 'zip:dist' ]); - grunt.registerTask('skin', ['sass', 'concat:ie8_addition']); + grunt.registerTask('skin', ['sass']); // Default task - build and test grunt.registerTask('default', ['test']); diff --git a/build/rollup.js b/build/rollup.js index 165dd12b97..c3270c5843 100644 --- a/build/rollup.js +++ b/build/rollup.js @@ -45,7 +45,6 @@ const primedBabel = babel({ babelrc: false, exclude: 'node_modules/**', presets: [ - 'es3', ['es2015', { loose: true, modules: false diff --git a/docs/guides/debugging.md b/docs/guides/debugging.md index 2346caa48e..fe643ece62 100644 --- a/docs/guides/debugging.md +++ b/docs/guides/debugging.md @@ -44,18 +44,6 @@ Similar to the `console`, any number of mixed-type values can be passed to `vide videojs.log('this is a string', {butThis: 'is an object'}); ``` -However, certain browser consoles (namely, IE10 and lower) do not support non-string values. Video.js improves on this situation by passing objects through `JSON.stringify` before logging them in IE10 and below. In other words, instead of the above producing this: - -```txt -VIDEOJS: this is a string [object Object] -``` - -it will produce this: - -```txt -VIDEOJS: this is a string {"butThis": "is an object"} -``` - ### Log Levels Unlike the `console`, `videojs.log` includes the concept of logging levels. These levels toggle logging methods on or off. diff --git a/docs/guides/embeds.md b/docs/guides/embeds.md index bd3b01ff8c..6d80bb470f 100644 --- a/docs/guides/embeds.md +++ b/docs/guides/embeds.md @@ -77,11 +77,6 @@ Adding `class="video-js"` with this embed is no longer necessary as it will auto #### Custom Elements Native Custom Elements support is relatively small according to [Can I Use](http://caniuse.com/#feat=custom-elementsv1) and because we didn't want to include a polyfill we're going with just an element called `video-js` rather than a full blown custom element. -#### Browser support -These all work in all browsers that Video.js supports, though, there are some caveats for some older browsers. -- IE8 requires running `document.createElement('video-js')` before using the `video-js` embed code. -- IE9 doesn't support having `source` elements outside of the `video` element, thus, the `video-js` embed will not work there. Though, if the source is set later, it should still work. - ## data-setup This is an ease-of-use method for having Video.js set up the player automatically. It is an HTML attribute and it takes a JSON string representation of the [player options](/docs/guides/options.md) as the value. Using the programmatic approach is probably preferable. diff --git a/package-lock.json b/package-lock.json index 1d8f3bfd63..df4ce71af6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1057,24 +1057,6 @@ "regexpu-core": "2.0.0" } }, - "babel-plugin-transform-es3-member-expression-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es3-member-expression-literals/-/babel-plugin-transform-es3-member-expression-literals-6.22.0.tgz", - "integrity": "sha1-cz00RPPsxBvvjtGmpOCWV7iWnrs=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-plugin-transform-es3-property-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es3-property-literals/-/babel-plugin-transform-es3-property-literals-6.22.0.tgz", - "integrity": "sha1-sgeNWELiKr9A9z6M3pzTcRq9V1g=", - "dev": true, - "requires": { - "babel-runtime": "6.26.0" - } - }, "babel-plugin-transform-regenerator": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", @@ -1154,16 +1136,6 @@ "babel-plugin-transform-regenerator": "6.26.0" } }, - "babel-preset-es3": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-es3/-/babel-preset-es3-1.0.1.tgz", - "integrity": "sha1-4I3ZUKFnDauLUKvOqpuT09mszR4=", - "dev": true, - "requires": { - "babel-plugin-transform-es3-member-expression-literals": "6.22.0", - "babel-plugin-transform-es3-property-literals": "6.22.0" - } - }, "babel-register": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", @@ -3832,7 +3804,8 @@ "es5-shim": { "version": "4.5.10", "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.5.10.tgz", - "integrity": "sha512-vmryBdqKRO8Ei9LJ4yyEk/EOmAOGIagcHDYPpTAi6pot4IMHS1AC2q5cTKPmydpijg2iX8DVmCuqgrNxIWj8Yg==" + "integrity": "sha512-vmryBdqKRO8Ei9LJ4yyEk/EOmAOGIagcHDYPpTAi6pot4IMHS1AC2q5cTKPmydpijg2iX8DVmCuqgrNxIWj8Yg==", + "dev": true }, "es6-iterator": { "version": "2.0.1", @@ -6905,7 +6878,7 @@ "husky": { "version": "0.14.3", "resolved": "https://registry.npmjs.org/husky/-/husky-0.14.3.tgz", - "integrity": "sha1-xp7XTi0neXaaF7qDmbVM4LY8EsM=", + "integrity": "sha512-e21wivqHpstpoiWA/Yi8eFti8E+sQDSS53cpJsPptPs295QTOQR0ZwnHo2TXy1XOpZFD9rPOd3NpmqTK6uMLJA==", "dev": true, "requires": { "is-ci": "1.0.10", @@ -12115,7 +12088,7 @@ "rollup-watch": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/rollup-watch/-/rollup-watch-4.3.1.tgz", - "integrity": "sha1-WqHq6reHrd82iQXRArOdb8XOSos=", + "integrity": "sha512-6yjnIwfjpSrqA8IafyIu7fsEyeImNR4aDjA1bQ7KWeVuiA+Clfsx8+PGQkyABWIQzmauQ//tIJ5wAxLXsXs8qQ==", "dev": true, "requires": { "chokidar": "1.7.0", @@ -14101,6 +14074,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/videojs-ie8/-/videojs-ie8-1.1.2.tgz", "integrity": "sha1-oj09hgitcZK2nGB3/E64SJmNNdk=", + "dev": true, "requires": { "es5-shim": "4.5.10" } diff --git a/package.json b/package.json index 6fe5d43819..65d7723f14 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "safe-json-parse": "4.0.0", "tsml": "1.0.1", "videojs-font": "2.1.0", - "videojs-ie8": "1.1.2", "videojs-vtt.js": "0.12.6", "xhr": "2.4.0" }, @@ -63,7 +62,6 @@ "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-runtime": "^6.9.0", "babel-preset-es2015": "^6.14.0", - "babel-preset-es3": "^1.0.1", "babel-register": "^6.9.0", "babelify": "^8.0.0", "bluebird": "^3.5.1", diff --git a/sandbox/combined-tracks.html.example b/sandbox/combined-tracks.html.example index 9982ebb8c7..4cc6431809 100644 --- a/sandbox/combined-tracks.html.example +++ b/sandbox/combined-tracks.html.example @@ -4,9 +4,6 @@ Video.js Sandbox - - - @@ -28,11 +25,11 @@

This player has the captions-only captionsButton, the subtiles-only subtitlesButton and the subsCapsButton which shows both kinds. Typically you'll use either just the subsCapsButton alone, or one or both of the captionsButton and subtitlesButton.

diff --git a/sandbox/descriptions.html.example b/sandbox/descriptions.html.example index 86eae47464..f05ad29e92 100644 --- a/sandbox/descriptions.html.example +++ b/sandbox/descriptions.html.example @@ -4,9 +4,6 @@ Video.js Text Descriptions, Chapters & Captions Example - - - @@ -31,15 +28,15 @@ - - - - - + + + + + - + - +

To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video

diff --git a/sandbox/flash.html.example b/sandbox/flash.html.example index 8b37a9081e..ca8407f118 100644 --- a/sandbox/flash.html.example +++ b/sandbox/flash.html.example @@ -4,9 +4,6 @@ Video.js Sandbox - - - @@ -32,7 +29,7 @@ - +

To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video

diff --git a/sandbox/index.html.example b/sandbox/index.html.example index 6efb335253..4eeab3f776 100644 --- a/sandbox/index.html.example +++ b/sandbox/index.html.example @@ -4,9 +4,6 @@ Video.js Sandbox - - - @@ -32,7 +29,7 @@ - +

To view this video please enable JavaScript, and consider upgrading to a web browser that supports HTML5 video

diff --git a/sandbox/language.html.example b/sandbox/language.html.example index f287f6c5aa..ba70ea45cd 100644 --- a/sandbox/language.html.example +++ b/sandbox/language.html.example @@ -5,9 +5,6 @@ VideoJS Languages Demo - - - diff --git a/sandbox/middleware-play.html.example b/sandbox/middleware-play.html.example index 240bfc7aca..655c9786e3 100644 --- a/sandbox/middleware-play.html.example +++ b/sandbox/middleware-play.html.example @@ -4,9 +4,6 @@ Video.js Sandbox - - - diff --git a/sandbox/plugin.html.example b/sandbox/plugin.html.example index 87d3531ee9..e12e8c9283 100644 --- a/sandbox/plugin.html.example +++ b/sandbox/plugin.html.example @@ -4,9 +4,6 @@ Video.js Plugin Example - - - diff --git a/src/css/components/_button.scss b/src/css/components/_button.scss index d32be0b5dd..740bc40739 100644 --- a/src/css/components/_button.scss +++ b/src/css/components/_button.scss @@ -4,7 +4,6 @@ color: inherit; display: inline-block; - overflow: visible; // IE8 font-size: inherit; // IE in general. WTF. line-height: inherit; text-transform: none; diff --git a/src/css/components/_control-bar.scss b/src/css/components/_control-bar.scss index 3cf9393f0d..e4a2981559 100644 --- a/src/css/components/_control-bar.scss +++ b/src/css/components/_control-bar.scss @@ -44,7 +44,7 @@ visibility: visible; } -// IE 8 + 9 Support +// no flex support .vjs-has-started.vjs-no-flex .vjs-control-bar { display: table; } diff --git a/src/css/components/_control.scss b/src/css/components/_control.scss index 8f3e961207..114e694353 100644 --- a/src/css/components/_control.scss +++ b/src/css/components/_control.scss @@ -30,7 +30,6 @@ @include hide-visually; } -// IE 8 + 9 Support .vjs-no-flex .vjs-control { display: table-cell; vertical-align: middle; diff --git a/src/css/components/_error.scss b/src/css/components/_error.scss index e81b634244..67d6a7e395 100644 --- a/src/css/components/_error.scss +++ b/src/css/components/_error.scss @@ -16,7 +16,7 @@ margin-top: -0.5em; position: absolute; text-shadow: 0.05em 0.05em 0.1em #000; - text-align: center; // Needed for IE8 + text-align: center; top: 50%; vertical-align: middle; width: 100%; diff --git a/src/css/components/_layout.scss b/src/css/components/_layout.scss index a73503f693..0d92b9026c 100644 --- a/src/css/components/_layout.scss +++ b/src/css/components/_layout.scss @@ -103,8 +103,6 @@ body.vjs-full-window { padding: 0; margin: 0; height: 100%; - // Fix for IE6 full-window. http://www.cssplay.co.uk/layouts/fixed.html - overflow-y: auto; } .vjs-full-window .video-js.vjs-fullscreen { position: fixed; @@ -149,10 +147,8 @@ body.vjs-full-window { visibility: visible; } -// In IE8 w/ no JavaScript (no HTML5 shim), the video tag doesn't register. -// The .video-js classname on the video tag also isn't considered. // This optional paragraph inside the video tag can provide a message to users -// about what's required to play video. +// about what's required to play video when JavaScript is disabled .vjs-no-js { padding: 20px; color: #fff; diff --git a/src/css/components/_poster.scss b/src/css/components/_poster.scss index 9891da0dce..31ec5a8466 100644 --- a/src/css/components/_poster.scss +++ b/src/css/components/_poster.scss @@ -16,16 +16,6 @@ height: 100%; } -// Used for IE8 fallback -.vjs-poster img { - display: block; - vertical-align: middle; - margin: 0 auto; - max-height: 100%; - padding: 0; - width: 100%; -} - // Hide the poster after the video has started playing .vjs-has-started .vjs-poster { display: none; diff --git a/src/css/components/_progress.scss b/src/css/components/_progress.scss index bd62ef90b8..b4b876e074 100644 --- a/src/css/components/_progress.scss +++ b/src/css/components/_progress.scss @@ -63,9 +63,6 @@ padding: 0; // updated by javascript during playback width: 0; - // Needed for IE6 - left: 0; - top: 0; } .video-js .vjs-play-progress { @@ -83,18 +80,12 @@ } .video-js .vjs-load-progress { - // For IE8, we'll lighten the color - background: lighten($secondary-background-color, 25%); - // Otherwise, we'll rely on stacked opacities background: rgba($secondary-background-color, $secondary-background-transparency); } // There are child elements of the load progress bar that represent the // specific time ranges that have been buffered. .video-js .vjs-load-progress div { - // For IE8, we'll lighten the color - background: lighten($secondary-background-color, 50%); - // Otherwise, we'll rely on stacked opacities background: rgba($secondary-background-color, 0.75); } diff --git a/src/css/components/_text-track.scss b/src/css/components/_text-track.scss index ac7a3223b0..5fa61a54a4 100644 --- a/src/css/components/_text-track.scss +++ b/src/css/components/_text-track.scss @@ -18,8 +18,6 @@ font-size: 1.4em; text-align: center; margin-bottom: 0.1em; - // Transparent black background, or fallback to all black (oldIE) - @include background-color-with-alpha(#000, 0.5); } .vjs-subtitles { color: #fff; } // Subtitles are white diff --git a/src/css/components/_time.scss b/src/css/components/_time.scss index 081f1e43b8..0144dacd7d 100644 --- a/src/css/components/_time.scss +++ b/src/css/components/_time.scss @@ -18,12 +18,6 @@ display: none; } -// IE 8 + IE 9 width: auto container fix -.vjs-no-flex .vjs-remaining-time.vjs-time-control.vjs-control { - width: 0px !important; - white-space: nowrap; -} - .video-js .vjs-duration, .vjs-no-flex .vjs-duration { display: none; diff --git a/src/css/components/_volume.scss b/src/css/components/_volume.scss index abaeed1650..dc359de876 100644 --- a/src/css/components/_volume.scss +++ b/src/css/components/_volume.scss @@ -1,11 +1,6 @@ .video-js .vjs-mute-control { cursor: pointer; @include flex(none); - // padding here is for IE < 9, it doesn't do width: auto from - // another style correctly - padding-left: 2em; - padding-right: 2em; - padding-bottom: 3em; & .vjs-icon-placeholder { @extend .vjs-icon-volume-high; @@ -39,13 +34,6 @@ margin-left: -1px; } -.vjs-no-flex .vjs-volume-panel .vjs-volume-control.vjs-volume-vertical { - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - & .vjs-volume-bar, - & .vjs-volume-level { - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - } -} .video-js .vjs-volume-panel { &:hover .vjs-volume-control, @@ -64,14 +52,6 @@ opacity: 1; position: relative; - &.vjs-volume-vertical { - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; - & .vjs-volume-bar, - & .vjs-volume-level { - -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; - } - } - $transition-property: visibility 0.1s, opacity 0.1s, height 0.1s, width 0.1s, left 0s, top 0s; @include transition($transition-property); } diff --git a/src/css/components/menu/_menu.scss b/src/css/components/menu/_menu.scss index ed5e7c66ca..c7678bd253 100644 --- a/src/css/components/menu/_menu.scss +++ b/src/css/components/menu/_menu.scss @@ -20,10 +20,6 @@ // This allows scrolling of content if need be. overflow: auto; - - // When combined with `overflow: auto;`, this fixes gaps left by - // scrollbars in older IE versions. - box-sizing: content-box; } // Reset box-sizing inside the menu. @@ -31,8 +27,8 @@ box-sizing: border-box; } -// prevent menus from opening while scrubbing (FF, IE) -.vjs-scrubbing .vjs-menu-button:hover .vjs-menu { +// prevent menus from opening while scrubbing +.vjs-scrubbing .vjs-control.vjs-menu-button:hover .vjs-menu { display: none; } diff --git a/src/css/ie8.css b/src/css/ie8.css deleted file mode 100644 index 6ce8c23fdc..0000000000 --- a/src/css/ie8.css +++ /dev/null @@ -1,11 +0,0 @@ -@media \0screen { - .vjs-user-inactive.vjs-playing .vjs-control-bar :before { - content: ""; - } -} - -@media \0screen { - .vjs-has-started.vjs-user-inactive.vjs-playing .vjs-control-bar { - visibility: hidden; - } -} diff --git a/src/js/component.js b/src/js/component.js index 3b3e0e0ff0..96d9daa2a4 100644 --- a/src/js/component.js +++ b/src/js/component.js @@ -988,7 +988,7 @@ class Component { // if the computed value is still 0, it's possible that the browser is lying // and we want to check the offset values. - // This code also runs on IE8 and wherever getComputedStyle doesn't exist. + // This code also runs wherever getComputedStyle doesn't exist. if (computedWidthOrHeight === 0) { const rule = `offset${toTitleCase(widthOrHeight)}`; diff --git a/src/js/control-bar/progress-control/play-progress-bar.js b/src/js/control-bar/progress-control/play-progress-bar.js index 49b7a3fffb..17154ab742 100644 --- a/src/js/control-bar/progress-control/play-progress-bar.js +++ b/src/js/control-bar/progress-control/play-progress-bar.js @@ -2,7 +2,7 @@ * @file play-progress-bar.js */ import Component from '../../component.js'; -import {IE_VERSION, IS_IOS, IS_ANDROID} from '../../utils/browser.js'; +import {IS_IOS, IS_ANDROID} from '../../utils/browser.js'; import formatTime from '../../utils/format-time.js'; import './time-tooltip'; @@ -71,8 +71,8 @@ PlayProgressBar.prototype.options_ = { children: [] }; -// Time tooltips should not be added to a player on mobile devices or IE8 -if ((!IE_VERSION || IE_VERSION > 8) && !IS_IOS && !IS_ANDROID) { +// Time tooltips should not be added to a player on mobile devices +if (!IS_IOS && !IS_ANDROID) { PlayProgressBar.prototype.options_.children.push('timeTooltip'); } diff --git a/src/js/control-bar/progress-control/seek-bar.js b/src/js/control-bar/progress-control/seek-bar.js index 7c9e077141..d1e8a8ba4b 100644 --- a/src/js/control-bar/progress-control/seek-bar.js +++ b/src/js/control-bar/progress-control/seek-bar.js @@ -3,7 +3,7 @@ */ import Slider from '../../slider/slider.js'; import Component from '../../component.js'; -import {IE_VERSION, IS_IOS, IS_ANDROID} from '../../utils/browser.js'; +import {IS_IOS, IS_ANDROID} from '../../utils/browser.js'; import * as Dom from '../../utils/dom.js'; import * as Fn from '../../utils/fn.js'; import formatTime from '../../utils/format-time.js'; @@ -332,8 +332,8 @@ SeekBar.prototype.options_ = { barName: 'playProgressBar' }; -// MouseTimeDisplay tooltips should not be added to a player on mobile devices or IE8 -if ((!IE_VERSION || IE_VERSION > 8) && !IS_IOS && !IS_ANDROID) { +// MouseTimeDisplay tooltips should not be added to a player on mobile devices +if (!IS_IOS && !IS_ANDROID) { SeekBar.prototype.options_.children.splice(1, 0, 'mouseTimeDisplay'); } diff --git a/src/js/menu/menu.js b/src/js/menu/menu.js index d222cc690e..248426c451 100644 --- a/src/js/menu/menu.js +++ b/src/js/menu/menu.js @@ -51,7 +51,7 @@ class Menu extends Component { this.menuButton_.unpressButton(); // don't focus menu button if item is a caption settings item - // because focus will move elsewhere and it logs an error on IE8 + // because focus will move elsewhere if (component.name() !== 'CaptionSettingsMenuItem') { this.menuButton_.focus(); } diff --git a/src/js/player.js b/src/js/player.js index 4085c05c77..06f2ab8d21 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -578,20 +578,10 @@ class Player extends Component { tag.removeAttribute('height'); Object.getOwnPropertyNames(attrs).forEach(function(attr) { - // workaround so we don't totally break IE7 - // http://stackoverflow.com/questions/3653444/css-styles-not-applied-on-dynamic-elements-in-internet-explorer-7 - if (attr === 'class') { - el.className += ' ' + attrs[attr]; + el.setAttribute(attr, attrs[attr]); - if (divEmbed) { - tag.className += ' ' + attrs[attr]; - } - } else { - el.setAttribute(attr, attrs[attr]); - - if (divEmbed) { - tag.setAttribute(attr, attrs[attr]); - } + if (divEmbed) { + tag.setAttribute(attr, attrs[attr]); } }); @@ -624,7 +614,8 @@ class Player extends Component { this.fluid(this.options_.fluid); this.aspectRatio(this.options_.aspectRatio); - // Hide any links within the video/audio tag, because IE doesn't hide them completely. + // Hide any links within the video/audio tag, + // because IE doesn't hide them completely from screen readers. const links = tag.getElementsByTagName('a'); for (let i = 0; i < links.length; i++) { @@ -2884,7 +2875,7 @@ class Player extends Component { this.addClass('vjs-error'); // log the name of the error type and any message - // ie8 just logs "[object object]" if you just log the error object + // IE11 logs "[object object]" and required you to expand message to see error object log.error(`(CODE:${this.error_.code} ${MediaError.errorTypes[this.error_.code]})`, this.error_.message, this.error_); /** @@ -3396,7 +3387,7 @@ class Player extends Component { 'webkitFlexBasis' in elem.style || 'mozFlexBasis' in elem.style || 'msFlexBasis' in elem.style || - // IE10-specific (2012 flex spec) + // IE10-specific (2012 flex spec), available for completeness 'msFlexOrder' in elem.style); } } @@ -3506,7 +3497,8 @@ Player.prototype.options_ = { 'bigPlayButton', 'controlBar', 'errorDisplay', - 'textTrackSettings' + 'textTrackSettings', + 'resizeManager' ], language: navigator && (navigator.languages && navigator.languages[0] || navigator.userLanguage || navigator.language) || 'en', @@ -3518,10 +3510,6 @@ Player.prototype.options_ = { notSupportedMessage: 'No compatible source was found for this media.' }; -if (!browser.IS_IE8) { - Player.prototype.options_.children.push('resizeManager'); -} - [ /** * Returns whether or not the player is in the "ended" state. diff --git a/src/js/poster-image.js b/src/js/poster-image.js index 5c0a60958d..10976c3a05 100644 --- a/src/js/poster-image.js +++ b/src/js/poster-image.js @@ -5,7 +5,6 @@ import ClickableComponent from './clickable-component.js'; import Component from './component.js'; import * as Fn from './utils/fn.js'; import * as Dom from './utils/dom.js'; -import * as browser from './utils/browser.js'; /** * A `ClickableComponent` that handles showing the poster image for the player. @@ -52,15 +51,6 @@ class PosterImage extends ClickableComponent { tabIndex: -1 }); - // To ensure the poster image resizes while maintaining its original aspect - // ratio, use a div with `background-size` when available. For browsers that - // do not support `background-size` (e.g. IE8), fall back on using a regular - // img element. - if (!browser.BACKGROUND_SIZE_SUPPORTED) { - this.fallbackImg_ = Dom.createEl('img'); - el.appendChild(this.fallbackImg_); - } - return el; } @@ -93,19 +83,15 @@ class PosterImage extends ClickableComponent { * The URL to the source for the `PosterImage`. */ setSrc(url) { - if (this.fallbackImg_) { - this.fallbackImg_.src = url; - } else { - let backgroundImage = ''; + let backgroundImage = ''; - // Any falsey values should stay as an empty string, otherwise - // this will throw an extra error - if (url) { - backgroundImage = `url("${url}")`; - } - - this.el_.style.backgroundImage = backgroundImage; + // Any falsey values should stay as an empty string, otherwise + // this will throw an extra error + if (url) { + backgroundImage = `url("${url}")`; } + + this.el_.style.backgroundImage = backgroundImage; } /** diff --git a/src/js/setup.js b/src/js/setup.js index 6e8838d375..717a90c332 100644 --- a/src/js/setup.js +++ b/src/js/setup.js @@ -22,35 +22,10 @@ const autoSetup = function() { return; } - // One day, when we stop supporting IE8, go back to this, but in the meantime...*hack hack hack* - // var vids = Array.prototype.slice.call(document.getElementsByTagName('video')); - // var audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); - // var mediaEls = vids.concat(audios); - - // Because IE8 doesn't support calling slice on a node list, we need to loop - // through each list of elements to build up a new, combined list of elements. - const vids = document.getElementsByTagName('video'); - const audios = document.getElementsByTagName('audio'); - const divs = document.getElementsByTagName('video-js'); - const mediaEls = []; - - if (vids && vids.length > 0) { - for (let i = 0, e = vids.length; i < e; i++) { - mediaEls.push(vids[i]); - } - } - - if (audios && audios.length > 0) { - for (let i = 0, e = audios.length; i < e; i++) { - mediaEls.push(audios[i]); - } - } - - if (divs && divs.length > 0) { - for (let i = 0, e = divs.length; i < e; i++) { - mediaEls.push(divs[i]); - } - } + const vids = Array.prototype.slice.call(document.getElementsByTagName('video')); + const audios = Array.prototype.slice.call(document.getElementsByTagName('audio')); + const divs = Array.prototype.slice.call(document.getElementsByTagName('video-js')); + const mediaEls = vids.concat(audios, divs); // Check if any media elements exist if (mediaEls && mediaEls.length > 0) { @@ -59,8 +34,6 @@ const autoSetup = function() { const mediaEl = mediaEls[i]; // Check if element exists, has getAttribute func. - // IE seems to consider typeof el.getAttribute == 'object' instead of - // 'function' like expected, at least when loading the player immediately. if (mediaEl && mediaEl.getAttribute) { // Make sure this player hasn't already been set up. diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 02479d2ca3..2515280f4f 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -908,7 +908,7 @@ if (Dom.isReal()) { * - False if HTML5 media is not supported. */ Html5.isSupported = function() { - // IE9 with no Media Player is a LIAR! (#984) + // IE with no Media Player is a LIAR! (#984) try { Html5.TEST_VID.volume = 0.5; } catch (e) { @@ -995,9 +995,6 @@ Html5.canControlPlaybackRate = function() { * - False otherwise */ Html5.canOverrideAttributes = function() { - if (browser.IS_IE8) { - return false; - } // if we cannot overwrite the src property, there is no support // iOS 7 safari for instance cannot do this. try { @@ -1169,7 +1166,6 @@ Html5.prototype.featuresNativeAudioTracks = Html5.supportsNativeAudioTracks(); // HTML5 Feature detection and Device Fixes --------------------------------- // const canPlayType = Html5.TEST_VID && Html5.TEST_VID.constructor.prototype.canPlayType; const mpegurlRE = /^application\/(?:x-|vnd\.apple\.)mpegurl/i; -const mp4RE = /^video\/mp4/i; Html5.patchCanPlayType = function() { @@ -1182,15 +1178,6 @@ Html5.patchCanPlayType = function() { } return canPlayType.call(this, type); }; - - // Override Android 2.2 and less canPlayType method which is broken - } else if (browser.IS_OLD_ANDROID) { - Html5.TEST_VID.constructor.prototype.canPlayType = function(type) { - if (type && mp4RE.test(type)) { - return 'maybe'; - } - return canPlayType.call(this, type); - }; } }; @@ -1865,8 +1852,7 @@ Html5.nativeSourceHandler = {}; * 'probably', 'maybe', or '' (empty string) */ Html5.nativeSourceHandler.canPlayType = function(type) { - // IE9 on Windows 7 without MediaPlayer throws an error here - // https://github.com/videojs/video.js/issues/519 + // IE without MediaPlayer throws an error (#519) try { return Html5.TEST_VID.canPlayType(type); } catch (e) { diff --git a/src/js/tracks/audio-track-list.js b/src/js/tracks/audio-track-list.js index 37505b701d..0075fa5c50 100644 --- a/src/js/tracks/audio-track-list.js +++ b/src/js/tracks/audio-track-list.js @@ -2,8 +2,6 @@ * @file audio-track-list.js */ import TrackList from './track-list'; -import * as browser from '../utils/browser.js'; -import document from 'global/document'; /** * Anywhere we call this function we diverge from the spec @@ -42,8 +40,6 @@ class AudioTrackList extends TrackList { * A list of `AudioTrack` to instantiate the list with. */ constructor(tracks = []) { - let list; - // make sure only 1 track is enabled // sorted from last index to first index for (let i = tracks.length - 1; i >= 0; i--) { @@ -53,26 +49,8 @@ class AudioTrackList extends TrackList { } } - // IE8 forces us to implement inheritance ourselves - // as it does not support Object.defineProperty properly - if (browser.IS_IE8) { - list = document.createElement('custom'); - for (const prop in TrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = TrackList.prototype[prop]; - } - } - for (const prop in AudioTrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = AudioTrackList.prototype[prop]; - } - } - } - - list = super(tracks, list); - list.changing_ = false; - - return list; + super(tracks); + this.changing_ = false; } /** diff --git a/src/js/tracks/audio-track.js b/src/js/tracks/audio-track.js index ec760ae8aa..6091835cce 100644 --- a/src/js/tracks/audio-track.js +++ b/src/js/tracks/audio-track.js @@ -1,7 +1,6 @@ import {AudioTrackKind} from './track-enums'; import Track from './track'; import merge from '../utils/merge-options'; -import * as browser from '../utils/browser.js'; /** * A representation of a single `AudioTrack`. If it is part of an {@link AudioTrackList} @@ -38,18 +37,11 @@ class AudioTrack extends Track { const settings = merge(options, { kind: AudioTrackKind[options.kind] || '' }); - // on IE8 this will be a document element - // for every other browser this will be a normal object - const track = super(settings); + + super(settings); + let enabled = false; - if (browser.IS_IE8) { - for (const prop in AudioTrack.prototype) { - if (prop !== 'constructor') { - track[prop] = AudioTrack.prototype[prop]; - } - } - } /** * @memberof AudioTrack * @member {boolean} enabled @@ -59,7 +51,7 @@ class AudioTrack extends Track { * * @fires VideoTrack#selectedchange */ - Object.defineProperty(track, 'enabled', { + Object.defineProperty(this, 'enabled', { get() { return enabled; }, @@ -88,11 +80,9 @@ class AudioTrack extends Track { // set selected to that true value otherwise // we keep it false if (settings.enabled) { - track.enabled = settings.enabled; + this.enabled = settings.enabled; } - track.loaded_ = true; - - return track; + this.loaded_ = true; } } diff --git a/src/js/tracks/html-track-element-list.js b/src/js/tracks/html-track-element-list.js index 7ee7f6d360..02de07fba7 100644 --- a/src/js/tracks/html-track-element-list.js +++ b/src/js/tracks/html-track-element-list.js @@ -2,9 +2,6 @@ * @file html-track-element-list.js */ -import * as browser from '../utils/browser.js'; -import document from 'global/document'; - /** * The current list of {@link HtmlTrackElement}s. */ @@ -17,19 +14,7 @@ class HtmlTrackElementList { * A list of `HtmlTrackElement` to instantiate the list with. */ constructor(trackElements = []) { - let list = this; // eslint-disable-line - - if (browser.IS_IE8) { - list = document.createElement('custom'); - - for (const prop in HtmlTrackElementList.prototype) { - if (prop !== 'constructor') { - list[prop] = HtmlTrackElementList.prototype[prop]; - } - } - } - - list.trackElements_ = []; + this.trackElements_ = []; /** * @memberof HtmlTrackElementList @@ -37,18 +22,14 @@ class HtmlTrackElementList { * The current number of `Track`s in the this Trackist. * @instance */ - Object.defineProperty(list, 'length', { + Object.defineProperty(this, 'length', { get() { return this.trackElements_.length; } }); for (let i = 0, length = trackElements.length; i < length; i++) { - list.addTrackElement_(trackElements[i]); - } - - if (browser.IS_IE8) { - return list; + this.addTrackElement_(trackElements[i]); } } diff --git a/src/js/tracks/html-track-element.js b/src/js/tracks/html-track-element.js index a736fd4148..7c8a035853 100644 --- a/src/js/tracks/html-track-element.js +++ b/src/js/tracks/html-track-element.js @@ -2,8 +2,6 @@ * @file html-track-element.js */ -import * as browser from '../utils/browser.js'; -import document from 'global/document'; import EventTarget from '../event-target'; import TextTrack from '../tracks/text-track'; @@ -63,48 +61,40 @@ class HTMLTrackElement extends EventTarget { super(); let readyState; - let trackElement = this; // eslint-disable-line - - if (browser.IS_IE8) { - trackElement = document.createElement('custom'); - - for (const prop in HTMLTrackElement.prototype) { - if (prop !== 'constructor') { - trackElement[prop] = HTMLTrackElement.prototype[prop]; - } - } - } const track = new TextTrack(options); - trackElement.kind = track.kind; - trackElement.src = track.src; - trackElement.srclang = track.language; - trackElement.label = track.label; - trackElement.default = track.default; - - /** - * @memberof HTMLTrackElement - * @member {HTMLTrackElement~ReadyState} readyState - * The current ready state of the track element. - * @instance - */ - Object.defineProperty(trackElement, 'readyState', { - get() { - return readyState; - } - }); - - /** - * @memberof HTMLTrackElement - * @member {TextTrack} track - * The underlying TextTrack object. - * @instance - * - */ - Object.defineProperty(trackElement, 'track', { - get() { - return track; + this.kind = track.kind; + this.src = track.src; + this.srclang = track.language; + this.label = track.label; + this.default = track.default; + + Object.defineProperties(this, { + + /** + * @memberof HTMLTrackElement + * @member {HTMLTrackElement~ReadyState} readyState + * The current ready state of the track element. + * @instance + */ + readyState: { + get() { + return readyState; + } + }, + + /** + * @memberof HTMLTrackElement + * @member {TextTrack} track + * The underlying TextTrack object. + * @instance + * + */ + track: { + get() { + return track; + } } }); @@ -114,18 +104,14 @@ class HTMLTrackElement extends EventTarget { * @listens TextTrack#loadeddata * @fires HTMLTrackElement#load */ - track.addEventListener('loadeddata', function() { + track.addEventListener('loadeddata', () => { readyState = LOADED; - trackElement.trigger({ + this.trigger({ type: 'load', - target: trackElement + target: this }); }); - - if (browser.IS_IE8) { - return trackElement; - } } } diff --git a/src/js/tracks/text-track-cue-list.js b/src/js/tracks/text-track-cue-list.js index ec751a56ba..b497e34027 100644 --- a/src/js/tracks/text-track-cue-list.js +++ b/src/js/tracks/text-track-cue-list.js @@ -1,8 +1,6 @@ /** * @file text-track-cue-list.js */ -import * as browser from '../utils/browser.js'; -import document from 'global/document'; /** * @typedef {Object} TextTrackCueList~TextTrackCue @@ -36,19 +34,7 @@ class TextTrackCueList { * A list of cues to be initialized with */ constructor(cues) { - let list = this; // eslint-disable-line - - if (browser.IS_IE8) { - list = document.createElement('custom'); - - for (const prop in TextTrackCueList.prototype) { - if (prop !== 'constructor') { - list[prop] = TextTrackCueList.prototype[prop]; - } - } - } - - TextTrackCueList.prototype.setCues_.call(list, cues); + TextTrackCueList.prototype.setCues_.call(this, cues); /** * @memberof TextTrackCueList @@ -56,15 +42,11 @@ class TextTrackCueList { * The current number of `TextTrackCue`s in the TextTrackCueList. * @instance */ - Object.defineProperty(list, 'length', { + Object.defineProperty(this, 'length', { get() { return this.length_; } }); - - if (browser.IS_IE8) { - return list; - } } /** diff --git a/src/js/tracks/text-track-list.js b/src/js/tracks/text-track-list.js index 4b419ad969..2ffbc56308 100644 --- a/src/js/tracks/text-track-list.js +++ b/src/js/tracks/text-track-list.js @@ -3,8 +3,6 @@ */ import TrackList from './track-list'; import * as Fn from '../utils/fn.js'; -import * as browser from '../utils/browser.js'; -import document from 'global/document'; /** * The current list of {@link TextTrack} for a media file. @@ -14,35 +12,6 @@ import document from 'global/document'; */ class TextTrackList extends TrackList { - /** - * Create an instance of this class. - * - * @param {TextTrack[]} [tracks=[]] - * A list of `TextTrack` to instantiate the list with. - */ - constructor(tracks = []) { - let list; - - // IE8 forces us to implement inheritance ourselves - // as it does not support Object.defineProperty properly - if (browser.IS_IE8) { - list = document.createElement('custom'); - for (const prop in TrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = TrackList.prototype[prop]; - } - } - for (const prop in TextTrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = TextTrackList.prototype[prop]; - } - } - } - - list = super(tracks, list); - return list; - } - /** * Add a {@link TextTrack} to the `TextTrackList` * diff --git a/src/js/tracks/text-track.js b/src/js/tracks/text-track.js index b94d9851b2..a3c8e28207 100644 --- a/src/js/tracks/text-track.js +++ b/src/js/tracks/text-track.js @@ -10,7 +10,6 @@ import Track from './track.js'; import { isCrossOrigin } from '../utils/url.js'; import XHR from 'xhr'; import merge from '../utils/merge-options'; -import * as browser from '../utils/browser.js'; /** * Takes a webvtt file contents and parses it into cues @@ -163,27 +162,17 @@ class TextTrack extends Track { if (settings.kind === 'metadata' || settings.kind === 'chapters') { mode = 'hidden'; } - // on IE8 this will be a document element - // for every other browser this will be a normal object - const tt = super(settings); + super(settings); - tt.tech_ = settings.tech; + this.tech_ = settings.tech; - if (browser.IS_IE8) { - for (const prop in TextTrack.prototype) { - if (prop !== 'constructor') { - tt[prop] = TextTrack.prototype[prop]; - } - } - } - - tt.cues_ = []; - tt.activeCues_ = []; + this.cues_ = []; + this.activeCues_ = []; - const cues = new TextTrackCueList(tt.cues_); - const activeCues = new TextTrackCueList(tt.activeCues_); + const cues = new TextTrackCueList(this.cues_); + const activeCues = new TextTrackCueList(this.activeCues_); let changed = false; - const timeupdateHandler = Fn.bind(tt, function() { + const timeupdateHandler = Fn.bind(this, function() { // Accessing this.activeCues for the side-effects of updating itself // due to it's nature as a getter function. Do not remove or cues will @@ -198,142 +187,142 @@ class TextTrack extends Track { }); if (mode !== 'disabled') { - tt.tech_.ready(() => { - tt.tech_.on('timeupdate', timeupdateHandler); + this.tech_.ready(() => { + this.tech_.on('timeupdate', timeupdateHandler); }, true); } - /** - * @memberof TextTrack - * @member {boolean} default - * If this track was set to be on or off by default. Cannot be changed after - * creation. - * @instance - * - * @readonly - */ - Object.defineProperty(tt, 'default', { - get() { - return default_; + Object.defineProperties(this, { + /** + * @memberof TextTrack + * @member {boolean} default + * If this track was set to be on or off by default. Cannot be changed after + * creation. + * @instance + * + * @readonly + */ + default: { + get() { + return default_; + }, + set() {} }, - set() {} - }); - - /** - * @memberof TextTrack - * @member {string} mode - * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will - * not be set if setting to an invalid mode. - * @instance - * - * @fires TextTrack#modechange - */ - Object.defineProperty(tt, 'mode', { - get() { - return mode; - }, - set(newMode) { - if (!TextTrackMode[newMode]) { - return; - } - mode = newMode; - if (mode === 'showing') { - this.tech_.ready(() => { - this.tech_.on('timeupdate', timeupdateHandler); - }, true); - } - /** - * An event that fires when mode changes on this track. This allows - * the TextTrackList that holds this track to act accordingly. - * - * > Note: This is not part of the spec! - * - * @event TextTrack#modechange - * @type {EventTarget~Event} - */ - this.trigger('modechange'); + /** + * @memberof TextTrack + * @member {string} mode + * Set the mode of this TextTrack to a valid {@link TextTrack~Mode}. Will + * not be set if setting to an invalid mode. + * @instance + * + * @fires TextTrack#modechange + */ + mode: { + get() { + return mode; + }, + set(newMode) { + if (!TextTrackMode[newMode]) { + return; + } + mode = newMode; + if (mode === 'showing') { - } - }); + this.tech_.ready(() => { + this.tech_.on('timeupdate', timeupdateHandler); + }, true); + } + /** + * An event that fires when mode changes on this track. This allows + * the TextTrackList that holds this track to act accordingly. + * + * > Note: This is not part of the spec! + * + * @event TextTrack#modechange + * @type {EventTarget~Event} + */ + this.trigger('modechange'); - /** - * @memberof TextTrack - * @member {TextTrackCueList} cues - * The text track cue list for this TextTrack. - * @instance - */ - Object.defineProperty(tt, 'cues', { - get() { - if (!this.loaded_) { - return null; } + }, + + /** + * @memberof TextTrack + * @member {TextTrackCueList} cues + * The text track cue list for this TextTrack. + * @instance + */ + cues: { + get() { + if (!this.loaded_) { + return null; + } - return cues; + return cues; + }, + set() {} }, - set() {} - }); - /** - * @memberof TextTrack - * @member {TextTrackCueList} activeCues - * The list text track cues that are currently active for this TextTrack. - * @instance - */ - Object.defineProperty(tt, 'activeCues', { - get() { - if (!this.loaded_) { - return null; - } + /** + * @memberof TextTrack + * @member {TextTrackCueList} activeCues + * The list text track cues that are currently active for this TextTrack. + * @instance + */ + activeCues: { + get() { + if (!this.loaded_) { + return null; + } - // nothing to do - if (this.cues.length === 0) { - return activeCues; - } + // nothing to do + if (this.cues.length === 0) { + return activeCues; + } - const ct = this.tech_.currentTime(); - const active = []; + const ct = this.tech_.currentTime(); + const active = []; - for (let i = 0, l = this.cues.length; i < l; i++) { - const cue = this.cues[i]; + for (let i = 0, l = this.cues.length; i < l; i++) { + const cue = this.cues[i]; - if (cue.startTime <= ct && cue.endTime >= ct) { - active.push(cue); - } else if (cue.startTime === cue.endTime && - cue.startTime <= ct && - cue.startTime + 0.5 >= ct) { - active.push(cue); + if (cue.startTime <= ct && cue.endTime >= ct) { + active.push(cue); + } else if (cue.startTime === cue.endTime && + cue.startTime <= ct && + cue.startTime + 0.5 >= ct) { + active.push(cue); + } } - } - changed = false; + changed = false; - if (active.length !== this.activeCues_.length) { - changed = true; - } else { - for (let i = 0; i < active.length; i++) { - if (this.activeCues_.indexOf(active[i]) === -1) { - changed = true; + if (active.length !== this.activeCues_.length) { + changed = true; + } else { + for (let i = 0; i < active.length; i++) { + if (this.activeCues_.indexOf(active[i]) === -1) { + changed = true; + } } } - } - this.activeCues_ = active; - activeCues.setCues_(this.activeCues_); + this.activeCues_ = active; + activeCues.setCues_(this.activeCues_); - return activeCues; - }, - set() {} + return activeCues; + }, + set() {} + } }); if (settings.src) { - tt.src = settings.src; - loadTrack(settings.src, tt); + this.src = settings.src; + loadTrack(settings.src, this); } else { - tt.loaded_ = true; + this.loaded_ = true; } - - return tt; } /** diff --git a/src/js/tracks/track-list.js b/src/js/tracks/track-list.js index aed95ef911..2df88dd257 100644 --- a/src/js/tracks/track-list.js +++ b/src/js/tracks/track-list.js @@ -2,8 +2,6 @@ * @file track-list.js */ import EventTarget from '../event-target'; -import * as browser from '../utils/browser.js'; -import document from 'global/document'; /** * Common functionaliy between {@link TextTrackList}, {@link AudioTrackList}, and @@ -18,26 +16,12 @@ class TrackList extends EventTarget { * @param {Track[]} tracks * A list of tracks to initialize the list with. * - * @param {Object} [list] - * The child object with inheritance done manually for ie8. - * * @abstract */ - constructor(tracks = [], list = null) { + constructor(tracks = []) { super(); - if (!list) { - list = this; // eslint-disable-line - if (browser.IS_IE8) { - list = document.createElement('custom'); - for (const prop in TrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = TrackList.prototype[prop]; - } - } - } - } - list.tracks_ = []; + this.tracks_ = []; /** * @memberof TrackList @@ -45,19 +29,15 @@ class TrackList extends EventTarget { * The current number of `Track`s in the this Trackist. * @instance */ - Object.defineProperty(list, 'length', { + Object.defineProperty(this, 'length', { get() { return this.tracks_.length; } }); for (let i = 0; i < tracks.length; i++) { - list.addTrack(tracks[i]); + this.addTrack(tracks[i]); } - - // must return the object, as for ie8 it will not be this - // but a reference to a document object - return list; } /** diff --git a/src/js/tracks/track.js b/src/js/tracks/track.js index 1b39a237de..1d05c4772c 100644 --- a/src/js/tracks/track.js +++ b/src/js/tracks/track.js @@ -1,8 +1,6 @@ /** * @file track.js */ -import * as browser from '../utils/browser.js'; -import document from 'global/document'; import * as Guid from '../utils/guid.js'; import EventTarget from '../event-target'; @@ -41,17 +39,6 @@ class Track extends EventTarget { constructor(options = {}) { super(); - let track = this; // eslint-disable-line - - if (browser.IS_IE8) { - track = document.createElement('custom'); - for (const prop in Track.prototype) { - if (prop !== 'constructor') { - track[prop] = Track.prototype[prop]; - } - } - } - const trackProps = { id: options.id || 'vjs_track_' + Guid.newGUID(), kind: options.kind || '', @@ -97,15 +84,13 @@ class Track extends EventTarget { */ for (const key in trackProps) { - Object.defineProperty(track, key, { + Object.defineProperty(this, key, { get() { return trackProps[key]; }, set() {} }); } - - return track; } } diff --git a/src/js/tracks/video-track-list.js b/src/js/tracks/video-track-list.js index 75f875982f..84b1d5f2ca 100644 --- a/src/js/tracks/video-track-list.js +++ b/src/js/tracks/video-track-list.js @@ -2,8 +2,6 @@ * @file video-track-list.js */ import TrackList from './track-list'; -import * as browser from '../utils/browser.js'; -import document from 'global/document'; /** * Un-select all other {@link VideoTrack}s that are selected. @@ -41,8 +39,6 @@ class VideoTrackList extends TrackList { * A list of `VideoTrack` to instantiate the list with. */ constructor(tracks = []) { - let list; - // make sure only 1 track is enabled // sorted from last index to first index for (let i = tracks.length - 1; i >= 0; i--) { @@ -52,30 +48,14 @@ class VideoTrackList extends TrackList { } } - // IE8 forces us to implement inheritance ourselves - // as it does not support Object.defineProperty properly - if (browser.IS_IE8) { - list = document.createElement('custom'); - for (const prop in TrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = TrackList.prototype[prop]; - } - } - for (const prop in VideoTrackList.prototype) { - if (prop !== 'constructor') { - list[prop] = VideoTrackList.prototype[prop]; - } - } - } - - list = super(tracks, list); - list.changing_ = false; + super(tracks); + this.changing_ = false; /** * @member {number} VideoTrackList#selectedIndex * The current index of the selected {@link VideoTrack`}. */ - Object.defineProperty(list, 'selectedIndex', { + Object.defineProperty(this, 'selectedIndex', { get() { for (let i = 0; i < this.length; i++) { if (this[i].selected) { @@ -86,8 +66,6 @@ class VideoTrackList extends TrackList { }, set() {} }); - - return list; } /** diff --git a/src/js/tracks/video-track.js b/src/js/tracks/video-track.js index 6fb3644d83..88c4e5be42 100644 --- a/src/js/tracks/video-track.js +++ b/src/js/tracks/video-track.js @@ -1,7 +1,6 @@ import {VideoTrackKind} from './track-enums'; import Track from './track'; import merge from '../utils/merge-options'; -import * as browser from '../utils/browser.js'; /** * A representation of a single `VideoTrack`. @@ -37,18 +36,9 @@ class VideoTrack extends Track { kind: VideoTrackKind[options.kind] || '' }); - // on IE8 this will be a document element - // for every other browser this will be a normal object - const track = super(settings); - let selected = false; + super(settings); - if (browser.IS_IE8) { - for (const prop in VideoTrack.prototype) { - if (prop !== 'constructor') { - track[prop] = VideoTrack.prototype[prop]; - } - } - } + let selected = false; /** * @memberof VideoTrack @@ -59,7 +49,7 @@ class VideoTrack extends Track { * * @fires VideoTrack#selectedchange */ - Object.defineProperty(track, 'selected', { + Object.defineProperty(this, 'selected', { get() { return selected; }, @@ -88,10 +78,8 @@ class VideoTrack extends Track { // set selected to that true value otherwise // we keep it false if (settings.selected) { - track.selected = settings.selected; + this.selected = settings.selected; } - - return track; } } diff --git a/src/js/utils/browser.js b/src/js/utils/browser.js index 829f5fe680..591ca1c44f 100644 --- a/src/js/utils/browser.js +++ b/src/js/utils/browser.js @@ -55,8 +55,6 @@ export const ANDROID_VERSION = (function() { return null; }()); -// Old Android is defined as Version older than 2.3, and requiring a webkit version of the android browser -export const IS_OLD_ANDROID = IS_ANDROID && (/webkit/i).test(USER_AGENT) && ANDROID_VERSION < 2.3; export const IS_NATIVE_ANDROID = IS_ANDROID && ANDROID_VERSION < 5 && appleWebkitVersion < 537; export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT); @@ -70,7 +68,6 @@ export const CHROME_VERSION = (function() { } return null; }()); -export const IS_IE8 = (/MSIE\s8\.0/).test(USER_AGENT); export const IE_VERSION = (function() { const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT); let version = result && parseFloat(result[1]); @@ -90,7 +87,3 @@ export const TOUCH_ENABLED = Dom.isReal() && ( 'ontouchstart' in window || window.DocumentTouch && window.document instanceof window.DocumentTouch); - -export const BACKGROUND_SIZE_SUPPORTED = ( - Dom.isReal() && - 'backgroundSize' in window.document.createElement('video').style); diff --git a/src/js/utils/computed-style.js b/src/js/utils/computed-style.js index c063e9d08e..b34e4cde56 100644 --- a/src/js/utils/computed-style.js +++ b/src/js/utils/computed-style.js @@ -5,7 +5,7 @@ import window from 'global/window'; /** - * A safe getComputedStyle with an IE8 fallback. + * A safe getComputedStyle. * * This is needed because in Firefox, if the player is loaded in an iframe with * `display:none`, then `getComputedStyle` returns `null`, so, we do a null-check to @@ -33,5 +33,5 @@ export default function computedStyle(el, prop) { return cs ? cs[prop] : ''; } - return el.currentStyle[prop] || ''; + return ''; } diff --git a/src/js/utils/dom.js b/src/js/utils/dom.js index d81512d04f..13084380f6 100644 --- a/src/js/utils/dom.js +++ b/src/js/utils/dom.js @@ -8,7 +8,6 @@ import log from './log.js'; import tsml from 'tsml'; import {isObject} from './obj'; import computedStyle from './computed-style'; -import * as browser from './browser'; /** * Detect if a value is a string with any non-whitespace characters. @@ -62,14 +61,8 @@ function classRegExp(className) { * @return {Boolean} */ export function isReal() { - return ( - // Both document and window will never be undefined thanks to `global`. - document === window.document && - - // In IE < 9, DOM methods return "object" as their type, so all we can - // confidently check is that it exists. - typeof document.createElement !== 'undefined'); + return document === window.document; } /** @@ -326,7 +319,7 @@ export function removeClass(element, classToRemove) { */ export function toggleClass(element, classToToggle, predicate) { - // This CANNOT use `classList` internally because IE does not support the + // This CANNOT use `classList` internally because IE11 does not support the // second parameter to the `classList.toggle()` method! Which is fine because // `classList` will be used by the add/remove functions. const has = hasClass(element, classToToggle); @@ -391,8 +384,8 @@ export function getAttributes(tag) { const obj = {}; // known boolean attributes - // we can check for matching boolean properties, but older browsers - // won't know about HTML5 boolean attributes that we still read from + // we can check for matching boolean properties, but not all browsers + // and not all tags know about these attributes, so, we still want to check them manually const knownBooleans = ',' + 'autoplay,controls,playsinline,loop,muted,default,defaultMuted' + ','; if (tag && tag.attributes && tag.attributes.length > 0) { @@ -783,12 +776,6 @@ export function isSingleLeftClick(event) { return true; } - if (browser.IE_VERSION === 9) { - // Ignore IE9 - - return true; - } - if (event.button !== 0 || event.buttons !== 1) { // This is the reason we have those if else block above // if any special case we can catch and let it slide diff --git a/src/js/utils/log.js b/src/js/utils/log.js index b3c5961250..a0012da590 100644 --- a/src/js/utils/log.js +++ b/src/js/utils/log.js @@ -3,8 +3,6 @@ * @module log */ import window from 'global/window'; -import {IE_VERSION} from './browser'; -import {isObject} from './obj'; let log; @@ -23,12 +21,8 @@ let history = []; * * @param {Array} args * The arguments to be passed to the matching console method. - * - * @param {boolean} [stringify] - * By default, only old IEs should get console argument stringification, - * but this is exposed as a parameter to facilitate testing. */ -export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 11) => { +export const logByType = (type, args) => { const lvl = log.levels[level]; const lvlRegExp = new RegExp(`^(${lvl})$`); @@ -69,31 +63,7 @@ export const logByType = (type, args, stringify = !!IE_VERSION && IE_VERSION < 1 return; } - // IEs previous to 11 log objects uselessly as "[object Object]"; so, JSONify - // objects and arrays for those less-capable browsers. - if (stringify) { - args = args.map(a => { - if (isObject(a) || Array.isArray(a)) { - try { - return JSON.stringify(a); - } catch (x) { - return String(a); - } - } - - // Cast to string before joining, so we get null and undefined explicitly - // included in output (as we would in a modern console). - return String(a); - }).join(' '); - } - - // Old IE versions do not allow .apply() for console methods (they are - // reported as objects rather than functions). - if (!fn.apply) { - fn(args); - } else { - fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args); - } + fn[Array.isArray(args) ? 'apply' : 'call'](window.console, args); }; /** diff --git a/src/js/video.js b/src/js/video.js index 8bebb496aa..9479eeadaf 100644 --- a/src/js/video.js +++ b/src/js/video.js @@ -33,14 +33,6 @@ import xhr from 'xhr'; import Tech from './tech/tech.js'; import { use as middlewareUse, TERMINATOR } from './tech/middleware.js'; -// HTML5 Element Shim for IE8 -if (typeof HTMLVideoElement === 'undefined' && Dom.isReal()) { - document.createElement('video'); - document.createElement('audio'); - document.createElement('track'); - document.createElement('video-js'); -} - /** * Normalize an `id` value by trimming off a leading `#` * @@ -381,22 +373,17 @@ videojs.use = middlewareUse; * @memberOf {videojs} * @property {object} middleware.TERMINATOR */ -// Object.defineProperty is not available in IE8 -if (!browser.IS_IE8 && Object.defineProperty) { - Object.defineProperty(videojs, 'middleware', { - value: {}, - writeable: false, - enumerable: true - }); +Object.defineProperty(videojs, 'middleware', { + value: {}, + writeable: false, + enumerable: true +}); - Object.defineProperty(videojs.middleware, 'TERMINATOR', { - value: TERMINATOR, - writeable: false, - enumerable: true - }); -} else { - videojs.middleware = { TERMINATOR }; -} +Object.defineProperty(videojs.middleware, 'TERMINATOR', { + value: TERMINATOR, + writeable: false, + enumerable: true +}); /** * A suite of browser and device tests from {@link browser}. @@ -820,7 +807,7 @@ videojs.VideoTrack = VideoTrack; }); /** - * A safe getComputedStyle with an IE8 fallback. + * A safe getComputedStyle. * * This is because in Firefox, if the player is loaded in an iframe with `display:none`, * then `getComputedStyle` returns `null`, so, we do a null-check to make sure diff --git a/test/index.html b/test/index.html index dee7975002..41b0375733 100644 --- a/test/index.html +++ b/test/index.html @@ -9,7 +9,6 @@
- diff --git a/test/karma.conf.js b/test/karma.conf.js index f956310644..bc9a982a5c 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -20,7 +20,6 @@ module.exports = function(config) { // Compling tests here files: [ '../build/temp/video-js.css', - '../build/temp/ie8/videojs-ie8.js', '../test/globals-shim.js', '../test/unit/**/*.js', '../build/temp/browserify.js', diff --git a/test/unit/controls.test.js b/test/unit/controls.test.js index b0e7a9b55c..f98c5c25bb 100644 --- a/test/unit/controls.test.js +++ b/test/unit/controls.test.js @@ -7,7 +7,6 @@ import Slider from '../../src/js/slider/slider.js'; import FullscreenToggle from '../../src/js/control-bar/fullscreen-toggle.js'; import TestHelpers from './test-helpers.js'; import document from 'global/document'; -import Html5 from '../../src/js/tech/html5.js'; import sinon from 'sinon'; QUnit.module('Controls', { @@ -111,107 +110,102 @@ QUnit.test('Fullscreen control text should be correct when fullscreenchange is t player.dispose(); }); -// only run these tests if Html5 is supported. -// IE8 can't run the Html5 tech and to test this functionality otherwith the the tech faker, -// we'd need to implement volume functionality into tech faker -if (Html5.isSupported()) { - QUnit.test('Clicking MuteToggle when volume is above 0 should toggle muted property and not change volume', function(assert) { - const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); - const muteToggle = new MuteToggle(player); +QUnit.test('Clicking MuteToggle when volume is above 0 should toggle muted property and not change volume', function(assert) { + const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); + const muteToggle = new MuteToggle(player); - assert.equal(player.volume(), 1, 'volume is above 0'); - assert.equal(player.muted(), false, 'player is not muted'); + assert.equal(player.volume(), 1, 'volume is above 0'); + assert.equal(player.muted(), false, 'player is not muted'); - muteToggle.handleClick(); + muteToggle.handleClick(); - assert.equal(player.volume(), 1, 'volume is same'); - assert.equal(player.muted(), true, 'player is muted'); + assert.equal(player.volume(), 1, 'volume is same'); + assert.equal(player.muted(), true, 'player is muted'); - player.dispose(); - }); + player.dispose(); +}); - QUnit.test('Clicking MuteToggle when volume is 0 and muted is false should set volume to lastVolume and keep muted false', function(assert) { - const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); - const muteToggle = new MuteToggle(player); +QUnit.test('Clicking MuteToggle when volume is 0 and muted is false should set volume to lastVolume and keep muted false', function(assert) { + const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); + const muteToggle = new MuteToggle(player); - player.volume(0); - assert.equal(player.lastVolume_(), 1, 'lastVolume is set'); - assert.equal(player.muted(), false, 'player is muted'); + player.volume(0); + assert.equal(player.lastVolume_(), 1, 'lastVolume is set'); + assert.equal(player.muted(), false, 'player is muted'); - muteToggle.handleClick(); + muteToggle.handleClick(); - assert.equal(player.volume(), 1, 'volume is set to lastVolume'); - assert.equal(player.muted(), false, 'muted remains false'); + assert.equal(player.volume(), 1, 'volume is set to lastVolume'); + assert.equal(player.muted(), false, 'muted remains false'); - player.dispose(); - }); + player.dispose(); +}); - QUnit.test('Clicking MuteToggle when volume is 0 and muted is true should set volume to lastVolume and sets muted to false', function(assert) { - const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); - const muteToggle = new MuteToggle(player); +QUnit.test('Clicking MuteToggle when volume is 0 and muted is true should set volume to lastVolume and sets muted to false', function(assert) { + const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); + const muteToggle = new MuteToggle(player); - player.volume(0); - player.muted(true); - player.lastVolume_(0.5); + player.volume(0); + player.muted(true); + player.lastVolume_(0.5); - muteToggle.handleClick(); + muteToggle.handleClick(); - assert.equal(player.volume(), 0.5, 'volume is set to lastVolume'); - assert.equal(player.muted(), false, 'muted is set to false'); + assert.equal(player.volume(), 0.5, 'volume is set to lastVolume'); + assert.equal(player.muted(), false, 'muted is set to false'); - player.dispose(); - }); + player.dispose(); +}); - QUnit.test('Clicking MuteToggle when volume is 0, lastVolume is less than 0.1, and muted is true sets volume to 0.1 and muted to false', function(assert) { - const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); - const muteToggle = new MuteToggle(player); +QUnit.test('Clicking MuteToggle when volume is 0, lastVolume is less than 0.1, and muted is true sets volume to 0.1 and muted to false', function(assert) { + const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); + const muteToggle = new MuteToggle(player); - player.volume(0); - player.muted(true); - player.lastVolume_(0.05); + player.volume(0); + player.muted(true); + player.lastVolume_(0.05); - muteToggle.handleClick(); + muteToggle.handleClick(); - // `Number.prototype.toFixed()` is used here to circumvent IE9 rounding issues - assert.equal(player.volume().toFixed(1), (0.1).toFixed(1), 'since lastVolume is less than 0.1, volume is set to 0.1'); - assert.equal(player.muted(), false, 'muted is set to false'); + // `Number.prototype.toFixed()` is used here to circumvent rounding issues + assert.equal(player.volume().toFixed(1), (0.1).toFixed(1), 'since lastVolume is less than 0.1, volume is set to 0.1'); + assert.equal(player.muted(), false, 'muted is set to false'); - player.dispose(); - }); + player.dispose(); +}); - QUnit.test('ARIA value of VolumeBar should start at 100', function(assert) { - const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); - const volumeBar = new VolumeBar(player); +QUnit.test('ARIA value of VolumeBar should start at 100', function(assert) { + const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); + const volumeBar = new VolumeBar(player); - this.clock.tick(1); + this.clock.tick(1); - assert.equal(volumeBar.el_.getAttribute('aria-valuenow'), 100, 'ARIA value of VolumeBar is 100'); + assert.equal(volumeBar.el_.getAttribute('aria-valuenow'), 100, 'ARIA value of VolumeBar is 100'); - player.dispose(); - }); + player.dispose(); +}); - QUnit.test('Muting with MuteToggle should set ARIA value of VolumeBar to 0', function(assert) { - const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); - const volumeBar = new VolumeBar(player); - const muteToggle = new MuteToggle(player); +QUnit.test('Muting with MuteToggle should set ARIA value of VolumeBar to 0', function(assert) { + const player = TestHelpers.makePlayer({ techOrder: ['html5'] }); + const volumeBar = new VolumeBar(player); + const muteToggle = new MuteToggle(player); - this.clock.tick(1); + this.clock.tick(1); - assert.equal(player.volume(), 1, 'Volume is 1'); - assert.equal(player.muted(), false, 'Muted is false'); - assert.equal(volumeBar.el_.getAttribute('aria-valuenow'), 100, 'ARIA value of VolumeBar is 100'); + assert.equal(player.volume(), 1, 'Volume is 1'); + assert.equal(player.muted(), false, 'Muted is false'); + assert.equal(volumeBar.el_.getAttribute('aria-valuenow'), 100, 'ARIA value of VolumeBar is 100'); - muteToggle.handleClick(); + muteToggle.handleClick(); - // Because `volumechange` is triggered asynchronously, it doesn't end up - // getting fired on `player` in the test environment, so we run it - // manually. - player.trigger('volumechange'); + // Because `volumechange` is triggered asynchronously, it doesn't end up + // getting fired on `player` in the test environment, so we run it + // manually. + player.trigger('volumechange'); - assert.equal(player.volume(), 1, 'Volume remains 1'); - assert.equal(player.muted(), true, 'Muted is true'); - assert.equal(volumeBar.el_.getAttribute('aria-valuenow'), 0, 'ARIA value of VolumeBar is 0'); + assert.equal(player.volume(), 1, 'Volume remains 1'); + assert.equal(player.muted(), true, 'Muted is true'); + assert.equal(volumeBar.el_.getAttribute('aria-valuenow'), 0, 'ARIA value of VolumeBar is 0'); - player.dispose(); - }); -} + player.dispose(); +}); diff --git a/test/unit/player.test.js b/test/unit/player.test.js index c81f81d847..f16f01be8f 100644 --- a/test/unit/player.test.js +++ b/test/unit/player.test.js @@ -344,7 +344,7 @@ QUnit.test('should default to 16:9 when fluid', function(assert) { const player = TestHelpers.makePlayer({fluid: true}); const ratio = player.currentHeight() / player.currentWidth(); - // IE8 rounds 0.5625 up to 0.563 + // account for some rounding of 0.5625 up to 0.563 assert.ok(((ratio >= 0.562) && (ratio <= 0.563)), 'fluid player without dimensions defaults to 16:9'); player.dispose(); diff --git a/test/unit/poster.test.js b/test/unit/poster.test.js index 7511731c9b..7dad13f50d 100644 --- a/test/unit/poster.test.js +++ b/test/unit/poster.test.js @@ -49,25 +49,6 @@ QUnit.test('should create and update a poster image', function(assert) { posterImage.dispose(); }); -QUnit.test('should create and update a fallback image in older browsers', function(assert) { - browser.BACKGROUND_SIZE_SUPPORTED = false; - - const posterImage = new PosterImage(this.mockPlayer); - - assert.notEqual(posterImage.fallbackImg_.src.indexOf(this.poster1), - -1, - 'Fallback image created'); - - // Update with a new poster source and check the new value - this.mockPlayer.poster_ = this.poster2; - this.mockPlayer.trigger('posterchange'); - assert.notEqual(posterImage.fallbackImg_.src.indexOf(this.poster2), - -1, - 'Fallback image updated'); - - posterImage.dispose(); -}); - QUnit.test('should remove itself from the document flow when there is no poster', function(assert) { const posterImage = new PosterImage(this.mockPlayer); diff --git a/test/unit/resize-manager.test.js b/test/unit/resize-manager.test.js index 603144cae5..5fcd922408 100644 --- a/test/unit/resize-manager.test.js +++ b/test/unit/resize-manager.test.js @@ -1,102 +1,97 @@ /* eslint-env qunit */ import ResizeManager from '../../src/js/resize-manager.js'; import TestHelpers from './test-helpers.js'; -import * as browser from '../../src/js/utils/browser.js'; import sinon from 'sinon'; -if (!browser.IS_IE8) { - - QUnit.module('ResizeManager', { - beforeEach() { - this.clock = sinon.useFakeTimers(); - this.player = TestHelpers.makePlayer(); - }, - afterEach() { - this.player.dispose(); - this.clock.restore(); +QUnit.module('ResizeManager', { + beforeEach() { + this.clock = sinon.useFakeTimers(); + this.player = TestHelpers.makePlayer(); + }, + afterEach() { + this.player.dispose(); + this.clock.restore(); + } +}); + +QUnit.test('ResizeManager creates an iframe if ResizeObserver is not available', function(assert) { + const rm = new ResizeManager(this.player, {ResizeObserver: null}); + + assert.equal(rm.el().tagName.toLowerCase(), 'iframe', 'we got an iframe'); + + rm.dispose(); +}); + +QUnit.test('ResizeManager uses the ResizeObserver, if given', function(assert) { + let roCreated = false; + let observeCalled = false; + let unobserveCalled = false; + let disconnectCalled = false; + let sameEl = false; + + class MyResizeObserver { + constructor(fn) { + roCreated = true; } - }); - QUnit.test('ResizeManager creates an iframe if ResizeObserver is not available', function(assert) { - const rm = new ResizeManager(this.player, {ResizeObserver: null}); - - assert.equal(rm.el().tagName.toLowerCase(), 'iframe', 'we got an iframe'); + observe(el) { + observeCalled = true; + this.el = el; + } - rm.dispose(); - }); + unobserve(el) { + unobserveCalled = true; + sameEl = this.el === el; + } - QUnit.test('ResizeManager uses the ResizeObserver, if given', function(assert) { - let roCreated = false; - let observeCalled = false; - let unobserveCalled = false; - let disconnectCalled = false; - let sameEl = false; - - class MyResizeObserver { - constructor(fn) { - roCreated = true; - } - - observe(el) { - observeCalled = true; - this.el = el; - } - - unobserve(el) { - unobserveCalled = true; - sameEl = this.el === el; - } - - disconnect() { - disconnectCalled = true; - } + disconnect() { + disconnectCalled = true; } + } - const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver}); + const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver}); - assert.ok(roCreated, 'we intantiated the RO that was passed'); - assert.ok(observeCalled, 'we observed the RO'); - assert.equal(rm.resizeObserver_.el, this.player.el(), 'we observed the player el'); + assert.ok(roCreated, 'we intantiated the RO that was passed'); + assert.ok(observeCalled, 'we observed the RO'); + assert.equal(rm.resizeObserver_.el, this.player.el(), 'we observed the player el'); - rm.dispose(); + rm.dispose(); - assert.ok(unobserveCalled, 'we unobserve when disposed'); - assert.ok(sameEl, 'we unobserve the same el as we observed'); - assert.ok(disconnectCalled, 'we disconnected when disposed'); - }); + assert.ok(unobserveCalled, 'we unobserve when disposed'); + assert.ok(sameEl, 'we unobserve the same el as we observed'); + assert.ok(disconnectCalled, 'we disconnected when disposed'); +}); - QUnit.test('ResizeManager triggers `playerresize` when the observer method is called', function(assert) { - let observer; +QUnit.test('ResizeManager triggers `playerresize` when the observer method is called', function(assert) { + let observer; - class MyResizeObserver { - constructor(fn) { - observer = fn; - } - - observe(el) { - this.el = el; - } + class MyResizeObserver { + constructor(fn) { + observer = fn; + } - unobserve(el) { - } + observe(el) { + this.el = el; + } - disconnect() { - } + unobserve(el) { } - let playerresizeCalled = 0; - const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver}); + disconnect() { + } + } - this.player.one('playerresize', function() { - playerresizeCalled++; - }); - observer(); + let playerresizeCalled = 0; + const rm = new ResizeManager(this.player, {ResizeObserver: MyResizeObserver}); - this.clock.tick(100); + this.player.one('playerresize', function() { + playerresizeCalled++; + }); + observer(); - assert.equal(playerresizeCalled, 1, 'playerresize was triggered'); + this.clock.tick(100); - rm.dispose(); - }); + assert.equal(playerresizeCalled, 1, 'playerresize was triggered'); -} + rm.dispose(); +}); diff --git a/test/unit/test-helpers.js b/test/unit/test-helpers.js index e901f9f24f..cc1bc34d54 100644 --- a/test/unit/test-helpers.js +++ b/test/unit/test-helpers.js @@ -33,15 +33,7 @@ const TestHelpers = { return document.defaultView.getComputedStyle(el, null).getPropertyValue(rule); } - // IE8 - if (el.currentStyle) { - if (rule === 'width' || rule === 'height') { - // return clientWidth or clientHeight instead for better accuracy - rule = 'client' + rule.substr(0, 1).toUpperCase() + rule.substr(1); - return el[rule] + 'px'; - } - return el.currentStyle[rule]; - } + return ''; }, /** diff --git a/test/unit/tracks/text-track-controls.test.js b/test/unit/tracks/text-track-controls.test.js index abba373b03..54a1ea9f34 100644 --- a/test/unit/tracks/text-track-controls.test.js +++ b/test/unit/tracks/text-track-controls.test.js @@ -1,7 +1,6 @@ /* eslint-env qunit */ import TextTrackMenuItem from '../../../src/js/control-bar/text-track-controls/text-track-menu-item.js'; import TestHelpers from '../test-helpers.js'; -import * as browser from '../../../src/js/utils/browser.js'; import sinon from 'sinon'; QUnit.module('Text Track Controls', { @@ -289,35 +288,31 @@ QUnit.test('enabling a captions track should disable the descriptions menu butto player.dispose(); }); -if (!browser.IS_IE8) { - // This test doesn't work on IE8. - // However, this test tests a specific with iOS7 where - // the TextTrackList doesn't report track mode changes. - // TODO: figure out why this test doens't work on IE8. https://github.com/videojs/video.js/issues/1861 - QUnit.test('menu items should polyfill mode change events', function(assert) { - const player = TestHelpers.makePlayer({}); - let changes; - - // emulate a TextTrackList that doesn't report track mode changes, - // like iOS7 - player.textTracks().onchange = undefined; - const trackMenuItem = new TextTrackMenuItem(player, { - track - }); - - player.textTracks().on('change', function() { - changes++; - }); - changes = 0; - trackMenuItem.trigger('tap'); - assert.equal(changes, 1, 'taps trigger change events'); - - trackMenuItem.trigger('click'); - assert.equal(changes, 2, 'clicks trigger change events'); - - player.dispose(); +// This test tests a specific with iOS7 where +// the TextTrackList doesn't report track mode changes. +QUnit.test('menu items should polyfill mode change events', function(assert) { + const player = TestHelpers.makePlayer({}); + let changes; + + // emulate a TextTrackList that doesn't report track mode changes, + // like iOS7 + player.textTracks().onchange = undefined; + const trackMenuItem = new TextTrackMenuItem(player, { + track }); -} + + player.textTracks().on('change', function() { + changes++; + }); + changes = 0; + trackMenuItem.trigger('tap'); + assert.equal(changes, 1, 'taps trigger change events'); + + trackMenuItem.trigger('click'); + assert.equal(changes, 2, 'clicks trigger change events'); + + player.dispose(); +}); const chaptersTrack = { kind: 'chapters', diff --git a/test/unit/tracks/text-track.test.js b/test/unit/tracks/text-track.test.js index cf3b2895d3..609720681e 100644 --- a/test/unit/tracks/text-track.test.js +++ b/test/unit/tracks/text-track.test.js @@ -5,10 +5,8 @@ import TrackBaseline from './track-baseline'; import TechFaker from '../tech/tech-faker'; import TextTrack from '../../../src/js/tracks/text-track.js'; import TestHelpers from '../test-helpers.js'; -import proxyquireify from 'proxyquireify'; import sinon from 'sinon'; - -const proxyquire = proxyquireify(require); +import log from '../../../src/js/utils/log.js'; QUnit.module('Text Track', { beforeEach() { @@ -331,6 +329,11 @@ QUnit.test('tracks are parsed if vttjs is loaded', function(assert) { const clock = sinon.useFakeTimers(); const oldVTT = window.WebVTT; let parserCreated = false; + const reqs = []; + + window.xhr.onCreate = function(req) { + reqs.push(req); + }; window.WebVTT = () => {}; window.WebVTT.StringDecoder = () => {}; @@ -345,22 +348,14 @@ QUnit.test('tracks are parsed if vttjs is loaded', function(assert) { }; }; - // use proxyquire to stub xhr module because IE8s XDomainRequest usage - let xhrHandler; - const TextTrack_ = proxyquire('../../../src/js/tracks/text-track.js', { - xhr(options, fn) { - xhrHandler = fn; - } - }).default; - /* eslint-disable no-unused-vars */ - const tt = new TextTrack_({ + const tt = new TextTrack({ tech: this.tech, src: 'http://example.com' }); /* eslint-enable no-unused-vars */ - xhrHandler(null, {}, 'WEBVTT\n'); + reqs.pop().respond(200, null, 'WEBVTT\n'); assert.ok(parserCreated, 'WebVTT is loaded, so we can just parse'); @@ -372,14 +367,11 @@ QUnit.test('tracks are parsed once vttjs is loaded', function(assert) { const clock = sinon.useFakeTimers(); const oldVTT = window.WebVTT; let parserCreated = false; + const reqs = []; - // use proxyquire to stub xhr module because IE8s XDomainRequest usage - let xhrHandler; - const TextTrack_ = proxyquire('../../../src/js/tracks/text-track.js', { - xhr(options, fn) { - xhrHandler = fn; - } - }).default; + window.xhr.onCreate = function(req) { + reqs.push(req); + }; window.WebVTT = true; @@ -389,13 +381,13 @@ QUnit.test('tracks are parsed once vttjs is loaded', function(assert) { testTech.currentTime = () => {}; /* eslint-disable no-unused-vars */ - const tt = new TextTrack_({ + const tt = new TextTrack({ tech: testTech, src: 'http://example.com' }); /* eslint-enable no-unused-vars */ - xhrHandler(null, {}, 'WEBVTT\n'); + reqs.pop().respond(200, null, 'WEBVTT\n'); assert.ok(!parserCreated, 'WebVTT is not loaded, do not try to parse yet'); @@ -426,22 +418,17 @@ QUnit.test('stops processing if vttjs loading errored out', function(assert) { const clock = sinon.useFakeTimers(); const errorSpy = sinon.spy(); const oldVTT = window.WebVTT; + const oldLogError = log.error; const parserCreated = false; + const reqs = []; - window.WebVTT = true; + window.xhr.onCreate = function(req) { + reqs.push(req); + }; - // use proxyquire to stub xhr module because IE8s XDomainRequest usage - let xhrHandler; - const TextTrack_ = proxyquire('../../../src/js/tracks/text-track.js', { - xhr(options, fn) { - xhrHandler = fn; - }, - '../utils/log.js': { - default: { - error: errorSpy - } - } - }).default; + log.error = errorSpy; + + window.WebVTT = true; const testTech = new EventTarget(); @@ -452,13 +439,13 @@ QUnit.test('stops processing if vttjs loading errored out', function(assert) { testTech.off.withArgs('vttjsloaded'); /* eslint-disable no-unused-vars */ - const tt = new TextTrack_({ + const tt = new TextTrack({ tech: testTech, src: 'http://example.com' }); /* eslint-enable no-unused-vars */ - xhrHandler(null, {}, 'WEBVTT\n'); + reqs.pop().respond(200, null, 'WEBVTT\n'); assert.ok(!parserCreated, 'WebVTT is not loaded, do not try to parse yet'); @@ -475,4 +462,5 @@ QUnit.test('stops processing if vttjs loading errored out', function(assert) { clock.restore(); window.WebVTT = oldVTT; + log.error = oldLogError; }); diff --git a/test/unit/tracks/track-baseline.js b/test/unit/tracks/track-baseline.js index 3c1dd7d69f..98cf8f3c83 100644 --- a/test/unit/tracks/track-baseline.js +++ b/test/unit/tracks/track-baseline.js @@ -1,5 +1,4 @@ /* eslint-env qunit */ -import * as browser from '../../../src/js/utils/browser.js'; /** * Tests baseline functionality for all tracks @@ -35,10 +34,6 @@ const TrackBaseline = function(TrackClass, options) { QUnit.test('returns an instance of itself on non ie8 browsers', function(assert) { const track = new TrackClass(options); - if (browser.IS_IE8) { - assert.ok(track, 'returns an object on ie8'); - return; - } assert.ok(track instanceof TrackClass, 'returns an instance'); }); }; diff --git a/test/unit/utils/dom.test.js b/test/unit/utils/dom.test.js index e1610b1835..6427d9f249 100644 --- a/test/unit/utils/dom.test.js +++ b/test/unit/utils/dom.test.js @@ -1,5 +1,4 @@ /* eslint-env qunit */ -import window from 'global/window'; import document from 'global/document'; import sinon from 'sinon'; import * as Dom from '../../../src/js/utils/dom.js'; @@ -546,30 +545,3 @@ QUnit.test('getBoundingClientRect() returns an object for elements that support assert.strictEqual(actual[k], expected[k], `the "${k}" returned by the Dom util matches what was returned by the mock element`); }); }); - -QUnit.test('getBoundingClientRect() shims only width and height for elements that do not return them', function(assert) { - const oldGCS = window.getComputedStyle; - - // This is done so that we fall back to looking for the `currentStyle` - // property on the mock element. - window.getComputedStyle = null; - - const mockEl = { - currentStyle: { - height: '123', - width: '456' - }, - getBoundingClientRect: sinon.spy(() => { - return {}; - }), - parentNode: true - }; - - const actual = Dom.getBoundingClientRect(mockEl); - - assert.deepEqual(Object.keys(actual).sort(), ['height', 'width'], 'only "height" and "width" were shimmed'); - assert.strictEqual(actual.height, 123, '"height" was shimmed because it was missing'); - assert.strictEqual(actual.width, 456, '"width" was shimmed because it was missing'); - - window.getComputedStyle = oldGCS; -}); diff --git a/test/unit/utils/log.test.js b/test/unit/utils/log.test.js index e1aac055d3..b24763af0d 100644 --- a/test/unit/utils/log.test.js +++ b/test/unit/utils/log.test.js @@ -92,27 +92,6 @@ QUnit.test('logging functions should work', function(assert) { 'history recorded the correct arguments'); }); -QUnit.test('in IE pre-11 (or when requested) objects and arrays are stringified', function(assert) { - - // Need to reset history here because there are extra messages logged - // when running via Karma. - log.history.clear(); - - // Run a custom log call, explicitly requesting object/array stringification. - logByType('log', [ - 'test', - {foo: 'bar'}, - [1, 2, 3], - 0, - false, - null - ], true); - - assert.ok(window.console.log.called, 'log was called'); - assert.deepEqual(window.console.log.firstCall.args, - ['VIDEOJS: test {"foo":"bar"} [1,2,3] 0 false null']); -}); - QUnit.test('setting the log level changes what is actually logged', function(assert) { // Need to reset history here because there are extra messages logged diff --git a/test/unit/video.test.js b/test/unit/video.test.js index e5cca0a91f..df2fbd445a 100644 --- a/test/unit/video.test.js +++ b/test/unit/video.test.js @@ -15,17 +15,6 @@ QUnit.module('video.js', { } }); -QUnit.test('should create a video tag and have access children in old IE', function(assert) { - const fixture = document.getElementById('qunit-fixture'); - - fixture.innerHTML += ''; - - const vid = document.getElementById('test_vid_id'); - - assert.ok(vid.childNodes.length === 1); - assert.ok(vid.childNodes[0].getAttribute('type') === 'video/mp4'); -}); - QUnit.test('should return a video player instance', function(assert) { const fixture = document.getElementById('qunit-fixture'); From 1cb67ab9c943938312aaa925a3468d323cb40216 Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Fri, 23 Mar 2018 13:51:47 -0400 Subject: [PATCH 028/371] refactor: move sourceset code out of tech (#5037) --- src/js/tech/html5.js | 80 +------------------------------ src/js/tech/setup-sourceset.js | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 78 deletions(-) create mode 100644 src/js/tech/setup-sourceset.js diff --git a/src/js/tech/html5.js b/src/js/tech/html5.js index 2515280f4f..d860d4a248 100644 --- a/src/js/tech/html5.js +++ b/src/js/tech/html5.js @@ -13,6 +13,7 @@ import {assign} from '../utils/obj'; import mergeOptions from '../utils/merge-options.js'; import toTitleCase from '../utils/to-title-case.js'; import {NORMAL as TRACK_TYPES} from '../tracks/track-types'; +import setupSourceset from './setup-sourceset'; /** * HTML5 Media Controller - Wrapper for HTML5 Media API @@ -128,84 +129,7 @@ class Html5 extends Tech { * the source is changed. Fires `sourceset` just after the source has changed */ setupSourcesetHandling_() { - if (!this.featuresSourceset) { - return; - } - - const el = this.el(); - - // we need to fire sourceset when the player is ready - // if we find that the media element had a src when it was - // given to us and that tech element is not in a stalled state - if (el.src || el.currentSrc && this.el().initNetworkState_ !== 3) { - this.triggerSourceset(el.src || el.currentSrc); - } - - const proto = window.HTMLMediaElement.prototype; - let srcDescriptor = {}; - - // preserve getters/setters already on `el.src` if they exist - if (Object.getOwnPropertyDescriptor(el, 'src')) { - srcDescriptor = Object.getOwnPropertyDescriptor(el, 'src'); - } else if (Object.getOwnPropertyDescriptor(proto, 'src')) { - srcDescriptor = mergeOptions(srcDescriptor, Object.getOwnPropertyDescriptor(proto, 'src')); - } - - if (!srcDescriptor.get) { - srcDescriptor.get = function() { - return proto.getAttribute.call(this, 'src'); - }; - } - - if (!srcDescriptor.set) { - srcDescriptor.set = function(v) { - return proto.setAttribute.call(this, 'src', v); - }; - } - - if (typeof srcDescriptor.enumerable === 'undefined') { - srcDescriptor.enumerable = true; - } - - Object.defineProperty(el, 'src', { - get: srcDescriptor.get.bind(el), - set: (v) => { - const retval = srcDescriptor.set.call(el, v); - - this.triggerSourceset(v); - - return retval; - }, - configurable: true, - enumerable: srcDescriptor.enumerable - }); - - const oldSetAttribute = el.setAttribute; - - el.setAttribute = (n, v) => { - const retval = oldSetAttribute.call(el, n, v); - - if (n === 'src') { - this.triggerSourceset(v); - } - - return retval; - }; - - const oldLoad = el.load; - - el.load = () => { - const retval = oldLoad.call(el); - - // if `el.src` is set, that source will be loaded - // otherwise, we can't know for sure what source will be set because - // source elements will be used but implementing the source selection algorithm - // is laborious and asynchronous, so, - // instead return an empty string to basically indicate source may change - this.triggerSourceset(el.src || ''); - - return retval; - }; + setupSourceset(this); } /** diff --git a/src/js/tech/setup-sourceset.js b/src/js/tech/setup-sourceset.js new file mode 100644 index 0000000000..5bbd54c0a3 --- /dev/null +++ b/src/js/tech/setup-sourceset.js @@ -0,0 +1,86 @@ +import window from 'global/window'; +import mergeOptions from '../utils/merge-options'; + +const setupSourceset = function(tech) { + + if (!tech.featuresSourceset) { + return; + } + + const el = tech.el(); + + // we need to fire sourceset when the player is ready + // if we find that the media element had a src when it was + // given to us and that tech element is not in a stalled state + if (el.src || el.currentSrc && tech.el().initNetworkState_ !== 3) { + tech.triggerSourceset(el.src || el.currentSrc); + } + + const proto = window.HTMLMediaElement.prototype; + let srcDescriptor = {}; + + // preserve getters/setters already on `el.src` if they exist + if (Object.getOwnPropertyDescriptor(el, 'src')) { + srcDescriptor = Object.getOwnPropertyDescriptor(el, 'src'); + } else if (Object.getOwnPropertyDescriptor(proto, 'src')) { + srcDescriptor = mergeOptions(srcDescriptor, Object.getOwnPropertyDescriptor(proto, 'src')); + } + + if (!srcDescriptor.get) { + srcDescriptor.get = function() { + return proto.getAttribute.call(el, 'src'); + }; + } + + if (!srcDescriptor.set) { + srcDescriptor.set = function(v) { + return proto.setAttribute.call(el, 'src', v); + }; + } + + if (typeof srcDescriptor.enumerable === 'undefined') { + srcDescriptor.enumerable = true; + } + + Object.defineProperty(el, 'src', { + get: srcDescriptor.get.bind(el), + set: (v) => { + const retval = srcDescriptor.set.call(el, v); + + tech.triggerSourceset(v); + + return retval; + }, + configurable: true, + enumerable: srcDescriptor.enumerable + }); + + const oldSetAttribute = el.setAttribute; + + el.setAttribute = (n, v) => { + const retval = oldSetAttribute.call(el, n, v); + + if (n === 'src') { + tech.triggerSourceset(v); + } + + return retval; + }; + + const oldLoad = el.load; + + el.load = () => { + const retval = oldLoad.call(el); + + // if `el.src` is set, that source will be loaded + // otherwise, we can't know for sure what source will be set because + // source elements will be used but implementing the source selection algorithm + // is laborious and asynchronous, so, + // instead return an empty string to basically indicate source may change + tech.triggerSourceset(el.src || ''); + + return retval; + }; +}; + +export default setupSourceset; From 3798446f8485b6f869ea09997f5e9c543962d3ca Mon Sep 17 00:00:00 2001 From: Joe Forbes Date: Fri, 23 Mar 2018 20:06:57 -0400 Subject: [PATCH 029/371] test: update karma browser OS versions (#5050) --- test/karma.conf.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/test/karma.conf.js b/test/karma.conf.js index bc9a982a5c..4748423628 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -151,17 +151,24 @@ function getCustomLaunchers(){ base: 'BrowserStack', browser: 'chrome', os: 'Windows', - os_version: '8.1' + os_version: '10' }, firefox_bs: { base: 'BrowserStack', browser: 'firefox', os: 'Windows', - os_version: '8.1' + os_version: '10' }, safari_bs: { + base: 'BrowserStack', + browser: 'safari', + os: 'OS X', + os_version: 'High Sierra' + }, + + safari9_bs: { base: 'BrowserStack', browser: 'safari', os: 'OS X', @@ -180,7 +187,7 @@ function getCustomLaunchers(){ browser: 'ie', browser_version: '11', os: 'Windows', - os_version: '8.1' + os_version: '10' } }; } From 44312bc06086255dc6389f0dd91545b6a85607a4 Mon Sep 17 00:00:00 2001 From: Gary Katsevman Date: Mon, 26 Mar 2018 10:40:59 -0400 Subject: [PATCH 030/371] chore(test): upgrade qunit and karma-qunit to latest (#5051) Since we no longer support IE8, we can actually update our qunit version. --- package-lock.json | 1468 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 5 +- test/index.html | 4 +- 3 files changed, 1453 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index df4ce71af6..1b903ca3a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -405,6 +405,12 @@ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, "array-differ": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", @@ -524,6 +530,12 @@ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "dev": true }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, "ast-types": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.1.tgz", @@ -582,6 +594,12 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, + "atob": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", + "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", + "dev": true + }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -1232,6 +1250,38 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", @@ -2055,6 +2105,31 @@ "integrity": "sha1-/TVGSkA/b5EXwt42Cez/nK4ABYg=", "dev": true }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "cached-path-relative": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", @@ -2262,6 +2337,92 @@ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, "clean-css": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", @@ -2360,6 +2521,16 @@ "integrity": "sha1-S5BvZw5aljqHt2sOFolkM0G2Ajw=", "dev": true }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "1.0.0", + "object-visit": "1.0.1" + } + }, "color-convert": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", @@ -2801,6 +2972,12 @@ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", "dev": true }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, "core-js": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", @@ -3223,6 +3400,12 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, "deep-assign": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-2.0.0.tgz", @@ -3254,6 +3437,24 @@ "object-keys": "1.0.11" } }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "defined": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", @@ -3385,6 +3586,12 @@ "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", "dev": true }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, "detect-indent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", @@ -3737,6 +3944,12 @@ } } }, + "ensure-posix-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz", + "integrity": "sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI=", + "dev": true + }, "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", @@ -4248,6 +4461,12 @@ "strip-eof": "1.0.0" } }, + "exists-stat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/exists-stat/-/exists-stat-1.0.0.tgz", + "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=", + "dev": true + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -4322,12 +4541,42 @@ "fill-range": "2.2.3" } }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "1.0.1" + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "dev": true }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", @@ -4639,6 +4888,15 @@ "samsam": "1.1.2" } }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -5758,6 +6016,12 @@ "readable-stream": "2.3.3" } }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, "getobject": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", @@ -5979,6 +6243,30 @@ "ini": "1.3.4" } }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "1.0.2", + "is-windows": "1.0.2", + "resolve-dir": "1.0.1" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "2.0.2", + "homedir-polyfill": "1.0.1", + "ini": "1.3.4", + "is-windows": "1.0.2", + "which": "1.3.0" + } + }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", @@ -6640,6 +6928,66 @@ "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, "hash-base": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", @@ -6725,6 +7073,15 @@ "os-tmpdir": "1.0.2" } }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, "hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", @@ -7227,6 +7584,23 @@ "dev": true, "optional": true }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "is-alphabetical": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.1.tgz", @@ -7294,6 +7668,23 @@ "ci-info": "1.1.1" } }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "is-date-object": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", @@ -7306,6 +7697,25 @@ "integrity": "sha1-9ftqlJlq2ejjdh+/vQkfH8qMToI=", "dev": true }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", @@ -7438,6 +7848,23 @@ "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", "dev": true }, + "is-odd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", + "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", + "dev": true, + "requires": { + "is-number": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -7468,8 +7895,25 @@ "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "dev": true }, - "is-posix-bracket": { - "version": "0.1.1", + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", "dev": true @@ -7567,6 +8011,12 @@ "integrity": "sha1-muAXbzKCtlRXoZks2whPil+DPjs=", "dev": true }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "is-word-character": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.1.tgz", @@ -7767,6 +8217,12 @@ "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==", "dev": true }, + "js-reporters": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz", + "integrity": "sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs=", + "dev": true + }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -8460,9 +8916,9 @@ "dev": true }, "karma-qunit": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/karma-qunit/-/karma-qunit-1.2.1.tgz", - "integrity": "sha1-iCUq/SEnvAOwzDGXjtaIKxOfRwo=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-qunit/-/karma-qunit-2.0.1.tgz", + "integrity": "sha512-m9JxUFlb9jHAkvxHCZxwmJAB120uGQS/v6/q5t38rX1O5ZUY0waHUHCfzBVt576ZrnilXb86oIwGDbxfweCTxQ==", "dev": true }, "karma-safari-launcher": { @@ -9207,6 +9663,12 @@ } } }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, "map-obj": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", @@ -9219,6 +9681,15 @@ "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "dev": true }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "1.0.1" + } + }, "marcosc-async": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/marcosc-async/-/marcosc-async-3.0.5.tgz", @@ -9279,6 +9750,15 @@ } } }, + "matcher-collection": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.5.tgz", + "integrity": "sha512-nUCmzKipcJEwYsBVAFh5P+d7JBuhJaW1xs85Hara9xuMLqtCVUrW6DSC0JVIkluxEH2W45nPBM/wjHtBXa/tYA==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, "maxmin": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", @@ -9488,6 +9968,27 @@ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "1.0.2", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + } + } + }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", @@ -9654,6 +10155,46 @@ "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", "dev": true }, + "nanomatch": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", + "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "natives": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz", @@ -10231,12 +10772,88 @@ "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", "dev": true }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + } + } + }, "object-keys": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", "dev": true }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "object.assign": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", @@ -10258,6 +10875,23 @@ "is-extendable": "0.1.1" } }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -10584,6 +11218,12 @@ "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", "dev": true }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, "parse5": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", @@ -10614,6 +11254,12 @@ "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", "dev": true }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, "path-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", @@ -10817,6 +11463,12 @@ } } }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -11169,22 +11821,258 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, - "qunitjs": { - "version": "1.23.1", - "resolved": "https://registry.npmjs.org/qunitjs/-/qunitjs-1.23.1.tgz", - "integrity": "sha1-GXHPl6yb4Bpk0jFVCNLkjm/U5xk=", - "dev": true - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "qunit": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.5.1.tgz", + "integrity": "sha512-klS4J7rF5Zs6KxMgcCR6TV/eF2A94AhH9I1wKG6VSd4mfEbti8DN1PMpDr2RuGu9BX+NbeCq2JcGjvc7KNewyw==", "dev": true, "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" + "chokidar": "1.7.0", + "commander": "2.12.2", + "exists-stat": "1.0.0", + "findup-sync": "2.0.0", + "js-reporters": "1.2.1", + "resolve": "1.5.0", + "shelljs": "0.2.6", + "walk-sync": "0.3.2" }, "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", + "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", + "dev": true, + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "define-property": "1.0.0", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "kind-of": "6.0.2", + "repeat-element": "1.1.2", + "snapdragon": "0.8.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "1.0.0", + "is-glob": "3.1.0", + "micromatch": "3.1.10", + "resolve-dir": "1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -11205,9 +12093,89 @@ } } }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.1", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + } + }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "shelljs": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", + "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=", + "dev": true + } + } + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { @@ -11459,6 +12427,16 @@ "is-equal-shallow": "0.1.3" } }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" + } + }, "regexpu-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", @@ -11880,6 +12858,16 @@ "path-parse": "1.0.5" } }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "2.0.2", + "global-modules": "1.0.0" + } + }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", @@ -11895,6 +12883,12 @@ "resolve-from": "2.0.0" } }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, "restore-cursor": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", @@ -11905,6 +12899,12 @@ "onetime": "1.1.0" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -12157,6 +13157,15 @@ "rust-result": "1.0.0" } }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, "samsam": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.2.tgz", @@ -12318,6 +13327,29 @@ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -12496,6 +13528,136 @@ "nodemailer-shared": "1.1.0" } }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.7", + "source-map-resolve": "0.5.1", + "use": "3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, "sntp": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", @@ -12606,6 +13768,19 @@ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, + "source-map-resolve": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", + "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "dev": true, + "requires": { + "atob": "2.0.3", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, "source-map-support": { "version": "0.4.18", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", @@ -12615,6 +13790,12 @@ "source-map": "0.5.7" } }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, "spdx-correct": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", @@ -12651,6 +13832,15 @@ "through": "2.3.8" } }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2" + } + }, "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", @@ -12700,6 +13890,84 @@ "integrity": "sha1-0g+aYWu08MO5i5GSLSW2QKorxCU=", "dev": true }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "object-copy": "0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", @@ -13238,6 +14506,48 @@ "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "repeat-string": "1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + } + } + }, "to-vfile": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-2.1.2.tgz", @@ -13641,6 +14951,41 @@ } } }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" + } + } + } + }, "unique-string": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", @@ -13704,6 +15049,58 @@ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "dev": true }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "0.3.1", + "isobject": "3.0.1" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "untildify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/untildify/-/untildify-2.1.0.tgz", @@ -13828,6 +15225,12 @@ "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", "dev": true }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", @@ -13872,6 +15275,23 @@ } } }, + "use": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", + "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "user-home": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", @@ -14148,6 +15568,16 @@ "browser-process-hrtime": "0.1.2" } }, + "walk-sync": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz", + "integrity": "sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ==", + "dev": true, + "requires": { + "ensure-posix-path": "1.0.2", + "matcher-collection": "1.0.5" + } + }, "watchify": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz", diff --git a/package.json b/package.json index 65d7723f14..f277d44277 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "karma-firefox-launcher": "^1.1.0", "karma-ie-launcher": "^1.0.0", "karma-opera-launcher": "^1.0.0", - "karma-qunit": "^1.2.0", + "karma-qunit": "^2.0.1", "karma-safari-launcher": "^1.0.0", "karma-safaritechpreview-launcher": "0.0.6", "karma-sinon": "^1.0.5", @@ -121,7 +121,7 @@ "npm-run": "^4.1.0", "npm-run-all": "^4.1.2", "proxyquireify": "^3.0.0", - "qunitjs": "1.23.1", + "qunit": "^2.5.1", "remark-cli": "^5.0.0", "remark-lint": "^6.0.0", "remark-parse": "^5.0.0", @@ -167,7 +167,6 @@ }, "greenkeeper": { "ignore": [ - "qunitjs", "sinon", "webpack", "uglify-js" diff --git a/test/index.html b/test/index.html index 41b0375733..cfff415458 100644 --- a/test/index.html +++ b/test/index.html @@ -3,12 +3,12 @@ VideoJS Tests - +
- + From 378d98ee87b6ac48536d0b8f263bee1f76c68aab Mon Sep 17 00:00:00 2001 From: Mayde Date: Mon, 26 Mar 2018 22:58:07 +0800 Subject: [PATCH 031/371] docs(time-ranges): fix misspellings (#5046) --- src/js/utils/time-ranges.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/utils/time-ranges.js b/src/js/utils/time-ranges.js index 1351398522..67b69e349a 100644 --- a/src/js/utils/time-ranges.js +++ b/src/js/utils/time-ranges.js @@ -63,7 +63,7 @@ function rangeCheck(fnName, index, maxIndex) { * The function name to use for logging * * @param {string} valueIndex - * The proprety that should be used to get the time. should be 'start' or 'end' + * The property that should be used to get the time. should be 'start' or 'end' * * @param {Array} ranges * An array of time ranges From 4d3331e3be17198d9e0eefab29d06134928de5d8 Mon Sep 17 00:00:00 2001 From: Mayde Date: Fri, 30 Mar 2018 03:27:36 +0800 Subject: [PATCH 032/371] docs(text-track): fix misspellings (#5058) --- src/js/tracks/text-track.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/tracks/text-track.js b/src/js/tracks/text-track.js index a3c8e28207..1615dd0d5a 100644 --- a/src/js/tracks/text-track.js +++ b/src/js/tracks/text-track.js @@ -58,7 +58,7 @@ const parseCues = function(srcContent, track) { }; /** - * Load a `TextTrack` from a specifed url. + * Load a `TextTrack` from a specified url. * * @param {string} src * Url to load track from. @@ -139,7 +139,7 @@ class TextTrack extends Track { * * @param {string} [options.srclang=''] * A valid two character language code. An alternative, but deprioritized - * vesion of `options.language` + * version of `options.language` * * @param {string} [options.src] * A url to TextTrack cues. From 96987f8d0acafb38bc71b0d0f871d700d5dec761 Mon Sep 17 00:00:00 2001 From: Mayde Date: Fri, 30 Mar 2018 03:28:36 +0800 Subject: [PATCH 033/371] docs(tech): fix misspellings (#5059) --- src/js/tech/tech.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/js/tech/tech.js b/src/js/tech/tech.js index 04c9e4bc34..ce9a9681bf 100644 --- a/src/js/tech/tech.js +++ b/src/js/tech/tech.js @@ -449,7 +449,7 @@ class Tech extends Component { * Returns the `TimeRange`s that have been played through for the current source. * * > NOTE: This implementation is incomplete. It does not track the played `TimeRange`. - * It only checks wether the source has played at all or not. + * It only checks whether the source has played at all or not. * * @return {TimeRange} * - A single time range if this video has played @@ -772,14 +772,14 @@ class Tech extends Component { setPoster() {} /** - * A method to check for the presence of the 'playsinine'