├── CHANGELOG.md ├── .npmignore ├── .editorconfig ├── .gitignore ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── LICENSE ├── .travis.yml ├── index.html ├── webpack.config.js ├── CONTRIBUTING.md ├── package.json ├── test └── index.test.js ├── README.md └── src ├── css └── index.scss └── js └── index.js /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | ## HEAD (Unreleased) 5 | _(none)_ 6 | 7 | -------------------- 8 | 9 | ## 2.2.0 (2017-05-09) 10 | _(none)_ 11 | 12 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Intentionally left blank, so that npm does not ignore anything by default, 2 | # but relies on the package.json "files" array to explicitly define what ends 3 | # up in the package. 4 | -------------------------------------------------------------------------------- /.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 | build/ 34 | 35 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Please describe the change as necessary. 3 | If it's a feature or enhancement please be as detailed as possible. 4 | If it's a bug fix, please link the issue that it fixes or describe the bug in as much detail. 5 | 6 | ## Specific Changes proposed 7 | Please list the specific changes involved in this pull request. 8 | 9 | ## Requirements Checklist 10 | - [ ] Feature implemented / Bug fixed 11 | - [ ] If necessary, more likely in a feature request than a bug fix 12 | - [ ] Unit Tests updated or fixed 13 | - [ ] Docs/guides updated 14 | - [ ] Reviewed by Two Core Contributors 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Fernando Godino 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: node_js 4 | node_js: 5 | - 'node' 6 | - 'lts/argon' 7 | before_script: 8 | 9 | # Check if the current version is equal to the major version for the env. 10 | - 'export IS_INSTALLED="$(npm list video.js | grep "video.js@$VJS")"' 11 | 12 | # We have to add semicolons to the end of each line in the if as Travis runs 13 | # this all on one line. 14 | - 'if [ -z "$IS_INSTALLED" ]; then 15 | echo "INSTALLING video.js@>=$VJS.0.0-RC.0 <$(($VJS+1)).0.0"; 16 | npm i "video.js@>=$VJS.0.0-RC.0 <\$(($VJS+1)).0.0"; 17 | else 18 | echo "video.js@$VJS ALREADY INSTALLED"; 19 | fi' 20 | - export CHROME_BIN=/usr/bin/google-chrome 21 | - export DISPLAY=:99.0 22 | - sh -e /etc/init.d/xvfb start 23 | env: 24 | - VJS=5 25 | - VJS=6 26 | addons: 27 | firefox: latest 28 | apt: 29 | sources: 30 | - google-chrome 31 | packages: 32 | - google-chrome-stable 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Briefly describe the issue. 3 | Include a [reduced test case](https://css-tricks.com/reduced-test-cases/). 4 | 5 | ## Steps to reproduce 6 | Explain in detail the exact steps necessary to reproduce the issue. 7 | 8 | 1. 9 | 2. 10 | 3. 11 | 12 | ## Results 13 | ### Expected 14 | Please describe what you expected to see. 15 | 16 | ### Actual 17 | Please describe what actually happened. 18 | 19 | ### Error output 20 | If there are any errors at all, please include them here. 21 | 22 | ## Additional Information 23 | Please include any additional information necessary here. Including the following: 24 | 25 | ### versions 26 | #### videojs 27 | what version of videojs does this occur with? 28 | 29 | #### browsers 30 | what browser are affected? 31 | 32 | #### OSes 33 | what platforms (operating systems and devices) are affected? 34 | 35 | ### plugins 36 | are any videojs plugins being used on the page? If so, please list them below. 37 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-upnext Demo 6 | 7 | 8 | 9 | 10 | 14 | 19 | 20 | 21 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | 4 | module.exports = { 5 | mode: "production", 6 | entry: { 7 | upnext: './src/js/index.js' 8 | }, 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.js$/, 13 | exclude: /(node_modules)/, 14 | use: { 15 | loader: 'babel-loader', 16 | options: { 17 | presets: ['@babel/preset-env'] 18 | } 19 | } 20 | }, 21 | { 22 | test: /\.s[ac]ss$/i, 23 | use: [ 24 | MiniCssExtractPlugin.loader, 25 | 'css-loader', 26 | 'sass-loader', 27 | ], 28 | }, 29 | ] 30 | }, 31 | plugins: [ 32 | new MiniCssExtractPlugin({ 33 | // Options similar to the same options in webpackOptions.output 34 | // both options are optional 35 | filename: '[name].css', 36 | chunkFilename: '[id].css', 37 | }), 38 | ], 39 | externals: { 40 | 'video.js': 'videojs' 41 | }, 42 | optimization: { 43 | minimize: true 44 | }, 45 | output: { 46 | path: path.join(__dirname, 'dist'), 47 | publicPath: '../dist/', 48 | filename: '[name].js' 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We welcome contributions from everyone! 4 | 5 | ## Getting Started 6 | 7 | Make sure you have NodeJS 0.10 or higher and npm installed. 8 | 9 | 1. Fork this repository and clone your fork 10 | 1. Install dependencies: `npm install` 11 | 1. Run a development server: `npm start` 12 | 13 | ### Making Changes 14 | 15 | Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship. 16 | 17 | When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository. 18 | 19 | ### Running Tests 20 | 21 | Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma]. 22 | 23 | - In all available and supported browsers: `npm test` 24 | - In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc. 25 | - While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local] 26 | 27 | 28 | [karma]: http://karma-runner.github.io/ 29 | [local]: http://localhost:9999/test/ 30 | [conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md 31 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-upnext-card", 3 | "version": "2.2.3", 4 | "description": "Youtube like plugin for up next videos", 5 | "main": "dist/upnext.js", 6 | "jsnext:main": "src/js/index.js", 7 | "engines": { 8 | "node": ">=4.4.0" 9 | }, 10 | "generator-videojs-plugin": { 11 | "version": "4.0.2" 12 | }, 13 | "scripts": { 14 | "build": "webpack", 15 | "clean": "sb-clean", 16 | "lint": "sb-lint", 17 | "start": "webpack -w & http-server", 18 | "test": "sb-test", 19 | "watch": "sb-watch", 20 | "prepublish": "npm run build", 21 | "postversion": "sb-release" 22 | }, 23 | "keywords": [ 24 | "videojs", 25 | "videojs-plugin" 26 | ], 27 | "author": "Fernando Godino ", 28 | "homepage": "https://github.com/venkataramanab/videojs-upnext-card", 29 | "contributors": [ 30 | "venkataramanab (https://github.com/venkataramanab/)" 31 | ], 32 | "repository": "github:venkataramanab/videojs-upnext-card", 33 | "license": "Apache-2.0", 34 | "spellbook": { 35 | "lang": false, 36 | "docs": false 37 | }, 38 | "files": [ 39 | "CHANGELOG.md", 40 | "CONTRIBUTING.md", 41 | "README.md", 42 | "build/docs", 43 | "build/es5", 44 | "dist/", 45 | "docs/", 46 | "index.html", 47 | "src/" 48 | ], 49 | "dependencies": { 50 | "global": "^4.3.2", 51 | "video.js": "^5.16.0" 52 | }, 53 | "devDependencies": { 54 | "@babel/core": "^7.8.3", 55 | "@babel/preset-env": "^7.8.3", 56 | "babel-loader": "^8.0.6", 57 | "css-loader": "^3.4.2", 58 | "http-server": "^0.12.1", 59 | "husky": "^0.13.1", 60 | "mini-css-extract-plugin": "^0.9.0", 61 | "node-sass": "^4.13.1", 62 | "sass-loader": "^8.0.2", 63 | "webpack": "^4.41.5", 64 | "webpack-cli": "^3.3.10" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | import document from 'global/document'; 2 | import QUnit from 'qunitjs'; 3 | import sinon from 'sinon'; 4 | import videojs from 'video.js'; 5 | 6 | import plugin from '../src/js/index.js'; 7 | 8 | const Player = videojs.getComponent('Player'); 9 | 10 | QUnit.module('sanity tests'); 11 | 12 | QUnit.test('the environment is sane', function(assert) { 13 | assert.strictEqual(typeof Array.isArray, 'function', 'es5 exists'); 14 | assert.strictEqual(typeof sinon, 'object', 'sinon exists'); 15 | assert.strictEqual(typeof videojs, 'function', 'videojs exists'); 16 | assert.strictEqual(typeof plugin, 'function', 'plugin is a function'); 17 | }); 18 | 19 | QUnit.module('videojs-upnext', { 20 | 21 | beforeEach() { 22 | 23 | // Mock the environment's timers because certain things - particularly 24 | // player readiness - are asynchronous in video.js 5. This MUST come 25 | // before any player is created; otherwise, timers could get created 26 | // with the actual timer methods! 27 | this.clock = sinon.useFakeTimers(); 28 | 29 | this.fixture = document.getElementById('qunit-fixture'); 30 | this.video = document.createElement('video'); 31 | this.fixture.appendChild(this.video); 32 | this.player = videojs(this.video); 33 | }, 34 | 35 | afterEach() { 36 | this.player.dispose(); 37 | this.clock.restore(); 38 | } 39 | }); 40 | 41 | QUnit.test('registers itself with video.js', function(assert) { 42 | assert.expect(2); 43 | 44 | assert.strictEqual( 45 | typeof Player.prototype.upnext, 46 | 'function', 47 | 'videojs-upnext plugin was registered' 48 | ); 49 | 50 | this.player.upnext(); 51 | 52 | // Tick the clock forward enough to trigger the player to be "ready". 53 | this.clock.tick(1); 54 | 55 | assert.ok( 56 | this.player.hasClass('vjs-upnext'), 57 | 'the plugin adds a class to the player' 58 | ); 59 | }); 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # videojs-upnext 2 | 3 | Youtube like plugin for up next videos 4 | 5 | ## Installation 6 | 7 | ```sh 8 | npm install --save videojs-upnext-card 9 | ``` 10 | 11 | ## Usage 12 | 13 | To include videojs-upnext on your website or web application, use any of the following methods. 14 | 15 | ### ` 21 | 22 | 33 | ``` 34 | 35 | ### Browserify / Webpack 36 | 37 | When using with Browserify, install videojs-upnext via npm and `require` the plugin as you would any other module. 38 | 39 | ```js 40 | var videojs = require('video.js'); 41 | 42 | // The actual plugin function is exported by this module, but it is also 43 | // attached to the `Player.prototype`; so, there is no need to assign it 44 | // to a variable. 45 | require('videojs-upnext-card'); 46 | 47 | var player = videojs('my-video'); 48 | 49 | player.upnext({ 50 | timeout : 5000, 51 | headText : 'Up Next', 52 | cancelText: 'Cancel', 53 | poster: 'posterUrl', 54 | getTitle : function() { return 'Next video title' }, 55 | next : function () { performActionAfterTimeout() } 56 | }); 57 | ``` 58 | 59 | ### RequireJS/AMD 60 | 61 | When using with RequireJS (or another AMD library), get the script in whatever way you prefer and `require` the plugin as you normally would: 62 | 63 | ```js 64 | require(['video.js', 'videojs-upnext-card'], function(videojs) { 65 | var player = videojs('my-video'); 66 | 67 | player.upnext({ 68 | timeout : 5000, 69 | headText : 'Up Next', 70 | cancelText: 'Cancel', 71 | poster: 'posterUrl', 72 | getTitle : function() { return 'Next video title' }, 73 | next : function () { performActionAfterTimeout() } 74 | }); 75 | }); 76 | ``` 77 | 78 | ## License 79 | 80 | Apache-2.0. Copyright (c) Fernando Godino 81 | 82 | 83 | [videojs]: http://videojs.com/ 84 | -------------------------------------------------------------------------------- /src/css/index.scss: -------------------------------------------------------------------------------- 1 | $browser-context: 16; 2 | 3 | @function em($pixels, $context: $browser-context) { 4 | 5 | @return #{$pixels/$context}em; 6 | } 7 | 8 | @mixin transition($string: $transition--default) { 9 | -webkit-transition: $string; 10 | -moz-transition: $string; 11 | -o-transition: $string; 12 | transition: $string; 13 | } 14 | 15 | .video-js { 16 | 17 | .vjs-upnext-content { 18 | pointer-events: all; 19 | display: flex; 20 | flex-direction: column; 21 | } 22 | 23 | .vjs-upnext-background { 24 | font-size: 1.8em; 25 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 26 | position: absolute; 27 | top: 0; 28 | bottom: 0; 29 | background: rgba(0,0,0,0.6) center; 30 | width: 100%; 31 | background-size: contain; 32 | background-repeat: no-repeat; 33 | opacity: 0.2; 34 | @include transition(opacity 0.1s); 35 | } 36 | 37 | .vjs-upnext-top { 38 | width: 100%; 39 | position: absolute; 40 | margin-left: auto; 41 | margin-right: auto; 42 | bottom: 50%; 43 | margin-bottom: 60px; 44 | } 45 | 46 | .vjs-upnext-bottom { 47 | width: 100%; 48 | position: absolute; 49 | margin-left: auto; 50 | margin-right: auto; 51 | top: 50%; 52 | margin-top: 52px; 53 | } 54 | 55 | .vjs-upnext-cancel { 56 | display: block; 57 | float: none; 58 | text-align: center; 59 | } 60 | 61 | .vjs-upnext-headtext { 62 | display: block; 63 | font-size: 14px; 64 | text-align: center; 65 | padding-bottom: 7px; 66 | } 67 | 68 | .vjs-upnext-title { 69 | display: block; 70 | padding: 10px 10px 2px; 71 | text-align: center; 72 | font-size: 22px; 73 | font-weight: 600; 74 | overflow: hidden; 75 | white-space: nowrap; 76 | word-wrap: normal; 77 | -o-text-overflow: ellipsis; 78 | text-overflow: ellipsis; 79 | } 80 | 81 | .vjs-upnext-cancel-button { 82 | cursor: pointer; 83 | display: inline-block; 84 | float: none; 85 | padding: 10px !important; 86 | font-size: 16px !important; 87 | border: none; 88 | } 89 | 90 | .vjs-upnext-cancel-button, 91 | .vjs-upnext-cancel-button:focus { 92 | outline: 0; 93 | } 94 | 95 | .vjs-upnext-cancel-button:hover { 96 | background-color: rgba(255,255,255,0.25); 97 | border-radius: 2px; 98 | } 99 | 100 | &.vjs-no-flex .vjs-upnext-content { 101 | padding-bottom: 1em; 102 | } 103 | 104 | .vjs-upnext-autoplay-icon { 105 | position: absolute; 106 | top: 50%; 107 | left: 50%; 108 | width: 98px; 109 | height: 98px; 110 | margin: -49px 0 0 -49px; 111 | -moz-transition: all 0.1s cubic-bezier(0.4,0,1,1); 112 | -webkit-transition: all 0.1s cubic-bezier(0.4,0,1,1); 113 | transition: all 0.1s cubic-bezier(0.4,0,1,1); 114 | cursor: pointer; 115 | } 116 | 117 | } 118 | 119 | .video-js.vjs-upnext--showing { 120 | pointer-events: none; 121 | } -------------------------------------------------------------------------------- /src/js/index.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | import '../css/index.scss' 3 | const defaults = {}; 4 | 5 | // Cross-compatibility for Video.js 5 and 6. 6 | const registerPlugin = videojs.registerPlugin || videojs.plugin; 7 | // const dom = videojs.dom || videojs; 8 | 9 | function getMainTemplate(options) { 10 | return ` 11 |
12 |
13 |
14 | ${options.headText} 15 |
16 |
17 |
18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
29 | `; 30 | } 31 | 32 | const Component = videojs.getComponent('Component'); 33 | 34 | /** 35 | * EndCard Component 36 | */ 37 | export class EndCard extends Component { 38 | 39 | constructor(player, options) { 40 | super(player, options); 41 | let _this = this; 42 | this.getTitle = this.options_.getTitle; 43 | this.next = this.options_.next; 44 | 45 | this.upNextEvents = new videojs.EventTarget(); 46 | 47 | this.dashOffsetTotal = 586; 48 | this.dashOffsetStart = 293; 49 | this.interval = 50; 50 | this.chunkSize = (this.dashOffsetTotal - this.dashOffsetStart) / (this.options_.timeout / this.interval); 51 | 52 | player.on('ended', (event) => { 53 | player.addClass('vjs-upnext--showing'); 54 | this.showCard((canceled) => { 55 | player.removeClass('vjs-upnext--showing'); 56 | // this.container.style.display = 'none'; 57 | if(!_this.el()) return; 58 | _this.dispose(); 59 | if (!canceled) { 60 | this.next(); 61 | } 62 | }); 63 | }); 64 | 65 | player.on('playing', function() { 66 | this.upNextEvents.trigger('playing'); 67 | }.bind(this)); 68 | } 69 | 70 | createEl() { 71 | 72 | const container = super.createEl('div', { 73 | className: 'upnext-container', 74 | innerHTML: getMainTemplate(this.options_) 75 | }); 76 | 77 | this.container = container; 78 | container.style.display = 'none'; 79 | 80 | this.autoplayRing = container.getElementsByClassName('vjs-upnext-svg-autoplay-ring')[0]; 81 | this.title = container.getElementsByClassName('vjs-upnext-title')[0]; 82 | this.cancelButton = container.getElementsByClassName('vjs-upnext-cancel-button')[0]; 83 | this.nextButton = container.getElementsByClassName('vjs-upnext-autoplay-icon')[0]; 84 | 85 | this.cancelButton.onclick = function() { 86 | this.upNextEvents.trigger('cancel'); 87 | }.bind(this); 88 | 89 | this.nextButton.onclick = function() { 90 | this.upNextEvents.trigger('next'); 91 | }.bind(this); 92 | 93 | return container; 94 | } 95 | 96 | showCard(cb) { 97 | 98 | let timeout; 99 | let start; 100 | let now; 101 | let newOffset; 102 | 103 | this.autoplayRing.setAttribute('stroke-dasharray', this.dashOffsetStart); 104 | this.autoplayRing.setAttribute('stroke-dashoffset', -this.dashOffsetStart); 105 | 106 | this.title.innerHTML = this.getTitle(); 107 | 108 | this.upNextEvents.one('cancel', () => { 109 | clearTimeout(timeout); 110 | cb(true); 111 | }); 112 | 113 | this.upNextEvents.one('playing', () => { 114 | clearTimeout(timeout); 115 | cb(true); 116 | }); 117 | 118 | this.upNextEvents.one('next', () => { 119 | clearTimeout(timeout); 120 | cb(false); 121 | }); 122 | 123 | const update = function() { 124 | now = this.options_.timeout - (new Date().getTime() - start); 125 | 126 | if (now <= 0) { 127 | clearTimeout(timeout); 128 | cb(false); 129 | } else { 130 | newOffset = Math.max(-this.dashOffsetTotal, this.autoplayRing.getAttribute('stroke-dashoffset') - this.chunkSize); 131 | this.autoplayRing.setAttribute('stroke-dashoffset', newOffset); 132 | timeout = setTimeout(update.bind(this), this.interval); 133 | } 134 | 135 | }; 136 | 137 | this.container.style.display = 'block'; 138 | start = new Date().getTime(); 139 | timeout = setTimeout(update.bind(this), this.interval); 140 | } 141 | } 142 | 143 | videojs.registerComponent('EndCard', EndCard); 144 | 145 | /** 146 | * Function to invoke when the player is ready. 147 | * 148 | * This is a great place for your plugin to initialize itself. When this 149 | * function is called, the player will have its DOM and child components 150 | * in place. 151 | * 152 | * @function onPlayerReady 153 | * @param {Player} player 154 | * A Video.js player. 155 | * @param {Object} [options={}] 156 | * An object of options left to the plugin author to define. 157 | */ 158 | const onPlayerReady = (player, options) => { 159 | player.addClass('vjs-upnext'); 160 | }; 161 | 162 | /** 163 | * A video.js plugin. 164 | * 165 | * In the plugin function, the value of `this` is a video.js `Player` 166 | * instance. You cannot rely on the player being in a "ready" state here, 167 | * depending on how the plugin is invoked. This may or may not be important 168 | * to you; if not, remove the wait for "ready"! 169 | * 170 | * @function upnext 171 | * @param {Object} [options={}] 172 | * An object of options left to the plugin author to define. 173 | */ 174 | const upnext = function(options) { 175 | 176 | this.ready(() => { 177 | onPlayerReady(this, videojs.mergeOptions(defaults, options)); 178 | }); 179 | 180 | const opts = options || {}; 181 | const settings = { 182 | next: opts.next, 183 | getTitle: opts.getTitle, 184 | poster: opts.poster, 185 | timeout: opts.timeout || 5000, 186 | cancelText: opts.cancelText || 'Cancel', 187 | headText: opts.headText || 'Up Next' 188 | }; 189 | // removing existing endCard to avoid overlapping multiple endCard's 190 | this.removeChild('endCard'); 191 | this.addChild('endCard', settings); 192 | 193 | }; 194 | 195 | // Register the plugin with video.js. 196 | registerPlugin('upnext', upnext); 197 | 198 | // Include the version number. 199 | upnext.VERSION = '__VERSION__'; 200 | 201 | export default upnext; 202 | --------------------------------------------------------------------------------