videojs-mobile-ui 0.7.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -4
- package/dist/lang/de.js +3 -0
- package/dist/lang/en.js +1 -1
- package/dist/lang/it.js +3 -0
- package/dist/videojs-mobile-ui.cjs.js +124 -190
- package/dist/videojs-mobile-ui.css +2 -2
- package/dist/videojs-mobile-ui.es.js +124 -189
- package/dist/videojs-mobile-ui.js +131 -236
- package/dist/videojs-mobile-ui.min.js +2 -2
- package/index.html +175 -102
- package/package.json +14 -11
- package/src/plugin.css +13 -1
- package/src/plugin.js +23 -41
- package/src/touchOverlay.js +46 -56
- package/CHANGELOG.md +0 -64
package/index.html
CHANGED
|
@@ -1,127 +1,200 @@
|
|
|
1
|
-
<!
|
|
1
|
+
<!DOCTYPE html>
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
|
-
<meta charset="utf-8"
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1"
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>videojs-mobile-ui Demo</title>
|
|
7
|
-
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet"
|
|
8
|
-
<link href="dist/videojs-mobile-ui.css" rel="stylesheet"
|
|
7
|
+
<link href="node_modules/video.js/dist/video-js.css" rel="stylesheet" />
|
|
8
|
+
<link href="dist/videojs-mobile-ui.css" rel="stylesheet" />
|
|
9
9
|
<style>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
.testEl {
|
|
11
|
+
width: 10%;
|
|
12
|
+
height: 10%;
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: 0;
|
|
15
|
+
pointer-events: none;
|
|
16
|
+
display: none;
|
|
17
|
+
}
|
|
18
18
|
</style>
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
|
21
|
-
<video-js
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
<video-js
|
|
22
|
+
id="videojs-mobile-ui-player"
|
|
23
|
+
class="video-js vjs-default-skin vjs-fluid"
|
|
24
|
+
controls
|
|
25
|
+
playsinline
|
|
26
|
+
>
|
|
27
|
+
<source src="https://d2zihajmogu5jn.cloudfront.net/bipbop-advanced/bipbop_16x9_variant.m3u8" type="application/x-mpegurl" />
|
|
28
|
+
</video-js>
|
|
29
|
+
<ul>
|
|
30
|
+
<li><a href="test/">Run unit tests in browser.</a></li>
|
|
31
|
+
<li><a href="docs/api/">Read generated docs.</a></li>
|
|
32
|
+
</ul>
|
|
33
|
+
<h2>Options</h2>
|
|
34
|
+
<ul id="options">
|
|
35
|
+
<li>fullscreen:</li>
|
|
25
36
|
<ul>
|
|
26
|
-
<li
|
|
27
|
-
|
|
37
|
+
<li>
|
|
38
|
+
<input
|
|
39
|
+
type="checkbox"
|
|
40
|
+
data-section="fullscreen"
|
|
41
|
+
id="enterOnRotate"
|
|
42
|
+
/>enterOnRotate
|
|
43
|
+
</li>
|
|
44
|
+
<li>
|
|
45
|
+
<input
|
|
46
|
+
type="checkbox"
|
|
47
|
+
data-section="fullscreen"
|
|
48
|
+
id="exitOnRotate"
|
|
49
|
+
/>exitOnRotate
|
|
50
|
+
</li>
|
|
51
|
+
<li>
|
|
52
|
+
<input
|
|
53
|
+
type="checkbox"
|
|
54
|
+
data-section="fullscreen"
|
|
55
|
+
id="lockOnRotate"
|
|
56
|
+
/>lockOnRotate
|
|
57
|
+
</li>
|
|
58
|
+
<li>
|
|
59
|
+
<input
|
|
60
|
+
type="checkbox"
|
|
61
|
+
data-section="fullscreen"
|
|
62
|
+
id="alwaysLockToLandscape"
|
|
63
|
+
/>alwaysLockToLandscape
|
|
64
|
+
</li>
|
|
65
|
+
<li>
|
|
66
|
+
<input
|
|
67
|
+
type="checkbox"
|
|
68
|
+
data-section="fullscreen"
|
|
69
|
+
id="fullscreenDisabled"
|
|
70
|
+
/>disabled
|
|
71
|
+
</li>
|
|
28
72
|
</ul>
|
|
29
|
-
<
|
|
30
|
-
<ul
|
|
31
|
-
<li>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
73
|
+
<li>touchControls:</li>
|
|
74
|
+
<ul>
|
|
75
|
+
<li>
|
|
76
|
+
<input
|
|
77
|
+
type="number"
|
|
78
|
+
data-section="touchControls"
|
|
79
|
+
id="seekSeconds"
|
|
80
|
+
/>seekSeconds
|
|
81
|
+
</li>
|
|
82
|
+
<li>
|
|
83
|
+
<input
|
|
84
|
+
type="number"
|
|
85
|
+
data-section="touchControls"
|
|
86
|
+
id="tapTimeout"
|
|
87
|
+
/>tapTimeout
|
|
88
|
+
</li>
|
|
89
|
+
<li>
|
|
90
|
+
<input
|
|
91
|
+
type="checkbox"
|
|
92
|
+
data-section="touchControls"
|
|
93
|
+
id="disableOnEnd"
|
|
94
|
+
/>disableOnEnd
|
|
95
|
+
</li>
|
|
96
|
+
<li>
|
|
97
|
+
<input
|
|
98
|
+
type="checkbox"
|
|
99
|
+
data-section="touchControls"
|
|
100
|
+
id="touchControlsDisabled"
|
|
101
|
+
/>disabled
|
|
102
|
+
</li>
|
|
46
103
|
</ul>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
104
|
+
</ul>
|
|
105
|
+
<button id="reload">Reload with options</button>
|
|
106
|
+
<ul id="log"></ul>
|
|
107
|
+
<script src="node_modules/video.js/dist/video.js"></script>
|
|
108
|
+
<script src="dist/videojs-mobile-ui.js"></script>
|
|
109
|
+
<script>
|
|
110
|
+
(function (window, videojs) {
|
|
111
|
+
var options = {
|
|
112
|
+
fullscreen: {
|
|
113
|
+
enterOnRotate: true,
|
|
114
|
+
exitOnRotate: true,
|
|
115
|
+
lockOnRotate: true,
|
|
116
|
+
alwaysLockToLandscape: false,
|
|
117
|
+
disabled: false,
|
|
118
|
+
},
|
|
119
|
+
touchControls: {
|
|
120
|
+
seekSeconds: 10,
|
|
121
|
+
tapTimeout: 300,
|
|
122
|
+
disableOnEnd: false,
|
|
123
|
+
disabled: false,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
68
126
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
127
|
+
var url = new URL(window.location);
|
|
128
|
+
if (url.searchParams.has('options')) {
|
|
129
|
+
options = JSON.parse(url.searchParams.get('options'));
|
|
130
|
+
}
|
|
73
131
|
|
|
74
|
-
|
|
132
|
+
console.log(JSON.stringify(options, null, 2));
|
|
75
133
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
134
|
+
Object.keys(options).forEach(function (section) {
|
|
135
|
+
Object.keys(options[section]).forEach(function (prop) {
|
|
136
|
+
const val = options[section][prop];
|
|
79
137
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
138
|
+
if (prop === 'disabled') {
|
|
139
|
+
prop = `${section}Disabled`;
|
|
140
|
+
}
|
|
83
141
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
});
|
|
142
|
+
if (typeof val === 'boolean') {
|
|
143
|
+
document.getElementById(prop).checked = val;
|
|
144
|
+
}
|
|
145
|
+
if (typeof val === 'number') {
|
|
146
|
+
document.getElementById(prop).value = val;
|
|
147
|
+
}
|
|
91
148
|
});
|
|
149
|
+
});
|
|
92
150
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
151
|
+
document
|
|
152
|
+
.getElementById('options')
|
|
153
|
+
.querySelectorAll('input')
|
|
154
|
+
.forEach(function (opt) {
|
|
155
|
+
opt.addEventListener('change', function () {
|
|
156
|
+
if (this.type === 'checkbox') {
|
|
157
|
+
const param = this.id.endsWith('Disabled')
|
|
158
|
+
? 'disabled'
|
|
159
|
+
: this.id;
|
|
97
160
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
161
|
+
options[this.getAttribute('data-section')][param] =
|
|
162
|
+
this.checked;
|
|
163
|
+
} else {
|
|
164
|
+
options[this.getAttribute('data-section')][this.id] =
|
|
165
|
+
parseFloat(this.value);
|
|
166
|
+
}
|
|
167
|
+
console.log(options);
|
|
104
168
|
});
|
|
169
|
+
});
|
|
105
170
|
|
|
106
|
-
|
|
107
|
-
|
|
171
|
+
document
|
|
172
|
+
.getElementById('reload')
|
|
173
|
+
.addEventListener('click', function () {
|
|
174
|
+
url.searchParams.set('options', JSON.stringify(options));
|
|
108
175
|
|
|
109
|
-
|
|
110
|
-
|
|
176
|
+
window.location = url.href;
|
|
177
|
+
});
|
|
111
178
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
179
|
+
window.addEventListener('orientationchange', function () {
|
|
180
|
+
var el = document.createElement('li');
|
|
181
|
+
var message =
|
|
182
|
+
new Date().toTimeString().split(' ')[0] + ' ' + window.orientation;
|
|
183
|
+
message +=
|
|
184
|
+
screen && screen.orientation
|
|
185
|
+
? ' ' + screen.orientation.type + ' ' + screen.orientation.angle
|
|
186
|
+
: '';
|
|
187
|
+
el.textContent = message;
|
|
188
|
+
console.log(message);
|
|
189
|
+
document.getElementById('log').appendChild(el);
|
|
190
|
+
});
|
|
120
191
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
192
|
+
var testPlayer = (window.testPlayer = videojs(
|
|
193
|
+
'videojs-mobile-ui-player'
|
|
194
|
+
));
|
|
195
|
+
testPlayer.endscreen = function () {};
|
|
196
|
+
testPlayer.mobileUi(options);
|
|
197
|
+
})(window, window.videojs);
|
|
198
|
+
</script>
|
|
126
199
|
</body>
|
|
127
200
|
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "videojs-mobile-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Mobile tap controls and fullscreen on rotate for Video.js",
|
|
5
5
|
"main": "dist/videojs-mobile-ui.cjs.js",
|
|
6
6
|
"module": "dist/videojs-mobile-ui.es.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"watch": "npm-run-all -p watch:*",
|
|
32
32
|
"watch:css": "npm run build:css -- -w",
|
|
33
33
|
"watch:js": "npm run build:js -- -w",
|
|
34
|
-
"prepublishOnly": "npm-run-all build-prod && vjsverify --verbose"
|
|
34
|
+
"prepublishOnly": "npm-run-all build-prod && vjsverify --verbose --skip-es-check"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": ">=14",
|
|
@@ -68,24 +68,27 @@
|
|
|
68
68
|
"README.md": "doctoc --notitle"
|
|
69
69
|
},
|
|
70
70
|
"dependencies": {
|
|
71
|
-
"global": "^4.4.0"
|
|
72
|
-
|
|
71
|
+
"global": "^4.4.0"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"video.js": "^8"
|
|
73
75
|
},
|
|
74
76
|
"devDependencies": {
|
|
75
77
|
"@babel/runtime": "^7.14.0",
|
|
76
|
-
"@videojs/generator-helpers": "~2.0
|
|
77
|
-
"
|
|
78
|
+
"@videojs/generator-helpers": "~3.2.0",
|
|
79
|
+
"husky": "^8.0.1",
|
|
80
|
+
"jsdoc": "^4.0.0",
|
|
78
81
|
"karma": "^6.3.2",
|
|
79
82
|
"postcss": "^8.2.13",
|
|
80
83
|
"postcss-cli": "^8.3.1",
|
|
81
84
|
"rollup": "^2.46.0",
|
|
82
|
-
"sinon": "^
|
|
85
|
+
"sinon": "^14.0.1",
|
|
86
|
+
"video.js": "^8.0.0",
|
|
83
87
|
"videojs-generate-karma-config": "~8.0.0",
|
|
84
88
|
"videojs-generate-postcss-config": "~3.0.0",
|
|
85
|
-
"videojs-generate-rollup-config": "
|
|
86
|
-
"videojs-generator-verify": "
|
|
89
|
+
"videojs-generate-rollup-config": "^7.0.0",
|
|
90
|
+
"videojs-generator-verify": "^4.1.0",
|
|
87
91
|
"videojs-languages": "^2.0.0",
|
|
88
|
-
"videojs-standard": "^
|
|
89
|
-
"husky": "^6.0.0"
|
|
92
|
+
"videojs-standard": "^9.0.1"
|
|
90
93
|
}
|
|
91
94
|
}
|
package/src/plugin.css
CHANGED
|
@@ -30,16 +30,28 @@
|
|
|
30
30
|
|
|
31
31
|
&.skip {
|
|
32
32
|
opacity: 0;
|
|
33
|
-
animation: fadeAndScale 0.
|
|
33
|
+
animation: fadeAndScale 0.8s linear;
|
|
34
34
|
background-repeat: no-repeat;
|
|
35
35
|
background-position: 80% center;
|
|
36
36
|
background-size: 10%;
|
|
37
37
|
background-image: url('data:image/svg+xml;utf8,<svg fill="%23FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
|
|
38
|
+
|
|
39
|
+
&:after {
|
|
40
|
+
content: attr(data-skip-text);
|
|
41
|
+
position: absolute;
|
|
42
|
+
top: 60%;
|
|
43
|
+
left: 70%;
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
&.skip.reverse {
|
|
41
48
|
background-position: 20% center;
|
|
42
49
|
background-image: url('data:image/svg+xml;utf8,<svg fill="%23FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
|
|
50
|
+
|
|
51
|
+
&:after {
|
|
52
|
+
right: 70%;
|
|
53
|
+
left: unset;
|
|
54
|
+
}
|
|
43
55
|
}
|
|
44
56
|
|
|
45
57
|
.vjs-play-control {
|
package/src/plugin.js
CHANGED
|
@@ -9,7 +9,7 @@ const defaults = {
|
|
|
9
9
|
enterOnRotate: true,
|
|
10
10
|
exitOnRotate: true,
|
|
11
11
|
lockOnRotate: true,
|
|
12
|
-
|
|
12
|
+
lockToLandscapeOnEnter: false,
|
|
13
13
|
disabled: false
|
|
14
14
|
},
|
|
15
15
|
touchControls: {
|
|
@@ -28,9 +28,9 @@ const screen = window.screen;
|
|
|
28
28
|
* @return {string} orientation
|
|
29
29
|
*/
|
|
30
30
|
const getOrientation = () => {
|
|
31
|
-
if (screen) {
|
|
31
|
+
if (window.screen) {
|
|
32
32
|
// Prefer the string over angle, as 0° can be landscape on some tablets
|
|
33
|
-
const orientationString = ((screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation || '').split('-')[0];
|
|
33
|
+
const orientationString = ((window.screen.orientation || {}).type || window.screen.mozOrientation || window.screen.msOrientation || '').split('-')[0];
|
|
34
34
|
|
|
35
35
|
if (orientationString === 'landscape' || orientationString === 'portrait') {
|
|
36
36
|
return orientationString;
|
|
@@ -48,9 +48,6 @@ const getOrientation = () => {
|
|
|
48
48
|
return 'portrait';
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
// Cross-compatibility for Video.js 5 and 6.
|
|
52
|
-
const registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
53
|
-
|
|
54
51
|
/**
|
|
55
52
|
* Add UI and event listeners
|
|
56
53
|
*
|
|
@@ -64,17 +61,6 @@ const registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
|
64
61
|
const onPlayerReady = (player, options) => {
|
|
65
62
|
player.addClass('vjs-mobile-ui');
|
|
66
63
|
|
|
67
|
-
if (options.fullscreen.iOS) {
|
|
68
|
-
videojs.log.warn('videojs-mobile-ui: `fullscreen.iOS` is deprecated. Use Video.js option `preferFullWindow` instead.');
|
|
69
|
-
if (videojs.browser.IS_IOS && videojs.browser.IOS_VERSION > 9 &&
|
|
70
|
-
!player.el_.ownerDocument.querySelector('.bc-iframe')) {
|
|
71
|
-
player.tech_.el_.setAttribute('playsinline', 'playsinline');
|
|
72
|
-
player.tech_.supportsFullScreen = function() {
|
|
73
|
-
return false;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
64
|
if (!options.touchControls.disabled) {
|
|
79
65
|
|
|
80
66
|
if (options.touchControls.disableOnEnd || typeof player.endscreen === 'function') {
|
|
@@ -82,20 +68,7 @@ const onPlayerReady = (player, options) => {
|
|
|
82
68
|
}
|
|
83
69
|
|
|
84
70
|
// Insert before the control bar
|
|
85
|
-
|
|
86
|
-
const versionParts = videojs.VERSION.split('.');
|
|
87
|
-
const major = parseInt(versionParts[0], 10);
|
|
88
|
-
const minor = parseInt(versionParts[1], 10);
|
|
89
|
-
|
|
90
|
-
// Video.js < 7.7.0 doesn't account for precedding components that don't have elements
|
|
91
|
-
if (major < 7 || (major === 7 && minor < 7)) {
|
|
92
|
-
controlBarIdx = Array.prototype.indexOf.call(
|
|
93
|
-
player.el_.children,
|
|
94
|
-
player.getChild('ControlBar').el_
|
|
95
|
-
);
|
|
96
|
-
} else {
|
|
97
|
-
controlBarIdx = player.children_.indexOf(player.getChild('ControlBar'));
|
|
98
|
-
}
|
|
71
|
+
const controlBarIdx = player.children_.indexOf(player.getChild('ControlBar'));
|
|
99
72
|
|
|
100
73
|
player.touchOverlay = player.addChild('TouchOverlay', options.touchControls, controlBarIdx);
|
|
101
74
|
}
|
|
@@ -112,7 +85,7 @@ const onPlayerReady = (player, options) => {
|
|
|
112
85
|
if (currentOrientation === 'landscape' && options.fullscreen.enterOnRotate) {
|
|
113
86
|
if (player.paused() === false) {
|
|
114
87
|
player.requestFullscreen();
|
|
115
|
-
if (options.fullscreen.lockOnRotate &&
|
|
88
|
+
if ((options.fullscreen.lockOnRotate || options.fullscreen.lockToLandscapeOnEnter) &&
|
|
116
89
|
screen.orientation && screen.orientation.lock) {
|
|
117
90
|
screen.orientation.lock('landscape').then(() => {
|
|
118
91
|
locked = true;
|
|
@@ -143,15 +116,21 @@ const onPlayerReady = (player, options) => {
|
|
|
143
116
|
screen.orientation.onchange = null;
|
|
144
117
|
});
|
|
145
118
|
}
|
|
146
|
-
|
|
147
|
-
player.on('fullscreenchange', _ => {
|
|
148
|
-
if (!player.isFullscreen() && locked) {
|
|
149
|
-
screen.orientation.unlock();
|
|
150
|
-
locked = false;
|
|
151
|
-
}
|
|
152
|
-
});
|
|
153
119
|
}
|
|
154
120
|
|
|
121
|
+
player.on('fullscreenchange', _ => {
|
|
122
|
+
if (player.isFullscreen() && options.fullscreen.lockToLandscapeOnEnter && getOrientation() === 'portrait') {
|
|
123
|
+
screen.orientation.lock('landscape').then(()=>{
|
|
124
|
+
locked = true;
|
|
125
|
+
}).catch((e) => {
|
|
126
|
+
videojs.log('Browser refused orientation lock:', e);
|
|
127
|
+
});
|
|
128
|
+
} else if (!player.isFullscreen() && locked) {
|
|
129
|
+
screen.orientation.unlock();
|
|
130
|
+
locked = false;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
155
134
|
player.on('ended', _ => {
|
|
156
135
|
if (locked === true) {
|
|
157
136
|
screen.orientation.unlock();
|
|
@@ -180,6 +159,9 @@ const onPlayerReady = (player, options) => {
|
|
|
180
159
|
* Whether to leave fullscreen when rotating to portrait (if not locked)
|
|
181
160
|
* @param {boolean} [options.fullscreen.lockOnRotate=true]
|
|
182
161
|
* Whether to lock orientation when rotating to landscape
|
|
162
|
+
* Unlocked when exiting fullscreen or on 'ended
|
|
163
|
+
* @param {boolean} [options.fullscreen.lockToLandscapeOnEnter=false]
|
|
164
|
+
* Whether to always lock orientation to landscape on fullscreen mode
|
|
183
165
|
* Unlocked when exiting fullscreen or on 'ended'
|
|
184
166
|
* @param {boolean} [options.fullscreen.iOS=false]
|
|
185
167
|
* Deprecated: Whether to disable iOS's native fullscreen so controls can work
|
|
@@ -198,13 +180,13 @@ const onPlayerReady = (player, options) => {
|
|
|
198
180
|
const mobileUi = function(options = {}) {
|
|
199
181
|
if (options.forceForTesting || videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
|
|
200
182
|
this.ready(() => {
|
|
201
|
-
onPlayerReady(this, videojs.
|
|
183
|
+
onPlayerReady(this, videojs.obj.merge(defaults, options));
|
|
202
184
|
});
|
|
203
185
|
}
|
|
204
186
|
};
|
|
205
187
|
|
|
206
188
|
// Register the plugin with video.js.
|
|
207
|
-
registerPlugin('mobileUi', mobileUi);
|
|
189
|
+
videojs.registerPlugin('mobileUi', mobileUi);
|
|
208
190
|
|
|
209
191
|
// Include the version number.
|
|
210
192
|
mobileUi.VERSION = VERSION;
|
package/src/touchOverlay.js
CHANGED
|
@@ -30,6 +30,7 @@ class TouchOverlay extends Component {
|
|
|
30
30
|
|
|
31
31
|
this.seekSeconds = options.seekSeconds;
|
|
32
32
|
this.tapTimeout = options.tapTimeout;
|
|
33
|
+
this.taps = 0;
|
|
33
34
|
|
|
34
35
|
// Add play toggle overlay
|
|
35
36
|
this.addChild('playToggle', {});
|
|
@@ -44,6 +45,46 @@ class TouchOverlay extends Component {
|
|
|
44
45
|
this.player_.options_.inactivityTimeout = 5000;
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Debounced tap handler.
|
|
50
|
+
* Seeks number of (taps - 1) * configured seconds to skip.
|
|
51
|
+
* One tap is a non-op
|
|
52
|
+
*
|
|
53
|
+
* @param {Event} event
|
|
54
|
+
*/
|
|
55
|
+
this.handleTaps_ = videojs.fn.debounce(event => {
|
|
56
|
+
const increment = (this.taps - 1) * this.seekSeconds;
|
|
57
|
+
|
|
58
|
+
this.taps = 0;
|
|
59
|
+
if (increment < 1) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const rect = this.el_.getBoundingClientRect();
|
|
64
|
+
const x = event.changedTouches[0].clientX - rect.left;
|
|
65
|
+
|
|
66
|
+
// Check if double tap is in left or right area
|
|
67
|
+
if (x < rect.width * 0.4) {
|
|
68
|
+
this.player_.currentTime(Math.max(0, this.player_.currentTime() - increment));
|
|
69
|
+
this.addClass('reverse');
|
|
70
|
+
} else if (x > rect.width - (rect.width * 0.4)) {
|
|
71
|
+
this.player_.currentTime(Math.min(this.player_.duration(), this.player_.currentTime() + increment));
|
|
72
|
+
this.removeClass('reverse');
|
|
73
|
+
} else {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Remove play toggle if showing
|
|
78
|
+
this.removeClass('show-play-toggle');
|
|
79
|
+
|
|
80
|
+
// Remove and readd class to trigger animation
|
|
81
|
+
this.setAttribute('data-skip-text', `${increment} ${this.localize('seconds')}`);
|
|
82
|
+
this.removeClass('skip');
|
|
83
|
+
window.requestAnimationFrame(() => {
|
|
84
|
+
this.addClass('skip');
|
|
85
|
+
});
|
|
86
|
+
}, this.tapTimeout);
|
|
87
|
+
|
|
47
88
|
this.enable();
|
|
48
89
|
}
|
|
49
90
|
|
|
@@ -78,63 +119,12 @@ class TouchOverlay extends Component {
|
|
|
78
119
|
|
|
79
120
|
event.preventDefault();
|
|
80
121
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
this.handleDoubleTap(event);
|
|
87
|
-
} else {
|
|
88
|
-
this.firstTapCaptured = true;
|
|
89
|
-
this.timeout = window.setTimeout(() => {
|
|
90
|
-
this.firstTapCaptured = false;
|
|
91
|
-
this.handleSingleTap(event);
|
|
92
|
-
}, this.tapTimeout);
|
|
122
|
+
this.taps += 1;
|
|
123
|
+
if (this.taps === 1) {
|
|
124
|
+
this.removeClass('skip');
|
|
125
|
+
this.toggleClass('show-play-toggle');
|
|
93
126
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Toggles display of play toggle
|
|
98
|
-
*
|
|
99
|
-
* @param {Event} event
|
|
100
|
-
* The touch event
|
|
101
|
-
*
|
|
102
|
-
*/
|
|
103
|
-
handleSingleTap(event) {
|
|
104
|
-
this.removeClass('skip');
|
|
105
|
-
this.toggleClass('show-play-toggle');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Seeks by configured number of seconds if left or right part of video double tapped
|
|
110
|
-
*
|
|
111
|
-
* @param {Event} event
|
|
112
|
-
* The touch event
|
|
113
|
-
*
|
|
114
|
-
*/
|
|
115
|
-
handleDoubleTap(event) {
|
|
116
|
-
const rect = this.el_.getBoundingClientRect();
|
|
117
|
-
const x = event.changedTouches[0].clientX - rect.left;
|
|
118
|
-
|
|
119
|
-
// Check if double tap is in left or right area
|
|
120
|
-
if (x < rect.width * 0.4) {
|
|
121
|
-
this.player_.currentTime(Math.max(0, this.player_.currentTime() - this.seekSeconds));
|
|
122
|
-
this.addClass('reverse');
|
|
123
|
-
} else if (x > rect.width - (rect.width * 0.4)) {
|
|
124
|
-
this.player_.currentTime(Math.min(this.player_.duration(), this.player_.currentTime() + this.seekSeconds));
|
|
125
|
-
this.removeClass('reverse');
|
|
126
|
-
} else {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Remove play toggle if showing
|
|
131
|
-
this.removeClass('show-play-toggle');
|
|
132
|
-
|
|
133
|
-
// Remove and readd class to trigger animation
|
|
134
|
-
this.removeClass('skip');
|
|
135
|
-
window.requestAnimationFrame(() => {
|
|
136
|
-
this.addClass('skip');
|
|
137
|
-
});
|
|
127
|
+
this.handleTaps_(event);
|
|
138
128
|
}
|
|
139
129
|
|
|
140
130
|
/**
|