├── .editorconfig ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .npmignore ├── .nvmrc ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── index.html ├── lang ├── de.json ├── en.json ├── fa.json ├── it.json ├── ja.json ├── lv.json ├── nl.json ├── ru.json ├── zh-CN.json └── zh-TW.json ├── package-lock.json ├── package.json ├── scripts ├── karma.conf.js ├── postcss.config.js └── rollup.config.js ├── src ├── plugin.css └── plugin.js └── test └── 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 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | commit-message: 8 | prefix: fix 9 | prefix-development: chore 10 | include: scope 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | should-skip: 7 | continue-on-error: true 8 | runs-on: ubuntu-latest 9 | # Map a step output to a job output 10 | outputs: 11 | should-skip-job: ${{steps.skip-check.outputs.should_skip}} 12 | steps: 13 | - id: skip-check 14 | uses: fkirc/skip-duplicate-actions@v2.1.0 15 | with: 16 | github_token: ${{github.token}} 17 | 18 | ci: 19 | needs: should-skip 20 | if: ${{needs.should-skip.outputs.should-skip-job != 'true' || github.ref == 'refs/heads/main'}} 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | os: [ubuntu-latest] 25 | env: 26 | BROWSER_STACK_USERNAME: ${{secrets.BROWSER_STACK_USERNAME}} 27 | BROWSER_STACK_ACCESS_KEY: ${{secrets.BROWSER_STACK_ACCESS_KEY}} 28 | runs-on: ${{matrix.os}} 29 | steps: 30 | - name: checkout code 31 | uses: actions/checkout@v2 32 | 33 | - name: Cache dependencies 34 | uses: actions/cache@v2 35 | with: 36 | path: | 37 | ~/.npm 38 | **/node_modules 39 | key: ${{runner.os}}-npm-${{hashFiles('**/package-lock.json')}} 40 | restore-keys: | 41 | ${{runner.os}}-npm- 42 | ${{runner.os}}- 43 | 44 | - name: read node version from .nvmrc 45 | run: echo ::set-output name=NVMRC::$(cat .nvmrc) 46 | shell: bash 47 | id: nvm 48 | 49 | - name: update apt cache on linux w/o browserstack 50 | run: sudo apt-get update 51 | if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}} 52 | 53 | - name: install ffmpeg/pulseaudio for firefox on linux w/o browserstack 54 | run: sudo apt-get install ffmpeg pulseaudio 55 | if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}} 56 | 57 | - name: start pulseaudio for firefox on linux w/o browserstack 58 | run: pulseaudio -D 59 | if: ${{startsWith(matrix.os, 'ubuntu') && !env.BROWSER_STACK_USERNAME}} 60 | 61 | - name: setup node 62 | uses: actions/setup-node@v1 63 | with: 64 | node-version: '${{steps.nvm.outputs.NVMRC}}' 65 | 66 | # turn off the default setup-node problem watchers... 67 | - run: echo "::remove-matcher owner=eslint-compact::" 68 | - run: echo "::remove-matcher owner=eslint-stylish::" 69 | - run: echo "::remove-matcher owner=tsc::" 70 | 71 | - name: npm install 72 | run: npm i --prefer-offline --no-audit 73 | 74 | - name: run npm test 75 | uses: GabrielBB/xvfb-action@v1 76 | with: 77 | run: npm run test 78 | -------------------------------------------------------------------------------- /.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 | es/ 31 | cjs/ 32 | docs/api/ 33 | test/dist/ 34 | .eslintcache 35 | .yo-rc.json 36 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: node_js 3 | # node version is specified using the .nvmrc file 4 | cache: npm 5 | before_install: 6 | - npm install -g greenkeeper-lockfile@1 7 | before_script: 8 | - greenkeeper-lockfile-update 9 | after_script: 10 | - greenkeeper-lockfile-upload 11 | addons: 12 | firefox: latest 13 | chrome: stable 14 | services: 15 | - xvfb 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [4.0.2](https://github.com/mister-ben/videojs-seek-buttons/compare/v4.0.1...v4.0.2) (2023-01-17) 3 | 4 | ### Bug Fixes 5 | 6 | * **deps:** bump decode-uri-component from 0.2.0 to 0.2.2 (#106) ([7c78da1](https://github.com/mister-ben/videojs-seek-buttons/commit/7c78da1)), closes [#106](https://github.com/mister-ben/videojs-seek-buttons/issues/106) 7 | * **deps:** bump json5 from 2.1.3 to 2.2.3 (#111) ([d9d5e95](https://github.com/mister-ben/videojs-seek-buttons/commit/d9d5e95)), closes [#111](https://github.com/mister-ben/videojs-seek-buttons/issues/111) 8 | 9 | ### Chores 10 | 11 | * **deps-dev:** bump [@babel](https://github.com/babel)/cli from 7.19.3 to 7.20.7 (#110) ([0ad741d](https://github.com/mister-ben/videojs-seek-buttons/commit/0ad741d)), closes [#110](https://github.com/mister-ben/videojs-seek-buttons/issues/110) 12 | * **deps-dev:** bump [@babel](https://github.com/babel)/runtime from 7.20.1 to 7.20.6 (#104) ([753f849](https://github.com/mister-ben/videojs-seek-buttons/commit/753f849)), closes [#104](https://github.com/mister-ben/videojs-seek-buttons/issues/104) 13 | * **deps-dev:** bump [@babel](https://github.com/babel)/runtime from 7.20.6 to 7.20.7 (#109) ([7f81b6d](https://github.com/mister-ben/videojs-seek-buttons/commit/7f81b6d)), closes [#109](https://github.com/mister-ben/videojs-seek-buttons/issues/109) 14 | * **deps-dev:** bump postcss from 8.4.19 to 8.4.20 (#107) ([5d91486](https://github.com/mister-ben/videojs-seek-buttons/commit/5d91486)), closes [#107](https://github.com/mister-ben/videojs-seek-buttons/issues/107) 15 | * **deps-dev:** bump postcss from 8.4.20 to 8.4.21 (#114) ([aa9370b](https://github.com/mister-ben/videojs-seek-buttons/commit/aa9370b)), closes [#114](https://github.com/mister-ben/videojs-seek-buttons/issues/114) 16 | * **deps-dev:** bump sinon from 14.0.2 to 15.0.0 (#105) ([6d57ed0](https://github.com/mister-ben/videojs-seek-buttons/commit/6d57ed0)), closes [#105](https://github.com/mister-ben/videojs-seek-buttons/issues/105) 17 | * **deps-dev:** bump sinon from 15.0.0 to 15.0.1 (#108) ([83ebc32](https://github.com/mister-ben/videojs-seek-buttons/commit/83ebc32)), closes [#108](https://github.com/mister-ben/videojs-seek-buttons/issues/108) 18 | * **deps-dev:** bump video.js from 8.0.0 to 8.0.1 (#102) ([f89a7fc](https://github.com/mister-ben/videojs-seek-buttons/commit/f89a7fc)), closes [#102](https://github.com/mister-ben/videojs-seek-buttons/issues/102) 19 | * **deps-dev:** bump video.js from 8.0.1 to 8.0.2 (#103) ([379dc99](https://github.com/mister-ben/videojs-seek-buttons/commit/379dc99)), closes [#103](https://github.com/mister-ben/videojs-seek-buttons/issues/103) 20 | * **deps-dev:** bump video.js from 8.0.2 to 8.0.3 (#112) ([6401398](https://github.com/mister-ben/videojs-seek-buttons/commit/6401398)), closes [#112](https://github.com/mister-ben/videojs-seek-buttons/issues/112) 21 | 22 | 23 | ## [4.0.1](https://github.com/mister-ben/videojs-seek-buttons/compare/v4.0.0...v4.0.1) (2022-11-23) 24 | 25 | ### Documentation 26 | 27 | * Note version support in readme ([9778b38](https://github.com/mister-ben/videojs-seek-buttons/commit/9778b38)) 28 | 29 | 30 | # [4.0.0](https://github.com/mister-ben/videojs-seek-buttons/compare/v4.0.0-1...v4.0.0) (2022-11-23) 31 | 32 | ### Bug Fixes 33 | 34 | * **deps:** bump engine.io from 6.2.0 to 6.2.1 (#98) ([934f2a1](https://github.com/mister-ben/videojs-seek-buttons/commit/934f2a1)), closes [#98](https://github.com/mister-ben/videojs-seek-buttons/issues/98) 35 | 36 | ### Chores 37 | 38 | * **deps-dev:** bump [@babel](https://github.com/babel)/runtime from 7.19.4 to 7.20.1 (#99) ([232e2d1](https://github.com/mister-ben/videojs-seek-buttons/commit/232e2d1)), closes [#99](https://github.com/mister-ben/videojs-seek-buttons/issues/99) 39 | * **deps-dev:** bump postcss from 8.4.18 to 8.4.19 (#100) ([9d68302](https://github.com/mister-ben/videojs-seek-buttons/commit/9d68302)), closes [#100](https://github.com/mister-ben/videojs-seek-buttons/issues/100) 40 | * **deps-dev:** bump sinon from 14.0.1 to 14.0.2 (#101) ([1af4bd8](https://github.com/mister-ben/videojs-seek-buttons/commit/1af4bd8)), closes [#101](https://github.com/mister-ben/videojs-seek-buttons/issues/101) 41 | * update dep to release version of vjs 8 ([4398518](https://github.com/mister-ben/videojs-seek-buttons/commit/4398518)) 42 | 43 | 44 | # [4.0.0-1](https://github.com/mister-ben/videojs-seek-buttons/compare/v3.0.1...v4.0.0-1) (2022-11-21) 45 | 46 | ### Features 47 | 48 | * Video.js 8 support (#97) ([597fe02](https://github.com/mister-ben/videojs-seek-buttons/commit/597fe02)), closes [#97](https://github.com/mister-ben/videojs-seek-buttons/issues/97) [#90](https://github.com/mister-ben/videojs-seek-buttons/issues/90) [#96](https://github.com/mister-ben/videojs-seek-buttons/issues/96) 49 | 50 | ### Chores 51 | 52 | * **deps-dev:** bump [@babel](https://github.com/babel)/cli from 7.13.16 to 7.19.3 (#84) ([834d35f](https://github.com/mister-ben/videojs-seek-buttons/commit/834d35f)), closes [#84](https://github.com/mister-ben/videojs-seek-buttons/issues/84) 53 | * **deps-dev:** bump [@babel](https://github.com/babel)/runtime from 7.14.0 to 7.19.4 (#87) ([48c856d](https://github.com/mister-ben/videojs-seek-buttons/commit/48c856d)), closes [#87](https://github.com/mister-ben/videojs-seek-buttons/issues/87) 54 | * **deps-dev:** bump [@babel](https://github.com/babel)/runtime from 7.19.4 to 7.20.1 (#92) ([191899b](https://github.com/mister-ben/videojs-seek-buttons/commit/191899b)), closes [#92](https://github.com/mister-ben/videojs-seek-buttons/issues/92) 55 | * **deps-dev:** bump jsdoc from 3.6.11 to 4.0.0 (#93) ([1c48f93](https://github.com/mister-ben/videojs-seek-buttons/commit/1c48f93)), closes [#93](https://github.com/mister-ben/videojs-seek-buttons/issues/93) 56 | * **deps-dev:** bump karma from 6.3.16 to 6.4.1 (#88) ([930fbd4](https://github.com/mister-ben/videojs-seek-buttons/commit/930fbd4)), closes [#88](https://github.com/mister-ben/videojs-seek-buttons/issues/88) 57 | * **deps-dev:** bump postcss from 8.2.13 to 8.4.18 (#89) ([614ca7e](https://github.com/mister-ben/videojs-seek-buttons/commit/614ca7e)), closes [#89](https://github.com/mister-ben/videojs-seek-buttons/issues/89) 58 | * **deps-dev:** bump postcss from 8.4.18 to 8.4.19 (#95) ([12c496f](https://github.com/mister-ben/videojs-seek-buttons/commit/12c496f)), closes [#95](https://github.com/mister-ben/videojs-seek-buttons/issues/95) 59 | * **deps-dev:** bump rollup from 2.46.0 to 2.79.1 (#83) ([23ef14d](https://github.com/mister-ben/videojs-seek-buttons/commit/23ef14d)), closes [#83](https://github.com/mister-ben/videojs-seek-buttons/issues/83) 60 | * **deps-dev:** bump sinon from 14.0.1 to 14.0.2 (#94) ([2562054](https://github.com/mister-ben/videojs-seek-buttons/commit/2562054)), closes [#94](https://github.com/mister-ben/videojs-seek-buttons/issues/94) 61 | * **deps-dev:** bump sinon from 9.2.4 to 14.0.1 (#86) ([f2fa7b8](https://github.com/mister-ben/videojs-seek-buttons/commit/f2fa7b8)), closes [#86](https://github.com/mister-ben/videojs-seek-buttons/issues/86) 62 | * **deps-dev:** bump videojs-generate-karma-config from 8.0.0 to 8.0.1 (#85) ([2458e4e](https://github.com/mister-ben/videojs-seek-buttons/commit/2458e4e)), closes [#85](https://github.com/mister-ben/videojs-seek-buttons/issues/85) 63 | 64 | 65 | ## [3.0.1](https://github.com/mister-ben/videojs-seek-buttons/compare/v3.0.0...v3.0.1) (2022-10-18) 66 | 67 | ### Chores 68 | 69 | * Use conventional commit prefixes with dependabot (#82) ([d8da86f](https://github.com/mister-ben/videojs-seek-buttons/commit/d8da86f)), closes [#82](https://github.com/mister-ben/videojs-seek-buttons/issues/82) 70 | 71 | 72 | # [3.0.0](https://github.com/mister-ben/videojs-seek-buttons/compare/v2.2.1...v3.0.0) (2022-09-19) 73 | 74 | ### Chores 75 | 76 | * cleanup comments ([3111020](https://github.com/mister-ben/videojs-seek-buttons/commit/3111020)) 77 | * Move video.js to peerDependencies (#74) ([870408c](https://github.com/mister-ben/videojs-seek-buttons/commit/870408c)), closes [#74](https://github.com/mister-ben/videojs-seek-buttons/issues/74) 78 | * vjs verify update ([7bc9765](https://github.com/mister-ben/videojs-seek-buttons/commit/7bc9765)) 79 | 80 | ### Documentation 81 | 82 | * Clarify peerDependency in Readme ([a4a118f](https://github.com/mister-ben/videojs-seek-buttons/commit/a4a118f)) 83 | 84 | 85 | ### BREAKING CHANGES 86 | 87 | * video.js is no longer a dependency but a peer dependency. 88 | This should alleviate issues with requiring/importing the right version, 89 | but if video.js wasn't explicitly installed before it now needs to be. 90 | * es and cjs script paths change to match current video.js 91 | plugin standards. 92 | 93 | 94 | ## [2.2.1](https://github.com/mister-ben/videojs-seek-buttons/compare/v2.2.0...v2.2.1) (2022-04-23) 95 | 96 | ### Bug Fixes 97 | 98 | * don't try to seek past start or end (#68) ([e349018](https://github.com/mister-ben/videojs-seek-buttons/commit/e349018)), closes [#68](https://github.com/mister-ben/videojs-seek-buttons/issues/68) [#69](https://github.com/mister-ben/videojs-seek-buttons/issues/69) 99 | 100 | ### Chores 101 | 102 | * Remove erroneous sass comment ([5efc6fd](https://github.com/mister-ben/videojs-seek-buttons/commit/5efc6fd)) 103 | 104 | 105 | # [2.2.0](https://github.com/mister-ben/videojs-seek-buttons/compare/v2.0.0...v2.2.0) (2021-10-06) 106 | 107 | ### Features 108 | 109 | * Add Latvian (#52) 110 | * Add Russian (#53) 111 | 112 | ### Bug Fixes 113 | 114 | * Workaround for Safari bug with rotateY (#47) ([eadd89a](https://github.com/mister-ben/videojs-seek-buttons/commit/eadd89a)), closes [#47](https://github.com/mister-ben/videojs-seek-buttons/issues/47) 115 | 116 | 117 | # [2.1.0](https://github.com/mister-ben/videojs-seek-buttons/compare/v2.0.1...v2.1.0) (2021-07-20) 118 | 119 | 120 | ### Features 121 | 122 | * Add Farsi (#49) ([eda3607b2c564b1578133a76ece4c90de64439f3](https://github.com/mister-ben/videojs-seek-buttons/commit/eda3607b2c564b1578133a76ece4c90de64439f3)) 123 | 124 | 125 | ## [2.0.1](https://github.com/mister-ben/videojs-seek-buttons/compare/v1.3.0...v2.0.1) (2021-06-06) 126 | 127 | ### Features 128 | 129 | * Remove google font (#38) ([1d85d5a](https://github.com/mister-ben/videojs-seek-buttons/commit/1d85d5a)), closes [#38](https://github.com/mister-ben/videojs-seek-buttons/issues/38) 130 | 131 | ### Bug Fixes 132 | 133 | * Restore skip-n classes (#45) ([0c9c453](https://github.com/mister-ben/videojs-seek-buttons/commit/0c9c453)), closes [#45](https://github.com/mister-ben/videojs-seek-buttons/issues/45) 134 | * Workaround for Safari bug with rotateY (#47) ([eadd89a](https://github.com/mister-ben/videojs-seek-buttons/commit/eadd89a)), closes [#47](https://github.com/mister-ben/videojs-seek-buttons/issues/47) 135 | 136 | ### Chores 137 | 138 | * Complete JSDoc comments ([fa24f5b](https://github.com/mister-ben/videojs-seek-buttons/commit/fa24f5b)) 139 | * Improve tests ([12c3dcf](https://github.com/mister-ben/videojs-seek-buttons/commit/12c3dcf)) 140 | * Update plugin generator to v7 ([141c2e4](https://github.com/mister-ben/videojs-seek-buttons/commit/141c2e4)) 141 | * Update to Node 14 and Generator 8 packages ([06e56d5](https://github.com/mister-ben/videojs-seek-buttons/commit/06e56d5)) 142 | 143 | ### Documentation 144 | 145 | * add css and option to readme ([d08a9df](https://github.com/mister-ben/videojs-seek-buttons/commit/d08a9df)) 146 | 147 | 148 | # [2.0.0](https://github.com/mister-ben/videojs-seek-buttons/compare/v1.3.0...v2.0.0) (2021-05-31) 149 | 150 | ### Features 151 | 152 | * Remove google font (#38) ([1d85d5a](https://github.com/mister-ben/videojs-seek-buttons/commit/1d85d5a)), closes [#38](https://github.com/mister-ben/videojs-seek-buttons/issues/38) 153 | 154 | ### Bug Fixes 155 | 156 | * Restore skip-n classes (#45) ([0c9c453](https://github.com/mister-ben/videojs-seek-buttons/commit/0c9c453)), closes [#45](https://github.com/mister-ben/videojs-seek-buttons/issues/45) 157 | 158 | ### Chores 159 | 160 | * Complete JSDoc comments ([fa24f5b](https://github.com/mister-ben/videojs-seek-buttons/commit/fa24f5b)) 161 | * Improve tests ([12c3dcf](https://github.com/mister-ben/videojs-seek-buttons/commit/12c3dcf)) 162 | * Update plugin generator to v7 ([141c2e4](https://github.com/mister-ben/videojs-seek-buttons/commit/141c2e4)) 163 | * Update to Node 14 and Generator 8 packages ([06e56d5](https://github.com/mister-ben/videojs-seek-buttons/commit/06e56d5)) 164 | 165 | ### Documentation 166 | 167 | * add css and option to readme ([d08a9df](https://github.com/mister-ben/videojs-seek-buttons/commit/d08a9df)) 168 | 169 | 170 | # [1.5.0](https://github.com/mister-ben/videojs-seek-buttons/compare/v1.5.0-beta0...v1.5.0) (2019-04-18) 171 | 172 | ### Documentation 173 | 174 | * add css and option to readme ([d08a9df](https://github.com/mister-ben/videojs-seek-buttons/commit/d08a9df)) 175 | 176 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We welcome contributions from everyone! 4 | 5 | ## Getting Started 6 | 7 | Make sure you have Node.js 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright mister-ben 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # videojs-seek-buttons 2 | 3 | Plugin for video.js to add seek buttons to the control bar. These buttons allow the user to skip forward or back by a configured number of seconds. 4 | 5 | ## Table of Contents 6 | 7 | 8 | 9 | 10 | 11 | - [Installation](#installation) 12 | - [Options](#options) 13 | - [Control position](#control-position) 14 | - [Usage](#usage) 15 | - [` 64 | 65 | 85 | ``` 86 | 87 | The dist versions will be available from services which host npm packages such as jsdelivr: 88 | 89 | * https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.min.js 90 | * https://cdn.jsdelivr.net/npm/videojs-seek-buttons/dist/videojs-seek-buttons.css 91 | 92 | ### Browserify/CommonJS 93 | 94 | When using with Browserify, install videojs-seek-buttons via npm and `require` the plugin as you would any other module. 95 | Make sure if using React to also `include "videojs-seek-buttons/dist/videojs-seek-buttons.css"`, otherwise the icons will not appear in the control bar. 96 | 97 | ```js 98 | var videojs = require('video.js'); 99 | 100 | // The actual plugin function is exported by this module, but it is also 101 | // attached to the `Player.prototype`; so, there is no need to assign it 102 | // to a variable. 103 | require('videojs-seek-buttons'); 104 | 105 | var player = videojs('my-video'); 106 | 107 | player.seekButtons({ 108 | forward: 30, 109 | back: 10 110 | }); 111 | ``` 112 | 113 | ### RequireJS/AMD 114 | 115 | When using with RequireJS (or another AMD library), get the script in whatever way you prefer and `require` the plugin as you normally would: 116 | 117 | ```js 118 | require(['video.js', 'videojs-seek-buttons'], function(videojs) { 119 | var player = videojs('my-video'); 120 | 121 | player.seekButtons({ 122 | forward: 30, 123 | back: 10 124 | }); 125 | }); 126 | ``` 127 | 128 | ## License 129 | 130 | Apache-2.0. Copyright (c) mister-ben <git@misterben.me> 131 | 132 | 133 | [videojs]: http://videojs.com/ 134 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-seek-buttons Demo 6 | 7 | 8 | 9 | 10 | 14 | 18 | 19 | 20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /lang/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "{{seconds}} Sekunden vorspulen", 3 | "Seek back {{seconds}} seconds": "{{seconds}} Sekunden zurückspulen" 4 | } 5 | -------------------------------------------------------------------------------- /lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "Seek forward {{seconds}} seconds", 3 | "Seek back {{seconds}} seconds": "Seek back {{seconds}} seconds" 4 | } -------------------------------------------------------------------------------- /lang/fa.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "{{seconds}} ثانیه بعد", 3 | "Seek back {{seconds}} seconds": "{{seconds}} ثانیه قبل" 4 | } 5 | -------------------------------------------------------------------------------- /lang/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "Avanti di {{seconds}} secondi", 3 | "Seek back {{seconds}} seconds": "Indietro di {{seconds}} secondi" 4 | } -------------------------------------------------------------------------------- /lang/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "{{seconds}}秒進む", 3 | "Seek back {{seconds}} seconds": "{{seconds}}秒戻る" 4 | } 5 | -------------------------------------------------------------------------------- /lang/lv.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "Pārtīt uz priekšu {{seconds}} sekundes", 3 | "Seek back {{seconds}} seconds": "Pārtīt atpakaļ {{seconds}} sekundes" 4 | } 5 | -------------------------------------------------------------------------------- /lang/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "{{seconds}} seconden vooruit", 3 | "Seek back {{seconds}} seconds": "{{seconds}} seconden terug" 4 | } 5 | -------------------------------------------------------------------------------- /lang/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "На {{seconds}} секунд вперед", 3 | "Seek back {{seconds}} seconds": "На {{seconds}} секунд назад" 4 | } 5 | -------------------------------------------------------------------------------- /lang/zh-CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "快进 {{seconds}} 秒", 3 | "Seek back {{seconds}} seconds": "快退 {{seconds}} 秒" 4 | } -------------------------------------------------------------------------------- /lang/zh-TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "Seek forward {{seconds}} seconds": "快轉 {{seconds}} 秒", 3 | "Seek back {{seconds}} seconds": "倒轉 {{seconds}} 秒" 4 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-seek-buttons", 3 | "repository": "https://github.com/mister-ben/videojs-seek-buttons", 4 | "issues": "https://github.com/mister-ben/videojs-seek-buttons/issues", 5 | "version": "4.0.2", 6 | "description": "Plugin for video.js to add seek buttons to the control bar", 7 | "main": "dist/videojs-seek-buttons.cjs.js", 8 | "module": "dist/videojs-seek-buttons.es.js", 9 | "generator-videojs-plugin": { 10 | "version": "8.0.0" 11 | }, 12 | "scripts": { 13 | "prebuild": "npm run clean", 14 | "build": "npm-run-all -s clean -p build:*", 15 | "build-prod": "cross-env-shell NO_TEST_BUNDLE=1 'npm run build'", 16 | "build-test": "cross-env-shell TEST_BUNDLE_ONLY=1 'npm run build'", 17 | "build:css": "postcss -o dist/videojs-seek-buttons.css --config scripts/postcss.config.js src/plugin.css", 18 | "build:js": "rollup -c scripts/rollup.config.js", 19 | "build:lang": "vjslang --dir dist/lang", 20 | "clean": "shx rm -rf ./dist ./test/dist ./cjs ./es && shx mkdir -p ./dist ./test/dist ./cjs ./es", 21 | "postclean": "shx mkdir -p ./dist ./test/dist", 22 | "docs": "npm-run-all docs:*", 23 | "docs:api": "jsdoc src -r -d docs/api", 24 | "docs:toc": "doctoc --notitle README.md", 25 | "lint": "vjsstandard", 26 | "server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch", 27 | "start": "npm-run-all -p server watch", 28 | "pretest": "npm-run-all lint build", 29 | "test": "npm-run-all lint build-test && karma start scripts/karma.conf.js", 30 | "posttest": "shx cat test/dist/coverage/text.txt", 31 | "test:unit": "karma start scripts/karma.conf.js", 32 | "test:verify": "vjsverify --skip-es-check --verbose", 33 | "update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", 34 | "preversion": "npm test", 35 | "version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md", 36 | "watch": "npm-run-all -p watch:*", 37 | "watch:css": "npm run build:css -- -w", 38 | "watch:js": "npm run build:js -- -w", 39 | "prepublishOnly": "npm-run-all build-prod && vjsverify --skip-es-check --verbose" 40 | }, 41 | "engines": { 42 | "node": ">=14", 43 | "npm": ">=6" 44 | }, 45 | "keywords": [ 46 | "videojs", 47 | "videojs-plugin" 48 | ], 49 | "author": "mister-ben ", 50 | "license": "Apache-2.0", 51 | "vjsstandard": { 52 | "ignore": [ 53 | "es", 54 | "cjs", 55 | "dist", 56 | "docs", 57 | "test/dist" 58 | ] 59 | }, 60 | "files": [ 61 | "CONTRIBUTING.md", 62 | "cjs/", 63 | "dist/", 64 | "docs/", 65 | "es/", 66 | "index.html", 67 | "scripts/", 68 | "src/", 69 | "test/" 70 | ], 71 | "husky": { 72 | "hooks": { 73 | "pre-commit": "lint-staged", 74 | "pre-push": "npm run test" 75 | } 76 | }, 77 | "lint-staged": { 78 | "*.js": "vjsstandard --fix", 79 | "README.md": "doctoc --notitle" 80 | }, 81 | "dependencies": { 82 | "global": "^4.4.0" 83 | }, 84 | "devDependencies": { 85 | "@babel/cli": "^7.13.16", 86 | "@babel/runtime": "^7.14.0", 87 | "@videojs/babel-config": "^1.0.0", 88 | "@videojs/generator-helpers": "~3.2.0", 89 | "jsdoc": "^4.0.0", 90 | "karma": "^6.3.2", 91 | "postcss": "^8.2.13", 92 | "postcss-cli": "^8.3.1", 93 | "rollup": "^2.46.0", 94 | "sinon": "^15.0.0", 95 | "video.js": "^8.3.0", 96 | "videojs-generate-karma-config": "~8.0.0", 97 | "videojs-generate-postcss-config": "~3.0.0", 98 | "videojs-generate-rollup-config": "^7.0.0", 99 | "videojs-generator-verify": "^4.1.0", 100 | "videojs-languages": "^2.0.0", 101 | "videojs-standard": "^9.0.1" 102 | }, 103 | "peerDependencies": { 104 | "video.js": "^8" 105 | }, 106 | "browser": "dist/videojs-seek-buttons.js" 107 | } 108 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/plugin.css: -------------------------------------------------------------------------------- 1 | .video-js { 2 | 3 | /* This class is added to the video.js element by the plugin by default. */ 4 | & .vjs-seek-button { 5 | cursor: pointer; 6 | 7 | &.skip-back .vjs-icon-placeholder::before { 8 | transform: rotate(-45deg); 9 | } 10 | 11 | &.skip-forward .vjs-icon-placeholder::before { 12 | transform: scale(-1, 1) rotate(-45deg); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | import {version as VERSION} from '../package.json'; 3 | 4 | const Button = videojs.getComponent('Button'); 5 | 6 | // Default options for the plugin. 7 | const defaults = { 8 | forwardIndex: 1, 9 | backIndex: 1 10 | }; 11 | 12 | /** 13 | * Set up buttons when the player is ready. 14 | * 15 | * @function onPlayerReady 16 | * @param {Player} player 17 | * A Video.js player object. 18 | * 19 | * @param {Object} [options={}] 20 | * A plain object containing options for the plugin. 21 | */ 22 | const onPlayerReady = (player, options) => { 23 | 24 | player.addClass('vjs-seek-buttons'); 25 | 26 | if (options.forward && options.forward > 0) { 27 | player.controlBar.seekForward = player.controlBar.addChild('seekButton', { 28 | direction: 'forward', 29 | seconds: options.forward 30 | }, options.forwardIndex); 31 | } 32 | 33 | if (options.back && options.back > 0) { 34 | player.controlBar.seekBack = player.controlBar.addChild('seekButton', { 35 | direction: 'back', 36 | seconds: options.back 37 | }, options.backIndex); 38 | } 39 | 40 | }; 41 | 42 | /** 43 | * Plugin init if ready or on ready 44 | * 45 | * @function seekButtons 46 | * @param {Object} [options={}] 47 | * An object of options left to the plugin author to define. 48 | */ 49 | const seekButtons = function(options) { 50 | this.ready(() => { 51 | onPlayerReady(this, videojs.obj.merge(defaults, options)); 52 | }); 53 | }; 54 | 55 | // Include the version number. 56 | seekButtons.VERSION = VERSION; 57 | 58 | /** 59 | * Button to seek forward/back 60 | * 61 | * @extends Button 62 | * @class SeekButton 63 | */ 64 | class SeekButton extends Button { 65 | /** 66 | * Constructor for class 67 | * 68 | * @param {Player|Object} player The player 69 | * @param {Object=} options Button options 70 | * @param {string} options.direction back or forward 71 | * @param {Int} options.seconds number of seconds to seek 72 | */ 73 | constructor(player, options) { 74 | super(player, options); 75 | this.$('.vjs-icon-placeholder').classList.add('vjs-icon-replay'); 76 | if (this.options_.direction === 'forward') { 77 | this.controlText(this.localize('Seek forward {{seconds}} seconds') 78 | .replace('{{seconds}}', this.options_.seconds)); 79 | } else if (this.options_.direction === 'back') { 80 | this.controlText(this.localize('Seek back {{seconds}} seconds') 81 | .replace('{{seconds}}', this.options_.seconds)); 82 | } 83 | } 84 | 85 | /** 86 | * Return button class names which include the seek amount. 87 | * 88 | * @return {string} css cass string 89 | */ 90 | buildCSSClass() { 91 | /* Each button will have the classes: 92 | `vjs-seek-button` 93 | `skip-forward` or `skip-back` 94 | `skip-n` where `n` is the number of seconds 95 | So you could have a generic icon for "skip back" and a more 96 | specific one for "skip back 30 seconds" 97 | */ 98 | return `vjs-seek-button skip-${this.options_.direction} ` + 99 | `skip-${this.options_.seconds} ${super.buildCSSClass()}`; 100 | } 101 | 102 | /** 103 | * Seek with the button's configured offset 104 | */ 105 | handleClick() { 106 | const now = this.player_.currentTime(); 107 | 108 | if (this.options_.direction === 'forward') { 109 | let duration = this.player_.duration(); 110 | 111 | if (this.player_.liveTracker && this.player_.liveTracker.isLive()) { 112 | duration = this.player_.liveTracker.seekableEnd(); 113 | } 114 | 115 | this.player_.currentTime(Math.min(now + this.options_.seconds, duration)); 116 | } else if (this.options_.direction === 'back') { 117 | this.player_.currentTime(Math.max(0, now - this.options_.seconds)); 118 | } 119 | } 120 | } 121 | videojs.registerComponent('SeekButton', SeekButton); 122 | 123 | // Register the plugin with video.js. 124 | videojs.registerPlugin('seekButtons', seekButtons); 125 | 126 | export default seekButtons; 127 | -------------------------------------------------------------------------------- /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-seek-buttons', { 19 | 20 | beforeEach() { 21 | 22 | // Mock the environment's timers because certain things - particularly 23 | // player readiness - are asynchronous in video.js 5. This MUST come 24 | // before any player is created; otherwise, timers could get created 25 | // with the actual timer methods! 26 | this.clock = sinon.useFakeTimers(); 27 | 28 | this.fixture = document.getElementById('qunit-fixture'); 29 | this.video = document.createElement('video'); 30 | this.fixture.appendChild(this.video); 31 | this.player = videojs(this.video); 32 | }, 33 | 34 | afterEach() { 35 | this.player.dispose(); 36 | this.clock.restore(); 37 | } 38 | }); 39 | 40 | QUnit.test('registers itself with video.js', function(assert) { 41 | assert.expect(2); 42 | 43 | assert.strictEqual( 44 | typeof Player.prototype.seekButtons, 45 | 'function', 46 | 'videojs-seek-buttons plugin was registered' 47 | ); 48 | 49 | this.player.seekButtons(); 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-seek-buttons'), 56 | 'the plugin adds a class to the player' 57 | ); 58 | }); 59 | 60 | QUnit.test('adds buttons with classes', function(assert) { 61 | this.player.seekButtons({ 62 | forward: 30, 63 | back: 10 64 | }); 65 | 66 | // Tick the clock forward enough to trigger the player to be "ready". 67 | this.clock.tick(1); 68 | 69 | assert.ok( 70 | this.player.controlBar.seekBack, 71 | 'the plugin adds a back button to the player' 72 | ); 73 | 74 | assert.ok( 75 | this.player.controlBar.seekForward, 76 | 'the plugin adds a forward button to the player' 77 | ); 78 | 79 | assert.ok( 80 | this.player.controlBar.seekBack.hasClass('skip-10'), 81 | 'the plugin adds a seconds class to the button' 82 | ); 83 | 84 | assert.ok( 85 | this.player.controlBar.seekBack.hasClass('skip-back'), 86 | 'the plugin adds a direction class to the button' 87 | ); 88 | }); 89 | 90 | QUnit.test('calls currentTime with the correct time', function(assert) { 91 | this.player.duration(100); 92 | 93 | this.player.seekButtons({ 94 | forward: 30, 95 | back: 10 96 | }); 97 | 98 | // Tick the clock forward enough to trigger the player to be "ready". 99 | this.clock.tick(1); 100 | 101 | const time = this.player.currentTime(); 102 | 103 | const spy = sinon.spy(this.player, 'currentTime'); 104 | 105 | this.player.controlBar.seekForward.trigger('click'); 106 | 107 | assert.ok( 108 | spy.withArgs(time + 30).calledOnce, 109 | 'forward button triggers seek 30 seconds' 110 | ); 111 | 112 | // Fake that the seek happened - it won't have as the test player has no source. 113 | this.player.tech_.currentTime = () => 30; 114 | 115 | this.player.controlBar.seekBack.trigger('click'); 116 | 117 | assert.ok( 118 | spy.withArgs(20).calledOnce, 119 | 'back button triggers seek back 10 seconds' 120 | ); 121 | 122 | }); 123 | --------------------------------------------------------------------------------