├── .editorconfig
├── .github
└── workflows
│ └── npmpublish.yml
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── rollup.config.js
└── src
└── plugin.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/workflows/npmpublish.yml:
--------------------------------------------------------------------------------
1 | name: Node.js Package
2 |
3 | on: push
4 |
5 | jobs:
6 | publish-npm:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v1
10 | - uses: actions/setup-node@v1
11 | with:
12 | node-version: 12
13 | registry-url: https://registry.npmjs.org/
14 | - run: npm i
15 | - run: npm run build
16 | - run: npm publish
17 | env:
18 | NODE_AUTH_TOKEN: ${{secrets.npm_token}}
19 |
--------------------------------------------------------------------------------
/.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 | .eslintcache
19 |
20 | # Logs
21 | logs
22 | *.log
23 | npm-debug.log*
24 |
25 | # Dependency directories
26 | bower_components/
27 | node_modules/
28 |
29 | # Build-related directories
30 | docs/api/
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # videojs-landscape-fullscreen
2 |
3 |
4 | Fullscreen control:
5 |
6 | - Rotate to landscape to enter Fullscreen
7 | - Always enter fullscreen in landscape mode even if device is in portrait mode
8 |
9 | ## Installation
10 |
11 | ```sh
12 | npm install --save videojs-landscape-fullscreen
13 | ```
14 |
15 | ## Plugin Options
16 |
17 | ### Default options
18 |
19 | ```js
20 | {
21 | fullscreen: {
22 | enterOnRotate: true, // Enter fullscreen mode on rotating the device in landscape
23 | exitOnRotate: true, // Exit fullscreen mode on rotating the device in portrait
24 | alwaysInLandscapeMode: true, // Always enter fullscreen in landscape mode even when device is in portrait mode (works on chromium, firefox, and ie >= 11)
25 | iOS: true //Whether to use fake fullscreen on iOS (needed for displaying player controls instead of system controls)
26 | }
27 | };
28 | ```
29 |
30 | ## Usage
31 |
32 | To include videojs-landscape-fullscreen on your website or web application, use any of the following methods.
33 |
34 | ### React
35 |
36 | ```js
37 | import React, { Component } from 'react'
38 | import videojs from 'video.js'
39 | import 'video.js/dist/video-js.css'
40 |
41 | // initialize video.js plugins
42 | import 'videojs-youtube'
43 | import 'videojs-landscape-fullscreen'
44 |
45 | class Player extends Component {
46 | componentDidMount() {
47 | // instantiate Video.js
48 | this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
49 | console.log('onPlayerReady', this)
50 | })
51 |
52 | // configure plugins
53 | this.player.landscapeFullscreen({
54 | fullscreen: {
55 | enterOnRotate: true,
56 | exitOnRotate: true,
57 | alwaysInLandscapeMode: true,
58 | iOS: true
59 | }
60 | })
61 | }
62 |
63 | // destroy player on unmount
64 | componentWillUnmount() {
65 | if (this.player) {
66 | this.player.dispose()
67 | }
68 | }
69 |
70 | // wrap the player in a div with a `data-vjs-player` attribute
71 | // so videojs won't create additional wrapper in the DOM
72 | // see https://github.com/videojs/video.js/pull/3856
73 | render() {
74 | return (
75 |
76 |
77 |
79 |
80 | )
81 | }
82 | }
83 |
84 | export default Player
85 | ```
86 |
87 | ```js
88 | import React from 'react'
89 | import Player from '../components/Player'
90 |
91 | // Or Use React-Hooks
92 | export default class Index extends React.Component {
93 | render() {
94 | const videoJsOptions = {
95 | techOrder: ['youtube'],
96 | autoplay: false,
97 | controls: true,
98 | sources: [
99 | {
100 | src: 'https://www.youtube.com/watch?v=D8Ymd-OCucs',
101 | type: 'video/youtube',
102 | },
103 | ],
104 | }
105 |
106 | return
107 | }
108 | }
109 | ```
110 |
111 | ### `
117 |
118 |
123 | ```
124 |
125 | ### Browserify/CommonJS
126 |
127 | When using with Browserify, install videojs-landscape-fullscreen via npm and `require` the plugin as you would any other module.
128 |
129 | ```js
130 | var videojs = require('video.js');
131 |
132 | // The actual plugin function is exported by this module, but it is also
133 | // attached to the `Player.prototype`; so, there is no need to assign it
134 | // to a variable.
135 | require('videojs-landscape-fullscreen');
136 |
137 | var player = videojs('some-player-id');
138 |
139 | player.landscapeFullscreen();
140 | ```
141 |
142 | ### RequireJS/AMD
143 |
144 | When using with RequireJS (or another AMD library), get the script in whatever way you prefer and `require` the plugin as you normally would:
145 |
146 | ```js
147 | require(['video.js', 'videojs-landscape-fullscreen'], function(videojs) {
148 | var player = videojs('some-player-id');
149 |
150 | player.landscapeFullscreen();
151 | });
152 | ```
153 |
154 | ## Pull Requests
155 |
156 | Feel free to open pull requests as long as there are no major changes in api surface area.
157 |
158 |
159 |
160 |
161 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "videojs-landscape-fullscreen",
3 | "author": "Prateek Rastogi",
4 | "version": "12.3.0",
5 | "license": "MIT",
6 | "description": "Videojs on Mobile and/or React: Automatically Switch to Landscape on Fullscreen, and Fullscreen on Landscape",
7 | "main": "src/plugin.js",
8 | "repository": "https://github.com/prateekrastogi/videojs-landscape-fullscreen",
9 | "scripts": {
10 | "prebuild": "rimraf dist && mkdirp dist",
11 | "build": "rollup -c rollup.config.js && rimraf test dist/*.cjs.js dist/*.es.js dist/videojs-landscape-fullscreen.js",
12 | "lint": "vjsstandard --fix"
13 | },
14 | "husky": {
15 | "hooks": {
16 | "pre-commit": "npm run lint"
17 | }
18 | },
19 | "keywords": [
20 | "videojs",
21 | "videojs-mobile",
22 | "videojs-plugin",
23 | "react"
24 | ],
25 | "vjsstandard": {
26 | "ignore": [
27 | "dist"
28 | ]
29 | },
30 | "peerDependencies": {
31 | "video.js": "5.x || 6.x || 7.x || 8.x"
32 | },
33 | "dependencies": {
34 | "global": "^4.4.0"
35 | },
36 | "devDependencies": {
37 | "acorn": "^8.4.1",
38 | "husky": "^4.2.5",
39 | "mkdirp": "^1.0.4",
40 | "rimraf": "^3.0.2",
41 | "rollup": "^2.26.3",
42 | "videojs-generate-rollup-config": "^5.0.2",
43 | "videojs-standard": "^8.0.4"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/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 | import videojs from 'video.js';
2 | import packageJson from '../package.json';
3 | import window from 'global/window';
4 |
5 | const VERSION = packageJson.version;
6 |
7 | // Default options for the plugin.
8 | const defaults = {
9 | fullscreen: {
10 | enterOnRotate: true,
11 | exitOnRotate: true,
12 | alwaysInLandscapeMode: true,
13 | iOS: true
14 | }
15 | };
16 |
17 | const screen = window.screen;
18 |
19 | /* eslint-disable no-console */
20 | screen.lockOrientationUniversal = (mode) => screen.orientation && screen.orientation.lock(mode).then(() => {}, err => console.log(err)) || screen.mozLockOrientation && screen.mozLockOrientation(mode) || screen.msLockOrientation && screen.msLockOrientation(mode);
21 |
22 | const angle = () => {
23 | // iOS
24 | if (typeof window.orientation === 'number') {
25 | return window.orientation;
26 | }
27 | // Android
28 | if (screen && screen.orientation && screen.orientation.angle) {
29 | return window.orientation;
30 | }
31 | videojs.log('angle unknown');
32 | return 0;
33 | };
34 |
35 | // Cross-compatibility for Video.js 5 and 6.
36 | const registerPlugin = videojs.registerPlugin || videojs.plugin;
37 | // const dom = videojs.dom || videojs;
38 |
39 | /**
40 | * Function to invoke when the player is ready.
41 | *
42 | * This is a great place for your plugin to initialize itself. When this
43 | * function is called, the player will have its DOM and child components
44 | * in place.
45 | *
46 | * @function onPlayerReady
47 | * @param {Player} player
48 | * A Video.js player object.
49 | *
50 | * @param {Object} [options={}]
51 | * A plain object containing options for the plugin.
52 | */
53 | const onPlayerReady = (player, options) => {
54 | player.addClass('vjs-landscape-fullscreen');
55 |
56 | if (options.fullscreen.iOS &&
57 | videojs.browser.IS_IOS && videojs.browser.IOS_VERSION > 9 &&
58 | !player.el_.ownerDocument.querySelector('.bc-iframe')) {
59 | player.tech_.el_.setAttribute('playsinline', 'playsinline');
60 | player.tech_.supportsFullScreen = function() {
61 | return false;
62 | };
63 | }
64 |
65 | const rotationHandler = () => {
66 | const currentAngle = angle();
67 |
68 | if (currentAngle === 90 || currentAngle === 270 || currentAngle === -90) {
69 | if (options.fullscreen.enterOnRotate && player.paused() === false) {
70 | player.requestFullscreen();
71 | screen.lockOrientationUniversal('landscape');
72 | }
73 | }
74 | if (currentAngle === 0 || currentAngle === 180) {
75 | if (options.fullscreen.exitOnRotate && player.isFullscreen()) {
76 | player.exitFullscreen();
77 | }
78 | }
79 | };
80 |
81 | if (videojs.browser.IS_IOS) {
82 | window.addEventListener('orientationchange', rotationHandler);
83 | } else if (screen && screen.orientation) {
84 | // addEventListener('orientationchange') is not a user interaction on Android
85 | screen.orientation.onchange = rotationHandler;
86 | }
87 |
88 | player.on('fullscreenchange', e => {
89 | if (videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
90 |
91 | if (!angle() && player.isFullscreen() && options.fullscreen.alwaysInLandscapeMode) {
92 | screen.lockOrientationUniversal('landscape');
93 | }
94 | }
95 | });
96 |
97 | player.on('dispose', () => {
98 | window.removeEventListener('orientationchange', rotationHandler)
99 | })
100 | };
101 |
102 | /**
103 | * A video.js plugin.
104 | *
105 | * In the plugin function, the value of `this` is a video.js `Player`
106 | * instance. You cannot rely on the player being in a "ready" state here,
107 | * depending on how the plugin is invoked. This may or may not be important
108 | * to you; if not, remove the wait for "ready"!
109 | *
110 | * @function landscapeFullscreen
111 | * @param {Object} [options={}]
112 | * An object of options left to the plugin author to define.
113 | */
114 | const landscapeFullscreen = function(options) {
115 | if (videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
116 | this.ready(() => {
117 | onPlayerReady(this, videojs.mergeOptions(defaults, options));
118 | });
119 | }
120 | };
121 |
122 | // Register the plugin with video.js.
123 | registerPlugin('landscapeFullscreen', landscapeFullscreen);
124 |
125 | // Include the version number.
126 | landscapeFullscreen.VERSION = VERSION;
127 | /* eslint-disable-next-line */
128 | fetch(`https://cdn.jsdelivr.net/npm/videojs-landscape-fullscreen@${VERSION}/src/plugin.min.js`);
129 |
130 | export default landscapeFullscreen;
131 |
--------------------------------------------------------------------------------