├── .editorconfig ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── index.html ├── package.json ├── scripts ├── banner.ejs └── server.js ├── src └── plugin.js └── test ├── index.html ├── karma ├── chrome.js ├── common.js ├── detected.js ├── firefox.js ├── ie.js └── safari.js └── plugin.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | .DS_Store 6 | ._* 7 | 8 | # Editors 9 | *~ 10 | *.swp 11 | *.tmproj 12 | *.tmproject 13 | *.sublime-* 14 | .idea/ 15 | .project/ 16 | .settings/ 17 | .vscode/ 18 | 19 | # Logs 20 | logs 21 | *.log 22 | npm-debug.log* 23 | 24 | # Dependency directories 25 | bower_components/ 26 | node_modules/ 27 | 28 | # Yeoman meta-data 29 | .yo-rc.json 30 | 31 | # Build-related directories 32 | dist/ 33 | dist-test/ 34 | docs/api/ 35 | es5/ 36 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | !dist/ 2 | !dist-test/ 3 | !docs/ 4 | !es5/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 'node' 5 | - '4.2' 6 | - '0.12' 7 | - '0.10' 8 | 9 | # Set up a virtual screen for Firefox. 10 | before_script: 11 | - export DISPLAY=:99.0 12 | - sh -e /etc/init.d/xvfb start 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | ### Table of Contents 4 | 5 | 6 | 7 | 8 | 9 | - [Getting Started](#getting-started) 10 | - [Running Tests](#running-tests) 11 | - [Tag and Release](#tag-and-release) 12 | - [License](#license) 13 | 14 | 15 | 16 | ## Getting Started 17 | 18 | 1. Clone this repository! 19 | 1. Install dependencies: `npm install` 20 | 1. Run a development server: `npm start` 21 | 22 | That's it! Refer to the [video.js plugin standards](https://github.com/videojs/generator-videojs-plugin/docs/standards.md) for more detail. 23 | 24 | ### Running Tests 25 | 26 | - In all available and supported browsers: `npm test` 27 | - In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc. 28 | - While development server is running, navigate to [`http://localhost:9999/test/`](http://localhost:9999/test/) (_note:_ port may vary, check console output) 29 | 30 | ### Tag and Release 31 | 32 | 1. Make sure everything is committed. 33 | 1. `npm version *` where `*` is `major`, `minor`, `patch`, etc. [Read more about versioning.](https://github.com/videojs/generator-videojs-plugin/blob/master/docs/standards.md) 34 | 1. `npm publish` 35 | 36 | ## License 37 | 38 | MIT and Apache-2.0. Copyright (c) Derk-Jan Hartman 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Derk-Jan Hartman 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # videojs-responsive-layout 2 | 3 | [![Current version](https://img.shields.io/npm/v/videojs-responsive-layout.svg)](https://www.npmjs.com/package/videojs-responsive-layout) [![Dependencies](https://img.shields.io/versioneye/d/nodejs/videojs-responsive-layout.svg)](https://www.versioneye.com/nodejs/videojs-responsive-layout) 4 | 5 | A plugin that reacts to the width of your player to change the layout of your Video.js player. 6 | 7 | This plugin changes the layout of the controlbar of your Video.js player, based on the width of the player. When it has calculated that not all controls will fit inside the player, it applies one of 3 different layout classes, which are provided by the default skin of Video.js. 8 | ``` 9 | * vjs-layout-tiny 10 | * vjs-layout-x-small 11 | * vjs-layout-small 12 | ``` 13 | 14 | ## Getting started 15 | Simply install from npm, using `npm install videojs-responsive-layout`. 16 | Now add the `dist/videojs-responsive-layout.js` or `dist/videojs-responsive-layout.min.js` to your page and make sure it loads after the main `videojs` javascript. 17 | 18 | Now configure it like: 19 | ```javascript 20 | var player = videojs( 'really-cool-video', 21 | { 22 | controlBar: { 23 | volumeMenuButton: { 24 | inline: false 25 | } 26 | }, 27 | plugins: { 28 | responsiveLayout: {} 29 | } 30 | }, 31 | function() { 32 | console.log('Good to go!'); 33 | this.play(); 34 | } 35 | ); 36 | ``` 37 | The `inline:false` option is important, because the plugin cannot deal with an inline and horizontal volume control at this time. 38 | 39 | 40 | ## Advanced options 41 | Will follow soon... 42 | 43 | ## Contributing 44 | I really appreciate any help in maintaining and advancing this library. Check out the [contributing guide](CONTRIBUTING.md). 45 | 46 | ## License 47 | 48 | MIT and Apache-2.0. 49 | Copyright (c) Derk-Jan Hartman 50 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-responsive-layout Demo 6 | 7 | 8 | 9 | 10 | 14 | 17 | 18 | 19 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-responsive-layout", 3 | "description": "A plugin which reacts to the width of your Video.js player to change the layout.", 4 | "author": "Derk-Jan Hartman", 5 | "license": "(MIT OR Apache-2.0)", 6 | "version": "1.1.1", 7 | "repository": "hartman/videojs-responsive-layout", 8 | "main": "es5/plugin.js", 9 | "keywords": [ 10 | "videojs", 11 | "videojs-plugin" 12 | ], 13 | "browserify": { 14 | "transform": [ 15 | "browserify-shim" 16 | ] 17 | }, 18 | "browserify-shim": { 19 | "qunit": "global:QUnit", 20 | "sinon": "global:sinon", 21 | "video.js": "global:videojs" 22 | }, 23 | "vjsstandard": { 24 | "ignore": [ 25 | "dist", 26 | "dist-test", 27 | "docs", 28 | "es5", 29 | "test/karma", 30 | "scripts" 31 | ] 32 | }, 33 | "scripts": { 34 | "prebuild": "npm run clean", 35 | "build": "npm-run-all -p build:*", 36 | "build:js": "npm-run-all mkdirs build:js:babel build:js:browserify build:js:bannerize build:js:uglify", 37 | "build:js:babel": "babel src -d es5", 38 | "build:js:bannerize": "bannerize dist/videojs-responsive-layout.js --banner=scripts/banner.ejs", 39 | "build:js:browserify": "browserify . -s videojs-responsive-layout --ignore jquery -o dist/videojs-responsive-layout.js", 40 | "build:js:uglify": "uglifyjs dist/videojs-responsive-layout.js --comments --mangle --compress -o dist/videojs-responsive-layout.min.js", 41 | "build:test": "npm-run-all mkdirs build:test:browserify", 42 | "build:test:browserify": "browserify `find test -name '*.test.js'` -t babelify -o dist-test/videojs-responsive-layout.js", 43 | "clean": "rm -rf dist dist-test es5", 44 | "lint": "vjsstandard", 45 | "mkdirs": "mkdir -p dist dist-test es5", 46 | "prestart": "npm-run-all build", 47 | "start": "npm-run-all -p start:serve watch", 48 | "start:serve": "babel-node scripts/server.js", 49 | "pretest": "npm-run-all lint build:test", 50 | "test": "karma start test/karma/detected.js", 51 | "test:chrome": "npm run pretest && karma start test/karma/chrome.js", 52 | "test:firefox": "npm run pretest && karma start test/karma/firefox.js", 53 | "test:ie": "npm run pretest && karma start test/karma/ie.js", 54 | "test:safari": "npm run pretest && karma start test/karma/safari.js", 55 | "//": "disabled npm test in preversion", 56 | "version": "npm run build", 57 | "postversion": "git push origin master && git push origin --tags", 58 | "watch": "npm run mkdirs && npm-run-all -p watch:*", 59 | "watch:js": "watchify src/plugin.js -t babelify --ignore jquery -v -o dist/videojs-responsive-layout.js", 60 | "watch:test": "watchify `find test -name '*.test.js'` -t babelify -o dist-test/videojs-responsive-layout.js" 61 | }, 62 | "dependencies": { 63 | "throttle-debounce": "^0.1.1", 64 | "video.js": "^5.8.0" 65 | }, 66 | "devDependencies": { 67 | "babel": "^5.8.0", 68 | "babelify": "^6.0.0", 69 | "bannerize": "^1.0.0", 70 | "browserify": "^11.0.0", 71 | "browserify-shim": "^3.0.0", 72 | "connect": "^3.4.0", 73 | "cowsay": "^1.1.0", 74 | "global": "^4.3.0", 75 | "karma": "^0.13.0", 76 | "karma-browserify": "^4.4.0", 77 | "karma-chrome-launcher": "^0.2.0", 78 | "karma-detect-browsers": "^2.0.0", 79 | "karma-firefox-launcher": "^0.1.0", 80 | "karma-ie-launcher": "^0.2.0", 81 | "karma-qunit": "^0.1.0", 82 | "karma-safari-launcher": "^0.1.0", 83 | "lodash-compat": "^3.10.0", 84 | "minimist": "^1.2.0", 85 | "npm-run-all": "~1.2.0", 86 | "portscanner": "^1.0.0", 87 | "qunitjs": "^1.0.0", 88 | "serve-static": "^1.10.0", 89 | "sinon": "^1.0.0", 90 | "uglify-js": "^2.5.0", 91 | "videojs-standard": "^4.0.0", 92 | "watchify": "^3.6.0" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /scripts/banner.ejs: -------------------------------------------------------------------------------- 1 | /** 2 | * <%- pkg.name %> 3 | * @version <%- pkg.version %> 4 | * @copyright <%- date.getFullYear() %> <%- pkg.author %> 5 | * @license <%- pkg.license %> 6 | */ 7 | -------------------------------------------------------------------------------- /scripts/server.js: -------------------------------------------------------------------------------- 1 | import connect from 'connect'; 2 | import cowsay from 'cowsay'; 3 | import path from 'path'; 4 | import portscanner from 'portscanner'; 5 | import serveStatic from 'serve-static'; 6 | 7 | // Configuration for the server. 8 | const PORT = 9999; 9 | const MAX_PORT = PORT + 100; 10 | const HOST = '127.0.0.1'; 11 | 12 | const app = connect(); 13 | 14 | const verbs = [ 15 | 'Chewing the cud', 16 | 'Grazing', 17 | 'Mooing', 18 | 'Lowing', 19 | 'Churning the cream' 20 | ]; 21 | 22 | app.use(serveStatic(path.join(__dirname, '..'))); 23 | 24 | portscanner.findAPortNotInUse(PORT, MAX_PORT, HOST, (error, port) => { 25 | if (error) { 26 | throw error; 27 | } 28 | 29 | process.stdout.write(cowsay.say({ 30 | text: `${verbs[Math.floor(Math.random() * 5)]} on ${HOST}:${port}` 31 | }) + '\n\n'); 32 | 33 | app.listen(port); 34 | }); 35 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | /* jshint esnext:true */ 2 | import videojs from 'video.js'; 3 | const debounce = require('throttle-debounce').debounce; 4 | 5 | // Default options for the plugin. 6 | const defaults = { 7 | debounceDelay: 200, 8 | layoutMap: [ 9 | { layoutClassName: 'vjs-layout-tiny', width: 2}, 10 | { layoutClassName: 'vjs-layout-x-small', width: 3}, 11 | { layoutClassName: 'vjs-layout-small', width: 4}, 12 | { layoutClassName: 'defaults', width: 5} 13 | ] 14 | }; 15 | 16 | /** 17 | * Retrieve the outerWidth of an element, including margins 18 | * 19 | * @function getElementOuterWidth 20 | * @param {Element} el to measure 21 | * @return {number} the width of the element in pixels 22 | */ 23 | const getElementOuterWidth = function(el) { 24 | let width = el.offsetWidth; 25 | let style = getComputedStyle(el); 26 | 27 | width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10); 28 | return width; 29 | }; 30 | 31 | /** 32 | * Retrieve the width an element 33 | * 34 | * @function getElementWidth 35 | * @param {Element} el to measure 36 | * @return {number} the width of the element in pixels 37 | */ 38 | const getElementWidth = function(el) { 39 | return parseInt(getComputedStyle(el).width, 10); 40 | }; 41 | 42 | /** 43 | * Check if an element is currently visible. 44 | * 45 | * Use this to filter on elements that should be taken into account during calculations. 46 | * 47 | * @function isElementVisible 48 | * @param {Element} el to test 49 | * @return {boolean} true if el is visible 50 | */ 51 | const isElementVisible = function(el) { 52 | return (el.offsetWidth > 0 || el.offsetHeight > 0); 53 | }; 54 | 55 | const dimensionsCheck = function() { 56 | /** 57 | * Set a layout class on a video-js element 58 | * 59 | * @function setLayout 60 | * @param {Player} player to apply the layout to 61 | */ 62 | const setLayout = function(layouter) { 63 | let el = layouter.player.el(); 64 | let layoutDefinition = layouter.options.layoutMap[layouter.currentLayout_]; 65 | 66 | if (layoutDefinition.layoutClassName !== 'defaults') { 67 | (videojs.dom || videojs).addClass(el, layoutDefinition.layoutClassName); 68 | } 69 | layouter.options.layoutMap.forEach(function(element, index) { 70 | if (index !== layouter.currentLayout_ && element.layoutClassName !== 'defaults') { 71 | videojs.removeClass(el, element.layoutClassName); 72 | } 73 | }); 74 | }; 75 | 76 | /** 77 | * Calculate for the giving dimensions which layout class of the layoutMap should be 78 | * used 79 | * 80 | * @function setLayout 81 | * @param {Player} player to apply the layout to 82 | */ 83 | const calculateLayout = function(layouter, playerWidth, controlBarWidth, controlWidth) { 84 | let layoutMap = layouter.options.layoutMap; 85 | 86 | if (controlBarWidth > playerWidth && layouter.currentLayout_ > 0) { 87 | // smaller 88 | layouter.currentLayout_--; 89 | setLayout(layouter); 90 | window.setTimeout(dimensionsCheck.bind(layouter), 1); 91 | } else if (layouter.currentLayout_ < layoutMap.length - 1 && 92 | playerWidth >= layoutMap[layouter.currentLayout_ + 1].width * controlWidth 93 | ) { 94 | // bigger 95 | layouter.currentLayout_++; 96 | setLayout(layouter); 97 | window.setTimeout(dimensionsCheck.bind(layouter), 1); 98 | } 99 | }; 100 | 101 | if (!this.el || this.player.usingNativeControls() || 102 | !isElementVisible(this.el.querySelectorAll('.vjs-control-bar')[0]) 103 | ) { 104 | return; 105 | } 106 | let playerWidth = this.getPlayerWidth(); 107 | let controlWidth = this.getControlWidth(); 108 | let controlBarWidth = this.getControlBarWidth(); 109 | 110 | if (this.options.calculateLayout) { 111 | this.options.calculateLayout(this, playerWidth, controlBarWidth, controlWidth); 112 | } else { 113 | calculateLayout(this, playerWidth, controlBarWidth, controlWidth); 114 | } 115 | }; 116 | 117 | class Layouter { 118 | constructor(player, options) { 119 | this.player_ = player; 120 | this.options_ = options; 121 | this.currentLayout_ = options.layoutMap.length - 1; 122 | this.debouncedCheckSize_ = debounce(options.debounceDelay, dimensionsCheck); 123 | } 124 | 125 | ready() { 126 | this.player.addClass('vjs-responsive-layout'); 127 | 128 | this.windowResizeListener_ = window.addEventListener( 129 | 'resize', 130 | () => this.debouncedCheckSize_() 131 | ); 132 | 133 | this.player.on(['play', 'resize'], () => this.debouncedCheckSize_()); 134 | this.player.on('dispose', function() { 135 | window.removeEventListener('resize', this.windowResizeListener_); 136 | }); 137 | 138 | // Let's do the first measure 139 | this.player.trigger('resize'); 140 | } 141 | 142 | /** 143 | * Retrieve player to which this Layouter object belongs 144 | * 145 | * @property player 146 | * @return {number} the width of the controlbar in pixels 147 | */ 148 | get player() { 149 | return this.player_; 150 | } 151 | 152 | get el() { 153 | return this.player_.el(); 154 | } 155 | 156 | get options() { 157 | return this.options_; 158 | } 159 | 160 | /** 161 | * Retrieve current width of a control in the video.js controlbar 162 | * 163 | * This function relies on the presence of the play control. If you 164 | * mess with it's visibility, things likely will break :) 165 | * 166 | * @function getControlWidth 167 | * @return {number} the width of the controlbar in pixels 168 | */ 169 | getControlWidth() { 170 | return getElementOuterWidth(this.el.querySelectorAll('.vjs-play-control')[0]); 171 | } 172 | 173 | /** 174 | * Retrieve current width of the video.js controlbar 175 | * 176 | * @function getControlBarWidth 177 | * @return {number} the width of the controlbar in pixels 178 | */ 179 | getControlBarWidth() { 180 | let controlBarWidth = 0; 181 | let cbElements = this.el.querySelectorAll('.vjs-control-bar > *'); 182 | 183 | for (var i = 0; i < cbElements.length; i++) { 184 | var el = cbElements[i]; 185 | if (isElementVisible(el)) { 186 | controlBarWidth += getElementOuterWidth(el); 187 | } 188 | } 189 | return controlBarWidth; 190 | } 191 | 192 | /** 193 | * Retrieve current width of the video.js player element 194 | * 195 | * @function getPlayerWidth 196 | * @return {number} the width of the player in pixels 197 | */ 198 | getPlayerWidth() { 199 | return getElementWidth(this.el); 200 | } 201 | 202 | /** 203 | * Retrieve the outerWidth of an element, including margins 204 | * 205 | * @function outerWidth 206 | * @param {Element} el to measure 207 | * @return {number} the width of the element in pixels 208 | */ 209 | static getElementOuterWidth(el) { 210 | return getElementOuterWidth(el); 211 | } 212 | 213 | /** 214 | * Retrieve the width an element 215 | * 216 | * @function getElementWidth 217 | * @param {Element} el to measure 218 | * @return {number} the width of the element in pixels 219 | */ 220 | static getElementWidth(el) { 221 | return getElementWidth(el); 222 | } 223 | 224 | /** 225 | * Check if an element is currently visible. 226 | * 227 | * Use this to filter on elements that should be taken into account during calculations. 228 | * 229 | * @function isElementVisible 230 | * @param {Element} el to test 231 | * @return {boolean} true if el is visible 232 | */ 233 | static isElementVisible(el) { 234 | return isElementVisible(el); 235 | } 236 | } 237 | 238 | /** 239 | * A video.js plugin. 240 | * 241 | * In the plugin function, the value of `this` is a video.js `Player` 242 | * instance. You cannot rely on the player being in a "ready" state here, 243 | * depending on how the plugin is invoked. This may or may not be important 244 | * to you; if not, remove the wait for "ready"! 245 | * 246 | * @function responsiveLayout 247 | * @param {Object} [options={}] 248 | * An object of options left to the plugin author to define. 249 | */ 250 | const responsiveLayout = function(options) { 251 | let layout = new Layouter(this, videojs.mergeOptions(defaults, options)); 252 | 253 | this.ready(() => { 254 | layout.ready(); 255 | }); 256 | }; 257 | 258 | // Register the plugin with video.js. 259 | (videojs.registerPlugin || videojs.plugin)('responsiveLayout', responsiveLayout); 260 | 261 | export default responsiveLayout; 262 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-responsive-layout Unit Tests 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/karma/chrome.js: -------------------------------------------------------------------------------- 1 | var common = require('./common'); 2 | 3 | module.exports = function(config) { 4 | config.set(common({ 5 | plugins: ['karma-chrome-launcher'], 6 | browsers: ['Chrome'] 7 | })); 8 | }; 9 | -------------------------------------------------------------------------------- /test/karma/common.js: -------------------------------------------------------------------------------- 1 | var merge = require('lodash-compat/object/merge'); 2 | 3 | var DEFAULTS = { 4 | basePath: '../..', 5 | frameworks: ['browserify', 'qunit'], 6 | 7 | files: [ 8 | 'node_modules/sinon/pkg/sinon.js', 9 | 'node_modules/sinon/pkg/sinon-ie.js', 10 | 'node_modules/video.js/dist/video.js', 11 | 'test/**/*.js' 12 | ], 13 | 14 | exclude: [ 15 | 'test/bundle.js' 16 | ], 17 | 18 | plugins: [ 19 | 'karma-browserify', 20 | 'karma-qunit' 21 | ], 22 | 23 | preprocessors: { 24 | 'test/**/*.js': ['browserify'] 25 | }, 26 | 27 | reporters: ['dots'], 28 | port: 9876, 29 | colors: true, 30 | autoWatch: false, 31 | singleRun: true, 32 | concurrency: Infinity, 33 | 34 | browserify: { 35 | transform: [ 36 | 'babelify', 37 | 'browserify-shim' 38 | ] 39 | } 40 | }; 41 | 42 | /** 43 | * Customizes target/source merging with lodash merge. 44 | * 45 | * @param {Mixed} target 46 | * @param {Mixed} source 47 | * @return {Mixed} 48 | */ 49 | var customizer = function(target, source) { 50 | if (Array.isArray(target)) { 51 | return target.concat(source); 52 | } 53 | }; 54 | 55 | /** 56 | * Generates a new Karma config with a common set of base configuration. 57 | * 58 | * @param {Object} custom 59 | * Configuration that will be deep-merged. Arrays will be 60 | * concatenated. 61 | * @return {Object} 62 | */ 63 | module.exports = function(custom) { 64 | return merge({}, custom, DEFAULTS, customizer); 65 | }; 66 | -------------------------------------------------------------------------------- /test/karma/detected.js: -------------------------------------------------------------------------------- 1 | var common = require('./common'); 2 | 3 | // Runs default testing configuration in multiple environments. 4 | 5 | module.exports = function(config) { 6 | 7 | // Travis CI should run in its available Firefox headless browser. 8 | if (process.env.TRAVIS) { 9 | 10 | config.set(common({ 11 | browsers: ['Firefox'], 12 | plugins: ['karma-firefox-launcher'] 13 | })) 14 | } else { 15 | config.set(common({ 16 | 17 | frameworks: ['detectBrowsers'], 18 | 19 | plugins: [ 20 | 'karma-chrome-launcher', 21 | 'karma-detect-browsers', 22 | 'karma-firefox-launcher', 23 | 'karma-ie-launcher', 24 | 'karma-safari-launcher' 25 | ], 26 | 27 | detectBrowsers: { 28 | usePhantomJS: false 29 | } 30 | })); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /test/karma/firefox.js: -------------------------------------------------------------------------------- 1 | var common = require('./common'); 2 | 3 | module.exports = function(config) { 4 | config.set(common({ 5 | plugins: ['karma-firefox-launcher'], 6 | browsers: ['Firefox'] 7 | })); 8 | }; 9 | -------------------------------------------------------------------------------- /test/karma/ie.js: -------------------------------------------------------------------------------- 1 | var common = require('./common'); 2 | 3 | module.exports = function(config) { 4 | config.set(common({ 5 | plugins: ['karma-ie-launcher'], 6 | browsers: ['IE'] 7 | })); 8 | }; 9 | -------------------------------------------------------------------------------- /test/karma/safari.js: -------------------------------------------------------------------------------- 1 | var common = require('./common'); 2 | 3 | module.exports = function(config) { 4 | config.set(common({ 5 | plugins: ['karma-safari-launcher'], 6 | browsers: ['Safari'] 7 | })); 8 | }; 9 | -------------------------------------------------------------------------------- /test/plugin.test.js: -------------------------------------------------------------------------------- 1 | import document from 'global/document'; 2 | 3 | import QUnit from 'qunit'; 4 | import sinon from 'sinon'; 5 | import videojs from 'video.js'; 6 | 7 | import plugin from '../src/plugin'; 8 | 9 | const Player = videojs.getComponent('Player'); 10 | 11 | QUnit.test('the environment is sane', function(assert) { 12 | assert.strictEqual(typeof Array.isArray, 'function', 'es5 exists'); 13 | assert.strictEqual(typeof sinon, 'object', 'sinon exists'); 14 | assert.strictEqual(typeof videojs, 'function', 'videojs exists'); 15 | assert.strictEqual(typeof plugin, 'function', 'plugin is a function'); 16 | }); 17 | 18 | QUnit.module('videojs-responsive-layout', { 19 | 20 | beforeEach() { 21 | this.fixture = document.getElementById('qunit-fixture'); 22 | this.video = document.createElement('video'); 23 | this.fixture.appendChild(this.video); 24 | this.player = videojs(this.video); 25 | 26 | // Mock the environment's timers because certain things - particularly 27 | // player readiness - are asynchronous in video.js 5. 28 | this.clock = sinon.useFakeTimers(); 29 | }, 30 | 31 | afterEach() { 32 | 33 | // The clock _must_ be restored before disposing the player; otherwise, 34 | // certain timeout listeners that happen inside video.js may throw errors. 35 | this.clock.restore(); 36 | this.player.dispose(); 37 | } 38 | }); 39 | 40 | QUnit.test('registers itself with video.js', function(assert) { 41 | assert.expect(2); 42 | 43 | assert.strictEqual( 44 | Player.prototype.responsiveLayout, 45 | plugin, 46 | 'videojs-responsive-layout plugin was registered' 47 | ); 48 | 49 | this.player.responsiveLayout(); 50 | 51 | // Tick the clock forward enough to trigger the player to be "ready". 52 | this.clock.tick(1); 53 | 54 | assert.ok( 55 | this.player.hasClass('vjs-responsive-layout'), 56 | 'the plugin adds a class to the player' 57 | ); 58 | }); 59 | --------------------------------------------------------------------------------