├── .nvmrc ├── lang ├── ja.json ├── ko.json ├── zh-Hans.json ├── zh-Hant.json ├── en.json ├── ar.json ├── es.json ├── fr.json └── de.json ├── test ├── example │ ├── oceans.jpg │ └── oceans-low.jpg └── plugin.test.js ├── .npmignore ├── scripts ├── postcss.config.js ├── karma.conf.js └── rollup.config.js ├── .editorconfig ├── .travis.yml ├── .gitignore ├── LICENSE ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── examples.css ├── index.html ├── CONTRIBUTING.md ├── package.json ├── src ├── plugin.js ├── playlist-menu-item.js ├── plugin.scss └── playlist-menu.js ├── example-custom-class.html ├── example-custom-element.html ├── README.md ├── example-custom-data.html ├── example-horizontal.html ├── example-two-players.html ├── example.html └── CHANGELOG.md /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/hydrogen 2 | -------------------------------------------------------------------------------- /lang/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "現在再生中", 3 | "Up Next": "次の動画", 4 | "Untitled Video": "無題の動画" 5 | } 6 | -------------------------------------------------------------------------------- /test/example/oceans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/videojs-playlist-ui/HEAD/test/example/oceans.jpg -------------------------------------------------------------------------------- /lang/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "지금 재생 중", 3 | "Up Next": "다음", 4 | "Untitled Video": "제목 없는 비디오" 5 | } 6 | -------------------------------------------------------------------------------- /lang/zh-Hans.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "正在播放", 3 | "Up Next": "播放下一个", 4 | "Untitled Video": "无标题视频" 5 | } 6 | -------------------------------------------------------------------------------- /lang/zh-Hant.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "正在播放", 3 | "Up Next": "播放下一個", 4 | "Untitled Video": "未命名視訊" 5 | } 6 | -------------------------------------------------------------------------------- /test/example/oceans-low.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/videojs/videojs-playlist-ui/HEAD/test/example/oceans-low.jpg -------------------------------------------------------------------------------- /lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "Now Playing", 3 | "Up Next": "Up Next", 4 | "Untitled Video": "Untitled Video" 5 | } 6 | -------------------------------------------------------------------------------- /lang/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "قيد التشغيل الآن", 3 | "Up Next": "التالي", 4 | "Untitled Video": "مقطع فيديو بدون عنوان" 5 | } 6 | -------------------------------------------------------------------------------- /lang/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "Reproduciendo", 3 | "Up Next": "A continuación:", 4 | "Untitled Video": "Vídeo sin título" 5 | } 6 | -------------------------------------------------------------------------------- /lang/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "En cours de lecture", 3 | "Up Next": "À suivre", 4 | "Untitled Video": "Vidéo sans titre" 5 | } 6 | -------------------------------------------------------------------------------- /lang/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "Now Playing": "Aktuelle Wiedergabe", 3 | "Up Next": "Als Nächstes", 4 | "Untitled Video": "Video ohne Titel" 5 | } 6 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /scripts/postcss.config.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-postcss-config'); 2 | 3 | module.exports = function(context) { 4 | const result = generate({}, context); 5 | 6 | // do custom stuff here 7 | 8 | return result; 9 | }; 10 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /scripts/karma.conf.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-karma-config'); 2 | 3 | module.exports = function(config) { 4 | 5 | // see https://github.com/videojs/videojs-generate-karma-config 6 | // for options 7 | const options = {}; 8 | 9 | config = generate(config, options); 10 | 11 | // any other custom stuff not supported by options here! 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /scripts/rollup.config.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-rollup-config'); 2 | 3 | // see https://github.com/videojs/videojs-generate-rollup-config 4 | // for options 5 | const options = {}; 6 | const config = generate(options); 7 | 8 | // Add additonal builds/customization here! 9 | 10 | // export the builds to rollup 11 | export default Object.values(config.builds); 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | dist: trusty 3 | language: node_js 4 | # node version is specified using the .nvmrc file 5 | before_install: 6 | - npm install -g greenkeeper-lockfile@1 7 | before_script: 8 | - export DISPLAY=:99.0 9 | - sh -e /etc/init.d/xvfb start 10 | - greenkeeper-lockfile-update 11 | after_script: 12 | - greenkeeper-lockfile-upload 13 | addons: 14 | firefox: latest 15 | chrome: stable 16 | 17 | -------------------------------------------------------------------------------- /.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 | # Build-related directories 29 | dist/ 30 | docs/api/ 31 | test/dist/ 32 | .eslintcache 33 | .yo-rc.json 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Brightcove, Inc. 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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /examples.css: -------------------------------------------------------------------------------- 1 | /* 2 | We include some minimal custom CSS to make the playlist UI look good 3 | in this context. 4 | */ 5 | 6 | body { 7 | font-family: Arial, sans-serif; 8 | } 9 | 10 | .info { 11 | background-color: #eee; 12 | border: thin solid #333; 13 | border-radius: 3px; 14 | margin: 0 0 20px; 15 | padding: 0 5px; 16 | } 17 | 18 | .player-container { 19 | background: #1a1a1a; 20 | overflow: auto; 21 | width: 900px; 22 | margin: 0 0 20px; 23 | } 24 | 25 | .video-js { 26 | float: left; 27 | } 28 | 29 | .vjs-playlist, 30 | .my-custom-class, 31 | #my-custom-element { 32 | float: left; 33 | width: 300px; 34 | } 35 | 36 | .vjs-playlist.vjs-playlist-horizontal { 37 | float: none; 38 | height: 120px; 39 | width: 600px; 40 | } 41 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-playlist-ui Demo 6 | 7 | 8 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We welcome contributions from everyone! 4 | 5 | ## Getting Started 6 | 7 | Make sure you have Node.js 4.8 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-playlist-ui", 3 | "version": "5.0.0", 4 | "author": "Brightcove, Inc.", 5 | "description": "A user interface for the videojs-playlist API", 6 | "license": "Apache-2.0", 7 | "keywords": [ 8 | "playlist", 9 | "videojs", 10 | "videojs-plugin" 11 | ], 12 | "scripts": { 13 | "prebuild": "npm run clean", 14 | "build": "npm-run-all -p build:*", 15 | "build:css": "sass src/plugin.scss dist/videojs-playlist-ui.css --style compressed", 16 | "build:js": "rollup -c scripts/rollup.config.js", 17 | "build:lang": "vjslang --dir dist/lang", 18 | "clean": "shx rm -rf ./dist ./test/dist", 19 | "postclean": "shx mkdir -p ./dist ./test/dist", 20 | "docs": "doctoc README.md", 21 | "lint": "vjsstandard", 22 | "server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch", 23 | "start": "npm-run-all -p server watch", 24 | "pretest": "npm-run-all lint build", 25 | "test": "karma start scripts/karma.conf.js", 26 | "update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", 27 | "version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md", 28 | "watch": "npm-run-all -p watch:*", 29 | "watch:css": "npm run build:css -- -w", 30 | "watch:js": "npm run build:js -- -w", 31 | "posttest": "shx cat test/dist/coverage/text.txt", 32 | "prepublishOnly": "npm run build && vjsverify --skip-es-check" 33 | }, 34 | "repository": { 35 | "type": "git", 36 | "url": "https://github.com/videojs/videojs-playlist-ui" 37 | }, 38 | "dependencies": { 39 | "global": "^4.4.0" 40 | }, 41 | "devDependencies": { 42 | "conventional-changelog-cli": "^2.2.2", 43 | "conventional-changelog-videojs": "^3.0.2", 44 | "doctoc": "^2.2.1", 45 | "husky": "^1.3.1", 46 | "karma": "^6.4.2", 47 | "lint-staged": "^13.2.2", 48 | "not-prerelease": "^1.0.1", 49 | "npm-merge-driver-install": "^3.0.0", 50 | "npm-run-all": "^4.1.5", 51 | "pkg-ok": "^2.2.0", 52 | "rollup": "^2.61.1", 53 | "sass": "^1.62.1", 54 | "shx": "^0.3.2", 55 | "sinon": "^6.1.5", 56 | "video.js": "^8.0.0", 57 | "videojs-generate-karma-config": "^8.0.1", 58 | "videojs-generate-rollup-config": "^7.0.0", 59 | "videojs-generator-verify": "^4.0.1", 60 | "videojs-languages": "^1.0.0", 61 | "videojs-playlist": "^5.1.0", 62 | "videojs-standard": "^9.0.1" 63 | }, 64 | "peerDependencies": { 65 | "video.js": "^8.0.0", 66 | "videojs-playlist": "^5.1.0" 67 | }, 68 | "main": "dist/videojs-playlist-ui.cjs.js", 69 | "module": "dist/videojs-playlist-ui.es.js", 70 | "generator-videojs-plugin": { 71 | "version": "7.3.2" 72 | }, 73 | "vjsstandard": { 74 | "jsdoc": false, 75 | "ignore": [ 76 | "dist", 77 | "docs", 78 | "test/dist" 79 | ] 80 | }, 81 | "files": [ 82 | "CONTRIBUTING.md", 83 | "dist/", 84 | "docs/", 85 | "index.html", 86 | "scripts/", 87 | "src/", 88 | "test/" 89 | ], 90 | "lint-staged": { 91 | "*.js": [ 92 | "vjsstandard --fix", 93 | "git add" 94 | ], 95 | "README.md": [ 96 | "npm run docs", 97 | "git add" 98 | ] 99 | }, 100 | "husky": { 101 | "hooks": { 102 | "pre-commit": "lint-staged" 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | import document from 'global/document'; 2 | import videojs from 'video.js'; 3 | import {version as VERSION} from '../package.json'; 4 | import PlaylistMenu from './playlist-menu'; 5 | 6 | // see https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/pointerevents.js 7 | const supportsCssPointerEvents = (() => { 8 | const element = document.createElement('x'); 9 | 10 | element.style.cssText = 'pointer-events:auto'; 11 | return element.style.pointerEvents === 'auto'; 12 | })(); 13 | 14 | const defaults = { 15 | className: 'vjs-playlist', 16 | playOnSelect: false, 17 | supportsCssPointerEvents 18 | }; 19 | 20 | const Plugin = videojs.getPlugin('plugin'); 21 | 22 | /** 23 | * Initialize the plugin on a player. 24 | * 25 | * @param {Object} [options] 26 | * An options object. 27 | * 28 | * @param {HTMLElement} [options.el] 29 | * A DOM element to use as a root node for the playlist. 30 | * 31 | * @param {string} [options.className] 32 | * An HTML class name to use to find a root node for the playlist. 33 | * 34 | * @param {boolean} [options.playOnSelect = false] 35 | * If true, will attempt to begin playback upon selecting a new 36 | * playlist item in the UI. 37 | */ 38 | class PlaylistUI extends Plugin { 39 | 40 | constructor(player, options) { 41 | super(player, options); 42 | 43 | if (!player.usingPlugin('playlist')) { 44 | player.log.error('videojs-playlist plugin is required by the videojs-playlist-ui plugin'); 45 | return; 46 | } 47 | 48 | options = this.options_ = videojs.obj.merge(defaults, options); 49 | 50 | if (!videojs.dom.isEl(options.el)) { 51 | options.el = this.findRoot_(options.className); 52 | } 53 | 54 | // Expose the playlist menu component on the player as well as the plugin 55 | // This is a bit of an anti-pattern, but it's been that way forever and 56 | // there are likely to be integrations relying on it. 57 | this.playlistMenu = player.playlistMenu = new PlaylistMenu(player, options); 58 | } 59 | 60 | /** 61 | * Dispose the plugin. 62 | */ 63 | dispose() { 64 | super.dispose(); 65 | this.playlistMenu.dispose(); 66 | } 67 | 68 | /** 69 | * Returns a boolean indicating whether an element has child elements. 70 | * 71 | * Note that this is distinct from whether it has child _nodes_. 72 | * 73 | * @param {HTMLElement} el 74 | * A DOM element. 75 | * 76 | * @return {boolean} 77 | * Whether the element has child elements. 78 | */ 79 | hasChildEls_(el) { 80 | for (let i = 0; i < el.childNodes.length; i++) { 81 | if (videojs.dom.isEl(el.childNodes[i])) { 82 | return true; 83 | } 84 | } 85 | return false; 86 | } 87 | 88 | /** 89 | * Finds the first empty root element. 90 | * 91 | * @param {string} className 92 | * An HTML class name to search for. 93 | * 94 | * @return {HTMLElement} 95 | * A DOM element to use as the root for a playlist. 96 | */ 97 | findRoot_(className) { 98 | const all = document.querySelectorAll('.' + className); 99 | 100 | for (let i = 0; i < all.length; i++) { 101 | if (!this.hasChildEls_(all[i])) { 102 | return all[i]; 103 | } 104 | } 105 | } 106 | } 107 | 108 | videojs.registerPlugin('playlistUi', PlaylistUI); 109 | 110 | PlaylistUI.VERSION = VERSION; 111 | 112 | export default PlaylistUI; 113 | -------------------------------------------------------------------------------- /example-custom-class.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Video.js Playlist UI - Using a Custom Class 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Video.js Playlist UI - Using a Custom Class

13 |

14 | You can see the Video.js Playlist UI plugin in action below. Look at the 15 | source of this page to see how to use it with your videos. 16 |

17 |

18 | When using a custom class, the plugin looks for the first element that 19 | matches the given class and uses that as a container for the list. 20 |

21 |

22 | Using this option means the default styles WILL NOT apply; so, 23 | you'll have to define your own. This may be desirable or not - 24 | depending on your implementation. This example has been left un-styled 25 | to demonstrate this fact. 26 |

27 |
28 | 29 |
30 | 39 | 40 |
41 | 45 |
46 |
47 | 48 | 49 | 50 | 51 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /example-custom-element.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Video.js Playlist UI - Using a Custom Element 6 | 7 | 8 | 9 | 10 | 11 |
12 |

Video.js Playlist UI - Using a Custom Element

13 |

14 | You can see the Video.js Playlist UI plugin in action below. Look at the 15 | source of this page to see how to use it with your videos. 16 |

17 |

18 | When using a custom element, the plugin uses the element that it was 19 | given as a container for the list. 20 |

21 |

22 | Using this option means the default styles MAY NOT apply (it 23 | depends on whether the element has the "vjs-playlist" class) so, you 24 | might have to define your own. This may be desirable or not - 25 | depending on your implementation. This example has been left un-styled 26 | to demonstrate this fact. 27 |

28 |
29 | 30 |
31 | 40 | 41 |
42 | 46 |
47 |
48 | 49 | 50 | 51 | 52 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # videojs-playlist-ui 2 | 3 | [![NPM](https://nodei.co/npm/videojs-playlist-ui.png?downloads=true&downloadRank=true)](https://nodei.co/npm/videojs-playlist-ui/) 4 | 5 | A playlist video picker for video.js and videojs-playlist 6 | 7 | Maintenance Status: Stable 8 | 9 | 10 | 11 | 12 | - [Getting Started](#getting-started) 13 | - [Root Element](#root-element) 14 | - [Using Automatic Discovery (default, example)](#using-automatic-discovery-default-example) 15 | - [Using a Custom Class (example)](#using-a-custom-class-example) 16 | - [Using a Custom Element (example)](#using-a-custom-element-example) 17 | - [Other Options](#other-options) 18 | - [`className`](#classname) 19 | - [playOnSelect](#playonselect) 20 | - [Playlists and Advertisements](#playlists-and-advertisements) 21 | 22 | 23 | 24 | 25 | ## Getting Started 26 | Include the plugin script in your page, and a placeholder list element with the class `vjs-playlist` to house the playlist menu: 27 | 28 | ```html 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 50 | ``` 51 | 52 | There's also a [working example](example.html) of the plugin you can check out if you're having trouble. 53 | 54 | ## Root Element 55 | Before this plugin will work at all, it needs an element in the DOM to which to attach itself. There are three ways to find or provide this element. 56 | 57 | > **NOTE:** In v2.x of this plugin, the root element was expected to be a list element (i.e., `
    ` or `