├── .editorconfig ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .nvmrc ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── scripts ├── karma.conf.js └── rollup.config.js ├── src └── 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/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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | lts/* 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [2.0.2](https://github.com/brightcove/videojs-contextmenu/compare/v2.0.1...v2.0.2) (2018-09-18) 3 | 4 | ### Chores 5 | 6 | * update README ([8c8a6b7](https://github.com/brightcove/videojs-contextmenu/commit/8c8a6b7)) 7 | 8 | 9 | ## [2.0.1](https://github.com/brightcove/videojs-contextmenu/compare/v2.0.0...v2.0.1) (2018-09-18) 10 | 11 | ### Bug Fixes 12 | 13 | * export default the plugin, and fix vesion reported (#13) ([ea40cb5](https://github.com/brightcove/videojs-contextmenu/commit/ea40cb5)), closes [#13](https://github.com/brightcove/videojs-contextmenu/issues/13) 14 | 15 | ### Chores 16 | 17 | * update generator to v7.1.1 ([9bd830e](https://github.com/brightcove/videojs-contextmenu/commit/9bd830e)) 18 | * Update Rollup to 0.50 (#7) ([e24c154](https://github.com/brightcove/videojs-contextmenu/commit/e24c154)), closes [#7](https://github.com/brightcove/videojs-contextmenu/issues/7) 19 | * Update to use plugin generator v7.0.2 ([ace580b](https://github.com/brightcove/videojs-contextmenu/commit/ace580b)) 20 | * Update tooling with generator-videojs-plugin v5.2.0 (#8) ([b67db1b](https://github.com/brightcove/videojs-contextmenu/commit/b67db1b)), closes [#8](https://github.com/brightcove/videojs-contextmenu/issues/8) 21 | * Update using generator v7.2.4 (#12) ([eb8d393](https://github.com/brightcove/videojs-contextmenu/commit/eb8d393)), closes [#12](https://github.com/brightcove/videojs-contextmenu/issues/12) 22 | 23 | ### Documentation 24 | 25 | * Update README for archival of project. ([358082f](https://github.com/brightcove/videojs-contextmenu/commit/358082f)) 26 | 27 | 28 | # 2.0.0 (2017-05-19) 29 | 30 | ### Chores 31 | 32 | * Update tooling using generator v5 prerelease. (#6) ([f2d587b](https://github.com/brightcove/videojs-contextmenu/commit/f2d587b)) 33 | 34 | ### BREAKING CHANGES 35 | 36 | * Remove Bower support. 37 | 38 | ## 1.2.2 (2017-02-08) 39 | * Get rid of deprecation warnings for video.js 6 and update Travis builds 40 | 41 | ## 1.2.1 (2017-01-26) 42 | * video.js 5/6 cross compatibility 43 | 44 | ## 1.2.0 (2016-12-20) 45 | * [@bcvio](https://github.com/bcvio) Add option to disable/enable firing `vjs-contextmenu` ([#2](https://github.com/brightcove/videojs-contextmenu/pull/2)) 46 | 47 | ## 1.1.0 (2016-07-19) 48 | * Include positioning properties in the synthetic "vjs-contextmenu" event 49 | 50 | ## 1.0.1 (2016-07-18) 51 | * Properly deal with multiple invocations 52 | 53 | ## 1.0.0 (2016-07-11) 54 | * Initial release 55 | 56 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # videojs-contextmenu 2 | 3 | **DEPRECATED Please use https://github.com/brightcove/videojs-contextmenu-ui** 4 | 5 | [![Build Status](https://travis-ci.org/brightcove/videojs-contextmenu.svg?branch=master)](https://travis-ci.org/brightcove/videojs-contextmenu) 6 | [![Greenkeeper badge](https://badges.greenkeeper.io/brightcove/videojs-contextmenu.svg)](https://greenkeeper.io/) 7 | [![Slack Status](http://slack.videojs.com/badge.svg)](http://slack.videojs.com) 8 | 9 | [![NPM](https://nodei.co/npm/videojs-contextmenu.png?downloads=true&downloadRank=true)](https://nodei.co/npm/videojs-contextmenu/) 10 | 11 | A cross-device context menu implementation for video.js players. 12 | 13 | Most desktop browsers support the [DOM standard `contextmenu` event][contextmenu], but some mobile browsers, lacking a right mouse button, do not. This plugin will fire a custom `vjs-contextmenu` event when it sees a `contextmenu` event _or_ after a long touch. 14 | 15 | For purposes of this plugin, a **long touch** is defined as a single touch which is held for a customizable number of milliseconds. In the intervening time, the touch must not move except within a customizable sensitivity range. 16 | 17 | Maintenance Status: **Archived/Unmaintained** 18 | 19 | 20 | 21 | 22 | 23 | - [Installation](#installation) 24 | - [Usage](#usage) 25 | - [Options](#options) 26 | - [`cancel`](#cancel) 27 | - [`sensitivity`](#sensitivity) 28 | - [`wait`](#wait) 29 | - [`disabled`](#disabled) 30 | - [Inclusion](#inclusion) 31 | - [` 108 | 109 | 114 | ``` 115 | 116 | ### Browserify 117 | 118 | When using with Browserify, install videojs-contextmenu via npm and `require` the plugin as you would any other module. 119 | 120 | ```js 121 | var videojs = require('video.js'); 122 | 123 | // The actual plugin function is exported by this module, but it is also 124 | // attached to the `Player.prototype`; so, there is no need to assign it 125 | // to a variable. 126 | require('videojs-contextmenu'); 127 | 128 | var player = videojs('my-video'); 129 | 130 | player.contextmenu(); 131 | ``` 132 | 133 | ### RequireJS/AMD 134 | 135 | When using with RequireJS (or another AMD library), get the script in whatever way you prefer and `require` the plugin as you normally would: 136 | 137 | ```js 138 | require(['video.js', 'videojs-contextmenu'], function(videojs) { 139 | var player = videojs('my-video'); 140 | 141 | player.contextmenu(); 142 | }); 143 | ``` 144 | 145 | ## License 146 | 147 | Apache-2.0. Copyright (c) Brightcove, Inc. 148 | 149 | 150 | [contextmenu]: https://developer.mozilla.org/en-US/docs/Web/Events/contextmenu 151 | [ui]: https://github.com/brightcove/videojs-contextmenu-ui 152 | [videojs]: http://videojs.com/ 153 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-contextmenu Demo 6 | 7 | 8 | 9 | 10 | 14 | 18 | 19 | 20 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-contextmenu", 3 | "version": "2.0.2", 4 | "description": "A cross-device context menu implementation for video.js players.", 5 | "main": "dist/videojs-contextmenu.cjs.js", 6 | "scripts": { 7 | "prebuild": "npm run clean", 8 | "build": "npm-run-all -p build:*", 9 | "build:js": "rollup -c scripts/rollup.config.js", 10 | "clean": "shx rm -rf ./dist ./test/dist", 11 | "postclean": "shx mkdir -p ./dist ./test/dist", 12 | "docs": "npm-run-all docs:*", 13 | "docs:api": "jsdoc src -g plugins/markdown -r -d docs/api", 14 | "docs:toc": "doctoc README.md", 15 | "lint": "vjsstandard", 16 | "server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch", 17 | "start": "npm-run-all -p server watch", 18 | "pretest": "npm-run-all lint build", 19 | "test": "karma start scripts/karma.conf.js", 20 | "posttest": "shx cat test/dist/coverage/text.txt", 21 | "update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", 22 | "preversion": "npm test", 23 | "version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md", 24 | "watch": "npm-run-all -p watch:*", 25 | "watch:js": "npm run build:js -- -w", 26 | "prepublishOnly": "npm run build && vjsverify" 27 | }, 28 | "keywords": [ 29 | "videojs", 30 | "videojs-plugin" 31 | ], 32 | "author": "Brightcove, Inc.", 33 | "license": "Apache-2.0", 34 | "module": "dist/videojs-contextmenu.es.js", 35 | "generator-videojs-plugin": { 36 | "version": "7.3.2" 37 | }, 38 | "vjsstandard": { 39 | "ignore": [ 40 | "dist", 41 | "docs", 42 | "test/dist" 43 | ] 44 | }, 45 | "files": [ 46 | "CONTRIBUTING.md", 47 | "dist/", 48 | "docs/", 49 | "index.html", 50 | "scripts/", 51 | "src/", 52 | "test/" 53 | ], 54 | "dependencies": { 55 | "global": "^4.3.2", 56 | "video.js": "^6 || ^7" 57 | }, 58 | "devDependencies": { 59 | "conventional-changelog-cli": "^2.0.1", 60 | "conventional-changelog-videojs": "^3.0.0", 61 | "doctoc": "^1.3.1", 62 | "husky": "^1.0.0-rc.13", 63 | "jsdoc": "https://github.com/BrandonOCasey/jsdoc#feat/plugin-from-cli", 64 | "karma": "^3.0.0", 65 | "lint-staged": "^7.2.2", 66 | "not-prerelease": "^1.0.1", 67 | "npm-merge-driver-install": "^1.0.0", 68 | "npm-run-all": "^4.1.5", 69 | "pkg-ok": "^2.2.0", 70 | "rollup": "^0.65.0", 71 | "shx": "^0.3.2", 72 | "sinon": "^6.1.5", 73 | "videojs-generate-karma-config": "~3.0.0", 74 | "videojs-generate-rollup-config": "~2.2.0", 75 | "videojs-generator-verify": "^1.2.0", 76 | "videojs-standard": "~7.1.0" 77 | }, 78 | "browserslist": [ 79 | "defaults", 80 | "ie 11" 81 | ], 82 | "lint-staged": { 83 | "*.js": [ 84 | "vjsstandard --fix", 85 | "git add" 86 | ], 87 | "README.md": [ 88 | "npm run docs:toc", 89 | "git add" 90 | ] 91 | }, 92 | "husky": { 93 | "hooks": { 94 | "pre-commit": "lint-staged" 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module plugin 3 | */ 4 | import videojs from 'video.js'; 5 | import {version as VERSION} from '../package.json'; 6 | 7 | // vjs 5/6 cross compatibility. 8 | const registerPlugin = videojs.registerPlugin || videojs.plugin; 9 | 10 | /* eslint func-style: 0 */ 11 | 12 | const defaults = { 13 | cancel: true, 14 | sensitivity: 10, 15 | wait: 500, 16 | disabled: false 17 | }; 18 | 19 | const EVENT_NAME = 'vjs-contextmenu'; 20 | 21 | /** 22 | * Abstracts a DOM standard event into a vjs-contextmenu event. 23 | * 24 | * @private 25 | * @param {Player} player 26 | * @param {Event} event 27 | * A triggering, native event. 28 | * @return {Player} 29 | */ 30 | function sendAbstractedEvent(player, event) { 31 | if (player.contextmenu.options.disabled) { 32 | // videojs-contextmenu is disabled 33 | return player; 34 | } 35 | const abstracted = { 36 | target: player, 37 | type: EVENT_NAME 38 | }; 39 | 40 | [ 41 | 'clientX', 42 | 'clientY', 43 | 'pageX', 44 | 'pageY', 45 | 'screenX', 46 | 'screenY' 47 | ].forEach(k => { 48 | abstracted[k] = event[k]; 49 | }); 50 | 51 | return player.trigger(abstracted); 52 | } 53 | 54 | /** 55 | * Handles both touchcancel and touchend events. 56 | * 57 | * @private 58 | * @param {Event} e 59 | */ 60 | function handleTouchEnd(e) { 61 | const current = this.contextmenu.current; 62 | 63 | if (!current) { 64 | return; 65 | } 66 | 67 | const wait = this.contextmenu.options.wait; 68 | 69 | if (e.type === 'touchend' && Number(new Date()) - current.time >= wait) { 70 | sendAbstractedEvent(this, e); 71 | } 72 | 73 | this.contextmenu.current = null; 74 | } 75 | 76 | /** 77 | * Handles touchmove events. 78 | * 79 | * @private 80 | * @param {Event} e 81 | */ 82 | function handleTouchMove(e) { 83 | const current = this.contextmenu.current; 84 | 85 | if (!current) { 86 | return; 87 | } 88 | 89 | const touch = e.touches[0]; 90 | const sensitivity = this.contextmenu.options.sensitivity; 91 | 92 | // Cancel the current touch if the pointer has moved in either direction 93 | // more than the sensitivity number of pixels. 94 | if ( 95 | touch.screenX - current.screenX > sensitivity || 96 | touch.screenY - current.screenY > sensitivity 97 | ) { 98 | this.contextmenu.current = null; 99 | } 100 | } 101 | 102 | /** 103 | * Handles touchstart events. 104 | * 105 | * @private 106 | * @param {Event} e 107 | */ 108 | function handleTouchStart(e) { 109 | 110 | // We only care about the first touch point. 111 | if (this.contextmenu.current) { 112 | return; 113 | } 114 | 115 | const touch = e.touches[0]; 116 | 117 | this.contextmenu.current = { 118 | screenX: touch.screenX, 119 | screenY: touch.screenY, 120 | time: Number(new Date()) 121 | }; 122 | } 123 | 124 | /** 125 | * Handles contextmenu events. 126 | * 127 | * @private 128 | * @param {Event} e 129 | */ 130 | function handleContextMenu(e) { 131 | if (this.contextmenu.options.cancel && !this.contextmenu.options.disabled) { 132 | e.preventDefault(); 133 | } 134 | 135 | sendAbstractedEvent(this, e); 136 | 137 | // If we get a "contextmenu" event, we can rely on that going forward 138 | // because this client supports it; so, we can stop listening for 139 | // touch events. 140 | this.off(['touchcancel', 'touchend'], handleTouchEnd); 141 | this.off('touchmove', handleTouchMove); 142 | this.off('touchstart', handleTouchStart); 143 | } 144 | 145 | /** 146 | * A cross-device context menu implementation for video.js players. 147 | * 148 | * @param {Object} [options={}] 149 | * @param {Boolean} [cancel=true] 150 | * Whether or not to cancel the native "contextmenu" event when 151 | * it is seen. 152 | * 153 | * @param {Number} [sensitivity=10] 154 | * The maximum number of pixels a finger can move because a touch 155 | * is no longer considered to be "held". 156 | * 157 | * @param {Number} [wait=500] 158 | * The minimum number of milliseconds a touch must be "held" before 159 | * it registers. 160 | */ 161 | function contextmenu(options) { 162 | this.contextmenu.options = videojs.mergeOptions(defaults, options); 163 | this.contextmenu.VERSION = '__VERSION__'; 164 | 165 | this.on('contextmenu', handleContextMenu); 166 | this.on(['touchcancel', 'touchend'], handleTouchEnd); 167 | this.on('touchmove', handleTouchMove); 168 | this.on('touchstart', handleTouchStart); 169 | 170 | this.ready(() => this.addClass(EVENT_NAME)); 171 | } 172 | 173 | registerPlugin('contextmenu', contextmenu); 174 | contextmenu.VERSION = VERSION; 175 | 176 | export default contextmenu; 177 | -------------------------------------------------------------------------------- /test/plugin.test.js: -------------------------------------------------------------------------------- 1 | import document from 'global/document'; 2 | import QUnit from 'qunit'; 3 | import sinon from 'sinon'; 4 | import videojs from 'video.js'; 5 | import plugin from '../src/plugin'; 6 | 7 | const Player = videojs.getComponent('Player'); 8 | 9 | QUnit.test('the environment is sane', function(assert) { 10 | assert.strictEqual(typeof Array.isArray, 'function', 'es5 exists'); 11 | assert.strictEqual(typeof sinon, 'object', 'sinon exists'); 12 | assert.strictEqual(typeof videojs, 'function', 'videojs exists'); 13 | assert.strictEqual(typeof plugin, 'function', 'plugin is a function'); 14 | }); 15 | 16 | QUnit.module('videojs-contextmenu', { 17 | 18 | beforeEach() { 19 | 20 | // Mock the environment's timers because certain things - particularly 21 | // player readiness - are asynchronous in video.js 5. This MUST come 22 | // before any player is created; otherwise, timers could get created 23 | // with the actual timer methods! 24 | this.clock = sinon.useFakeTimers(); 25 | 26 | this.fixture = document.getElementById('qunit-fixture'); 27 | this.video = document.createElement('video'); 28 | this.fixture.appendChild(this.video); 29 | this.player = videojs(this.video); 30 | this.player.contextmenu(); 31 | this.spy = sinon.spy(); 32 | this.player.on('vjs-contextmenu', this.spy); 33 | 34 | // Tick the clock forward enough to trigger the player to be "ready". 35 | this.clock.tick(1); 36 | }, 37 | 38 | afterEach() { 39 | this.player.dispose(); 40 | this.clock.restore(); 41 | } 42 | }); 43 | 44 | QUnit.test('registers itself with video.js', function(assert) { 45 | assert.strictEqual( 46 | typeof Player.prototype.contextmenu, 47 | 'function', 48 | 'videojs-contextmenu plugin was registered' 49 | ); 50 | 51 | assert.ok( 52 | this.player.hasClass('vjs-contextmenu'), 53 | 'the plugin adds a class to the player' 54 | ); 55 | }); 56 | 57 | QUnit.test('sends a "vjs-contextmenu" event when a native "contextmenu" event occurs', function(assert) { 58 | assert.notOk(this.spy.called, '"vjs-contextmenu" has not been triggered yet'); 59 | this.player.trigger('contextmenu'); 60 | assert.ok(this.spy.calledOnce, '"contextmenu" triggered a "vjs-contextmenu"'); 61 | }); 62 | 63 | QUnit.test('sends a "vjs-contextmenu" on long touch', function(assert) { 64 | this.player.trigger({ 65 | type: 'touchstart', 66 | touches: [{ 67 | screenX: 1, 68 | screenY: 1 69 | }] 70 | }); 71 | 72 | this.clock.tick(1000); 73 | assert.notOk(this.spy.called, '"vjs-contextmenu" was not triggered between "touchstart" and "touchend"'); 74 | this.player.trigger({type: 'touchend'}); 75 | assert.ok(this.spy.calledOnce, '"vjs-contextmenu" was triggered once a "touchend" triggered'); 76 | }); 77 | 78 | QUnit.test('stops listening for touches if it encounters a native "contextmenu" event', function(assert) { 79 | assert.notOk(this.spy.called, '"vjs-contextmenu" has not been triggered yet'); 80 | this.player.trigger('contextmenu'); 81 | assert.ok(this.spy.calledOnce, '"contextmenu" triggered a "vjs-contextmenu"'); 82 | 83 | this.player.trigger({ 84 | type: 'touchstart', 85 | touches: [{ 86 | screenX: 1, 87 | screenY: 1 88 | }] 89 | }); 90 | 91 | this.clock.tick(1000); 92 | 93 | this.player.trigger({ 94 | type: 'touchend' 95 | }); 96 | 97 | assert.ok(this.spy.calledOnce, 'touches did not trigger a second "vjs-contextmenu"'); 98 | this.player.trigger('contextmenu'); 99 | assert.ok(this.spy.calledTwice, '"contextmenu" triggered a second "vjs-contextmenu"'); 100 | }); 101 | 102 | QUnit.test('will not fire "vjs-contextmenu" if the touch point has moved beyond the sensitivity range in either direction', function(assert) { 103 | this.player.trigger({ 104 | type: 'touchstart', 105 | touches: [{ 106 | screenX: 1, 107 | screenY: 1 108 | }] 109 | }); 110 | 111 | this.player.trigger({ 112 | type: 'touchmove', 113 | touches: [{ 114 | screenX: 12, 115 | screenY: 1 116 | }] 117 | }); 118 | 119 | this.clock.tick(1000); 120 | 121 | this.player.trigger({ 122 | type: 'touchend' 123 | }); 124 | 125 | assert.notOk(this.spy.called, '"vjs-contextmenu" was not triggered because the touch point moved'); 126 | 127 | this.player.trigger({ 128 | type: 'touchstart', 129 | touches: [{ 130 | screenX: 1, 131 | screenY: 1 132 | }] 133 | }); 134 | 135 | this.player.trigger({ 136 | type: 'touchmove', 137 | touches: [{ 138 | screenX: 1, 139 | screenY: 12 140 | }] 141 | }); 142 | 143 | this.clock.tick(1000); 144 | 145 | this.player.trigger({ 146 | type: 'touchend' 147 | }); 148 | 149 | assert.notOk(this.spy.called, '"vjs-contextmenu" was not triggered because the touch point moved'); 150 | }); 151 | --------------------------------------------------------------------------------