videojs-mobile-ui 0.7.0 → 0.9.0-beta.3
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 +114 -46
- package/dist/videojs-mobile-ui.cjs.js +275 -223
- package/dist/videojs-mobile-ui.css +2 -2
- package/dist/videojs-mobile-ui.es.js +270 -217
- package/dist/videojs-mobile-ui.js +278 -265
- package/dist/videojs-mobile-ui.min.js +2 -2
- package/docs/api/TouchOverlay.html +964 -0
- package/docs/api/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/docs/api/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/docs/api/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/docs/api/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-Light-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/docs/api/fonts/OpenSans-Light-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/docs/api/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/docs/api/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/docs/api/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/docs/api/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/docs/api/global.html +957 -0
- package/docs/api/index.html +159 -0
- package/docs/api/plugin.js.html +221 -0
- package/docs/api/scripts/linenumber.js +25 -0
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/api/scripts/prettify/lang-css.js +2 -0
- package/docs/api/scripts/prettify/prettify.js +28 -0
- package/docs/api/styles/jsdoc-default.css +358 -0
- package/docs/api/styles/prettify-jsdoc.css +111 -0
- package/docs/api/styles/prettify-tomorrow.css +132 -0
- package/docs/api/swipeFullscreen.js.html +173 -0
- package/docs/api/touchOverlay.js.html +211 -0
- package/index.html +206 -65
- package/package.json +19 -16
- package/src/plugin.css +21 -3
- package/src/plugin.js +32 -59
- package/src/swipeFullscreen.js +117 -0
- package/src/touchOverlay.js +62 -56
- package/test/plugin.test.js +128 -20
- package/test/swipeFullscreen.test.js +365 -0
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
/*! @name videojs-mobile-ui @version 0.
|
|
1
|
+
/*! @name videojs-mobile-ui @version 0.9.0-beta.3 @license MIT */
|
|
2
2
|
import videojs from 'video.js';
|
|
3
|
-
import _inheritsLoose from '@babel/runtime/helpers/inheritsLoose';
|
|
4
3
|
import window from 'global/window';
|
|
5
4
|
|
|
6
|
-
var version = "0.
|
|
5
|
+
var version = "0.9.0-beta.3";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @file touchOverlay.js
|
|
9
|
+
* Touch UI component
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** @import Player from 'video.js/dist/types/player' */
|
|
13
|
+
|
|
14
|
+
const Component = videojs.getComponent('Component');
|
|
15
|
+
const dom = videojs.dom || videojs;
|
|
16
|
+
const debounce = (callback, wait) => {
|
|
17
|
+
let timeoutId = null;
|
|
18
|
+
return (...args) => {
|
|
19
|
+
window.clearTimeout(timeoutId);
|
|
20
|
+
timeoutId = window.setTimeout(() => {
|
|
21
|
+
callback.apply(null, args);
|
|
22
|
+
}, wait);
|
|
23
|
+
};
|
|
24
|
+
};
|
|
7
25
|
|
|
8
|
-
var Component = videojs.getComponent('Component');
|
|
9
|
-
var dom = videojs.dom || videojs;
|
|
10
26
|
/**
|
|
11
27
|
* The `TouchOverlay` is an overlay to capture tap events.
|
|
12
28
|
*
|
|
13
29
|
* @extends Component
|
|
14
30
|
*/
|
|
15
|
-
|
|
16
|
-
var TouchOverlay = /*#__PURE__*/function (_Component) {
|
|
17
|
-
_inheritsLoose(TouchOverlay, _Component);
|
|
18
|
-
|
|
31
|
+
class TouchOverlay extends Component {
|
|
19
32
|
/**
|
|
20
33
|
* Creates an instance of the this class.
|
|
21
34
|
*
|
|
@@ -25,46 +38,80 @@ var TouchOverlay = /*#__PURE__*/function (_Component) {
|
|
|
25
38
|
* @param {Object} [options]
|
|
26
39
|
* The key/value store of player options.
|
|
27
40
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
player.on(['playing', 'userinactive'],
|
|
39
|
-
|
|
40
|
-
});
|
|
41
|
+
constructor(player, options) {
|
|
42
|
+
super(player, options);
|
|
43
|
+
this.seekSeconds = options.seekSeconds;
|
|
44
|
+
this.tapTimeout = options.tapTimeout;
|
|
45
|
+
this.taps = 0;
|
|
46
|
+
|
|
47
|
+
// Add play toggle overlay
|
|
48
|
+
this.addChild('playToggle', {});
|
|
49
|
+
|
|
50
|
+
// Clear overlay when playback starts or with control fade
|
|
51
|
+
player.on(['playing', 'userinactive'], e => {
|
|
52
|
+
this.removeClass('show-play-toggle');
|
|
53
|
+
});
|
|
41
54
|
|
|
42
|
-
|
|
43
|
-
|
|
55
|
+
// A 0 inactivity timeout won't work here
|
|
56
|
+
if (this.player_.options_.inactivityTimeout === 0) {
|
|
57
|
+
this.player_.options_.inactivityTimeout = 5000;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Debounced tap handler.
|
|
62
|
+
* Seeks number of (taps - 1) * configured seconds to skip.
|
|
63
|
+
* One tap is a non-op
|
|
64
|
+
*
|
|
65
|
+
* @param {Event} event
|
|
66
|
+
*/
|
|
67
|
+
this.handleTaps_ = debounce(event => {
|
|
68
|
+
const increment = (this.taps - 1) * this.seekSeconds;
|
|
69
|
+
this.taps = 0;
|
|
70
|
+
if (increment < 1) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const rect = this.el_.getBoundingClientRect();
|
|
74
|
+
const x = event.changedTouches[0].clientX - rect.left;
|
|
75
|
+
|
|
76
|
+
// Check if double tap is in left or right area
|
|
77
|
+
if (x < rect.width * 0.4) {
|
|
78
|
+
this.player_.currentTime(Math.max(0, this.player_.currentTime() - increment));
|
|
79
|
+
this.addClass('reverse');
|
|
80
|
+
} else if (x > rect.width - rect.width * 0.4) {
|
|
81
|
+
this.player_.currentTime(Math.min(this.player_.duration(), this.player_.currentTime() + increment));
|
|
82
|
+
this.removeClass('reverse');
|
|
83
|
+
} else {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Remove play toggle if showing
|
|
88
|
+
this.removeClass('show-play-toggle');
|
|
47
89
|
|
|
48
|
-
|
|
90
|
+
// Remove and readd class to trigger animation
|
|
91
|
+
this.setAttribute('data-skip-text', `${increment} ${this.localize('seconds')}`);
|
|
92
|
+
this.removeClass('skip');
|
|
93
|
+
window.requestAnimationFrame(() => {
|
|
94
|
+
this.addClass('skip');
|
|
95
|
+
});
|
|
96
|
+
}, this.tapTimeout);
|
|
97
|
+
this.enable();
|
|
49
98
|
}
|
|
99
|
+
|
|
50
100
|
/**
|
|
51
101
|
* Builds the DOM element.
|
|
52
102
|
*
|
|
53
103
|
* @return {Element}
|
|
54
104
|
* The DOM element.
|
|
55
105
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
var _proto = TouchOverlay.prototype;
|
|
59
|
-
|
|
60
|
-
_proto.createEl = function createEl() {
|
|
61
|
-
var el = dom.createEl('div', {
|
|
106
|
+
createEl() {
|
|
107
|
+
const el = dom.createEl('div', {
|
|
62
108
|
className: 'vjs-touch-overlay',
|
|
63
109
|
// Touch overlay is not tabbable.
|
|
64
110
|
tabIndex: -1
|
|
65
111
|
});
|
|
66
112
|
return el;
|
|
67
113
|
}
|
|
114
|
+
|
|
68
115
|
/**
|
|
69
116
|
* Debounces to either handle a delayed single tap, or a double tap
|
|
70
117
|
*
|
|
@@ -72,110 +119,166 @@ var TouchOverlay = /*#__PURE__*/function (_Component) {
|
|
|
72
119
|
* The touch event
|
|
73
120
|
*
|
|
74
121
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
_proto.handleTap = function handleTap(event) {
|
|
78
|
-
var _this2 = this;
|
|
79
|
-
|
|
122
|
+
handleTap(event) {
|
|
80
123
|
// Don't handle taps on the play button
|
|
81
124
|
if (event.target !== this.el_) {
|
|
82
125
|
return;
|
|
83
126
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
window.clearTimeout(this.timeout);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
this.handleDoubleTap(event);
|
|
95
|
-
} else {
|
|
96
|
-
this.firstTapCaptured = true;
|
|
97
|
-
this.timeout = window.setTimeout(function () {
|
|
98
|
-
_this2.firstTapCaptured = false;
|
|
99
|
-
|
|
100
|
-
_this2.handleSingleTap(event);
|
|
101
|
-
}, this.tapTimeout);
|
|
127
|
+
if (event.cancelable) {
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
}
|
|
130
|
+
this.taps += 1;
|
|
131
|
+
if (this.taps === 1) {
|
|
132
|
+
this.removeClass('skip');
|
|
133
|
+
this.toggleClass('show-play-toggle');
|
|
102
134
|
}
|
|
135
|
+
this.handleTaps_(event);
|
|
103
136
|
}
|
|
137
|
+
|
|
104
138
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* @param {Event} event
|
|
108
|
-
* The touch event
|
|
109
|
-
*
|
|
139
|
+
* Enables touch handler
|
|
110
140
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
this.removeClass('skip');
|
|
115
|
-
this.toggleClass('show-play-toggle');
|
|
141
|
+
enable() {
|
|
142
|
+
this.firstTapCaptured = false;
|
|
143
|
+
this.on('touchend', this.handleTap);
|
|
116
144
|
}
|
|
145
|
+
|
|
117
146
|
/**
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
* @param {Event} event
|
|
121
|
-
* The touch event
|
|
122
|
-
*
|
|
147
|
+
* Disables touch handler
|
|
123
148
|
*/
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
149
|
+
disable() {
|
|
150
|
+
this.off('touchend', this.handleTap);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
Component.registerComponent('TouchOverlay', TouchOverlay);
|
|
128
154
|
|
|
129
|
-
|
|
130
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Sets up swiping to enter and exit fullscreen.
|
|
157
|
+
*
|
|
158
|
+
* @param {Object} player
|
|
159
|
+
* The player to initialise on.
|
|
160
|
+
* @param {Object} pluginOptions
|
|
161
|
+
* The options used by the mobile ui plugin.
|
|
162
|
+
*/
|
|
163
|
+
const initSwipe = (player, pluginOptions) => {
|
|
164
|
+
const {
|
|
165
|
+
swipeToFullscreen,
|
|
166
|
+
swipeFromFullscreen
|
|
167
|
+
} = pluginOptions.fullscreen;
|
|
168
|
+
if (swipeToFullscreen) {
|
|
169
|
+
player.addClass('using-fs-swipe-up');
|
|
170
|
+
}
|
|
171
|
+
if (swipeFromFullscreen) {
|
|
172
|
+
player.addClass('using-fs-swipe-down');
|
|
173
|
+
}
|
|
174
|
+
let touchStartY = 0;
|
|
175
|
+
let couldBeSwiping = false;
|
|
176
|
+
const swipeThreshold = 30;
|
|
131
177
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Monitor the possible start of a swipe
|
|
180
|
+
*
|
|
181
|
+
* @param {TouchEvent} e Triggering touch event
|
|
182
|
+
*/
|
|
183
|
+
const onStart = e => {
|
|
184
|
+
const isFullscreen = player.isFullscreen();
|
|
185
|
+
if (!isFullscreen && !swipeToFullscreen || isFullscreen && !swipeFromFullscreen) {
|
|
186
|
+
couldBeSwiping = false;
|
|
139
187
|
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
188
|
+
}
|
|
189
|
+
touchStartY = e.changedTouches[0].clientY;
|
|
190
|
+
couldBeSwiping = true;
|
|
191
|
+
player.tech_.el().style.transition = '';
|
|
192
|
+
};
|
|
144
193
|
|
|
145
|
-
this.removeClass('skip');
|
|
146
|
-
window.requestAnimationFrame(function () {
|
|
147
|
-
_this3.addClass('skip');
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
194
|
/**
|
|
151
|
-
*
|
|
195
|
+
* Monitor the movement of a swipe
|
|
196
|
+
*
|
|
197
|
+
* @param {TouchEvent} e Triggering touch event
|
|
152
198
|
*/
|
|
153
|
-
|
|
199
|
+
const onMove = e => {
|
|
200
|
+
if (!couldBeSwiping) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const currentY = e.touches[0].clientY;
|
|
204
|
+
const deltaY = touchStartY - currentY;
|
|
205
|
+
const isFullscreen = player.isFullscreen();
|
|
206
|
+
let scale = 1;
|
|
207
|
+
if (!isFullscreen && deltaY > 0) {
|
|
208
|
+
// Swiping up to enter fullscreen: Zoom in (Max 1.1)
|
|
209
|
+
scale = 1 + Math.min(0.1, deltaY / 500);
|
|
210
|
+
player.tech_.el().style.transform = `scale(${scale})`;
|
|
211
|
+
} else if (isFullscreen && deltaY < 0) {
|
|
212
|
+
// Swiping down to exit fullscreen: Zoom out (Min 0.9)
|
|
213
|
+
scale = 1 - Math.min(0.1, Math.abs(deltaY) / 500);
|
|
214
|
+
player.tech_.el().style.transform = `scale(${scale})`;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
154
217
|
|
|
155
|
-
_proto.enable = function enable() {
|
|
156
|
-
this.firstTapCaptured = false;
|
|
157
|
-
this.on('touchend', this.handleTap);
|
|
158
|
-
}
|
|
159
218
|
/**
|
|
160
|
-
*
|
|
219
|
+
* Monitor the touch end to determine a valid swipe
|
|
220
|
+
*
|
|
221
|
+
* @param {TouchEvent} e Triggering touch event
|
|
161
222
|
*/
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
223
|
+
const onEnd = e => {
|
|
224
|
+
if (!couldBeSwiping) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
couldBeSwiping = false;
|
|
228
|
+
player.tech_.el().style.transition = 'transform 0.3s ease-out';
|
|
229
|
+
player.tech_.el().style.transform = 'scale(1)';
|
|
230
|
+
if (e.type === 'touchcancel') {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const touchEndY = e.changedTouches[0].clientY;
|
|
234
|
+
const deltaY = touchStartY - touchEndY;
|
|
235
|
+
if (deltaY > swipeThreshold && !player.isFullscreen()) {
|
|
236
|
+
player.requestFullscreen().catch(err => {
|
|
237
|
+
player.log.warn('Browser refused fullscreen', err);
|
|
238
|
+
});
|
|
239
|
+
} else if (deltaY < -swipeThreshold && player.isFullscreen()) {
|
|
240
|
+
player.exitFullscreen();
|
|
241
|
+
}
|
|
166
242
|
};
|
|
243
|
+
player.el().addEventListener('touchstart', onStart, {
|
|
244
|
+
passive: true
|
|
245
|
+
});
|
|
246
|
+
player.el().addEventListener('touchmove', onMove, {
|
|
247
|
+
passive: true
|
|
248
|
+
});
|
|
249
|
+
player.el().addEventListener('touchend', onEnd, {
|
|
250
|
+
passive: true
|
|
251
|
+
});
|
|
252
|
+
player.el().addEventListener('touchcancel', onEnd, {
|
|
253
|
+
passive: true
|
|
254
|
+
});
|
|
255
|
+
player.on('dispose', () => {
|
|
256
|
+
player.el().removeEventListener('touchstart', onStart, {
|
|
257
|
+
passive: true
|
|
258
|
+
});
|
|
259
|
+
player.el().removeEventListener('touchmove', onMove, {
|
|
260
|
+
passive: true
|
|
261
|
+
});
|
|
262
|
+
player.el().removeEventListener('touchend', onEnd, {
|
|
263
|
+
passive: true
|
|
264
|
+
});
|
|
265
|
+
player.el().removeEventListener('touchcancel', onEnd, {
|
|
266
|
+
passive: true
|
|
267
|
+
});
|
|
268
|
+
player.tech_.el().style.transform = '';
|
|
269
|
+
player.tech_.el().style.transition = '';
|
|
270
|
+
});
|
|
271
|
+
};
|
|
167
272
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Component.registerComponent('TouchOverlay', TouchOverlay);
|
|
172
|
-
|
|
173
|
-
var defaults = {
|
|
273
|
+
// Default options for the plugin.
|
|
274
|
+
const defaults = {
|
|
174
275
|
fullscreen: {
|
|
175
276
|
enterOnRotate: true,
|
|
176
277
|
exitOnRotate: true,
|
|
177
278
|
lockOnRotate: true,
|
|
178
|
-
|
|
279
|
+
lockToLandscapeOnEnter: false,
|
|
280
|
+
swipeToFullscreen: false,
|
|
281
|
+
swipeFromFullscreen: false,
|
|
179
282
|
disabled: false
|
|
180
283
|
},
|
|
181
284
|
touchControls: {
|
|
@@ -185,37 +288,33 @@ var defaults = {
|
|
|
185
288
|
disabled: false
|
|
186
289
|
}
|
|
187
290
|
};
|
|
188
|
-
|
|
291
|
+
const screen = window.screen;
|
|
292
|
+
const registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
293
|
+
|
|
189
294
|
/**
|
|
190
295
|
* Gets 'portrait' or 'lanscape' from the two orientation APIs
|
|
191
296
|
*
|
|
192
297
|
* @return {string} orientation
|
|
193
298
|
*/
|
|
194
|
-
|
|
195
|
-
var getOrientation = function getOrientation() {
|
|
299
|
+
const getOrientation = () => {
|
|
196
300
|
if (screen) {
|
|
197
301
|
// Prefer the string over angle, as 0° can be landscape on some tablets
|
|
198
|
-
|
|
199
|
-
|
|
302
|
+
const orientationString = ((screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation || '').split('-')[0];
|
|
200
303
|
if (orientationString === 'landscape' || orientationString === 'portrait') {
|
|
201
304
|
return orientationString;
|
|
202
305
|
}
|
|
203
|
-
}
|
|
204
|
-
|
|
306
|
+
}
|
|
205
307
|
|
|
308
|
+
// iOS only supports window.orientation
|
|
206
309
|
if (typeof window.orientation === 'number') {
|
|
207
310
|
if (window.orientation === 0 || window.orientation === 180) {
|
|
208
311
|
return 'portrait';
|
|
209
312
|
}
|
|
210
|
-
|
|
211
313
|
return 'landscape';
|
|
212
314
|
}
|
|
213
|
-
|
|
214
315
|
return 'portrait';
|
|
215
|
-
};
|
|
216
|
-
|
|
316
|
+
};
|
|
217
317
|
|
|
218
|
-
var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
219
318
|
/**
|
|
220
319
|
* Add UI and event listeners
|
|
221
320
|
*
|
|
@@ -223,63 +322,49 @@ var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
|
223
322
|
* @param {Player} player
|
|
224
323
|
* A Video.js player object.
|
|
225
324
|
*
|
|
226
|
-
* @param {
|
|
325
|
+
* @param {MobileUiOptions} [options={}]
|
|
227
326
|
* A plain object containing options for the plugin.
|
|
228
327
|
*/
|
|
229
|
-
|
|
230
|
-
var onPlayerReady = function onPlayerReady(player, options) {
|
|
328
|
+
const onPlayerReady = (player, options) => {
|
|
231
329
|
player.addClass('vjs-mobile-ui');
|
|
232
|
-
|
|
233
|
-
if (options.fullscreen.iOS) {
|
|
234
|
-
videojs.log.warn('videojs-mobile-ui: `fullscreen.iOS` is deprecated. Use Video.js option `preferFullWindow` instead.');
|
|
235
|
-
|
|
236
|
-
if (videojs.browser.IS_IOS && videojs.browser.IOS_VERSION > 9 && !player.el_.ownerDocument.querySelector('.bc-iframe')) {
|
|
237
|
-
player.tech_.el_.setAttribute('playsinline', 'playsinline');
|
|
238
|
-
|
|
239
|
-
player.tech_.supportsFullScreen = function () {
|
|
240
|
-
return false;
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
330
|
if (!options.touchControls.disabled) {
|
|
246
331
|
if (options.touchControls.disableOnEnd || typeof player.endscreen === 'function') {
|
|
247
332
|
player.addClass('vjs-mobile-ui-disable-end');
|
|
248
|
-
}
|
|
249
|
-
|
|
333
|
+
}
|
|
250
334
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
335
|
+
// Insert before the control bar
|
|
336
|
+
let controlBarIdx;
|
|
337
|
+
const versionParts = videojs.VERSION.split('.');
|
|
338
|
+
const major = parseInt(versionParts[0], 10);
|
|
339
|
+
const minor = parseInt(versionParts[1], 10);
|
|
255
340
|
|
|
341
|
+
// Video.js < 7.7.0 doesn't account for precedding components that don't have elements
|
|
256
342
|
if (major < 7 || major === 7 && minor < 7) {
|
|
257
343
|
controlBarIdx = Array.prototype.indexOf.call(player.el_.children, player.getChild('ControlBar').el_);
|
|
258
344
|
} else {
|
|
259
345
|
controlBarIdx = player.children_.indexOf(player.getChild('ControlBar'));
|
|
260
346
|
}
|
|
261
|
-
|
|
262
347
|
player.touchOverlay = player.addChild('TouchOverlay', options.touchControls, controlBarIdx);
|
|
263
348
|
}
|
|
264
|
-
|
|
265
349
|
if (options.fullscreen.disabled) {
|
|
266
350
|
return;
|
|
267
351
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
352
|
+
if (options.fullscreen.swipeToFullscreen || options.fullscreen.swipeFromFullscreen) {
|
|
353
|
+
initSwipe(player, options);
|
|
354
|
+
}
|
|
355
|
+
let locked = false;
|
|
356
|
+
const rotationHandler = () => {
|
|
357
|
+
const currentOrientation = getOrientation();
|
|
274
358
|
if (currentOrientation === 'landscape' && options.fullscreen.enterOnRotate) {
|
|
275
|
-
if (player.paused()
|
|
276
|
-
player.requestFullscreen()
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
359
|
+
if (!player.paused() && !player.isFullscreen()) {
|
|
360
|
+
player.requestFullscreen().catch(err => {
|
|
361
|
+
player.log.warn('Browser refused fullscreen request:', err);
|
|
362
|
+
});
|
|
363
|
+
if ((options.fullscreen.lockOnRotate || options.fullscreen.lockToLandscapeOnEnter) && screen.orientation && screen.orientation.lock) {
|
|
364
|
+
screen.orientation.lock('landscape').then(() => {
|
|
280
365
|
locked = true;
|
|
281
|
-
}).catch(
|
|
282
|
-
videojs.log('Browser refused orientation lock:',
|
|
366
|
+
}).catch(err => {
|
|
367
|
+
videojs.log.warn('Browser refused orientation lock:', err);
|
|
283
368
|
});
|
|
284
369
|
}
|
|
285
370
|
}
|
|
@@ -289,90 +374,58 @@ var onPlayerReady = function onPlayerReady(player, options) {
|
|
|
289
374
|
}
|
|
290
375
|
}
|
|
291
376
|
};
|
|
292
|
-
|
|
293
377
|
if (options.fullscreen.enterOnRotate || options.fullscreen.exitOnRotate) {
|
|
294
378
|
if (videojs.browser.IS_IOS) {
|
|
295
379
|
window.addEventListener('orientationchange', rotationHandler);
|
|
296
|
-
player.on('dispose',
|
|
380
|
+
player.on('dispose', () => {
|
|
297
381
|
window.removeEventListener('orientationchange', rotationHandler);
|
|
298
382
|
});
|
|
299
383
|
} else if (screen.orientation) {
|
|
300
384
|
// addEventListener('orientationchange') is not a user interaction on Android
|
|
301
385
|
screen.orientation.onchange = rotationHandler;
|
|
302
|
-
player.on('dispose',
|
|
386
|
+
player.on('dispose', () => {
|
|
303
387
|
screen.orientation.onchange = null;
|
|
304
388
|
});
|
|
305
389
|
}
|
|
306
|
-
|
|
307
|
-
player.on('fullscreenchange', function (_) {
|
|
308
|
-
if (!player.isFullscreen() && locked) {
|
|
309
|
-
screen.orientation.unlock();
|
|
310
|
-
locked = false;
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
390
|
}
|
|
314
|
-
|
|
315
|
-
|
|
391
|
+
player.on('fullscreenchange', _ => {
|
|
392
|
+
if (player.isFullscreen() && options.fullscreen.lockToLandscapeOnEnter && getOrientation() === 'portrait') {
|
|
393
|
+
screen.orientation.lock('landscape').then(() => {
|
|
394
|
+
locked = true;
|
|
395
|
+
}).catch(e => {
|
|
396
|
+
videojs.log('Browser refused orientation lock:', e);
|
|
397
|
+
});
|
|
398
|
+
} else if (!player.isFullscreen() && locked) {
|
|
399
|
+
screen.orientation.unlock();
|
|
400
|
+
locked = false;
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
player.on('ended', _ => {
|
|
316
404
|
if (locked === true) {
|
|
317
405
|
screen.orientation.unlock();
|
|
318
406
|
locked = false;
|
|
319
407
|
}
|
|
320
408
|
});
|
|
321
409
|
};
|
|
410
|
+
|
|
322
411
|
/**
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
* Adds a monile UI for player control, and fullscreen orientation control
|
|
412
|
+
* Adds a mobile UI for player control, and fullscreen orientation control
|
|
326
413
|
*
|
|
327
414
|
* @function mobileUi
|
|
328
|
-
* @param {Object} [options={}]
|
|
329
|
-
* Plugin options.
|
|
330
|
-
* @param {boolean} [options.forceForTesting=false]
|
|
331
|
-
* Enables the display regardless of user agent, for testing purposes
|
|
332
|
-
* @param {Object} [options.fullscreen={}]
|
|
333
|
-
* Fullscreen options.
|
|
334
|
-
* @param {boolean} [options.fullscreen.disabled=false]
|
|
335
|
-
* If true no fullscreen handling except the *deprecated* iOS fullwindow hack
|
|
336
|
-
* @param {boolean} [options.fullscreen.enterOnRotate=true]
|
|
337
|
-
* Whether to go fullscreen when rotating to landscape
|
|
338
|
-
* @param {boolean} [options.fullscreen.exitOnRotate=true]
|
|
339
|
-
* Whether to leave fullscreen when rotating to portrait (if not locked)
|
|
340
|
-
* @param {boolean} [options.fullscreen.lockOnRotate=true]
|
|
341
|
-
* Whether to lock orientation when rotating to landscape
|
|
342
|
-
* Unlocked when exiting fullscreen or on 'ended'
|
|
343
|
-
* @param {boolean} [options.fullscreen.iOS=false]
|
|
344
|
-
* Deprecated: Whether to disable iOS's native fullscreen so controls can work
|
|
345
|
-
* @param {Object} [options.touchControls={}]
|
|
346
|
-
* Touch UI options.
|
|
347
|
-
* @param {boolean} [options.touchControls.disabled=false]
|
|
348
|
-
* If true no touch controls are added.
|
|
349
|
-
* @param {int} [options.touchControls.seekSeconds=10]
|
|
350
|
-
* Number of seconds to seek on double-tap
|
|
351
|
-
* @param {int} [options.touchControls.tapTimeout=300]
|
|
352
|
-
* Interval in ms to be considered a doubletap
|
|
353
|
-
* @param {boolean} [options.touchControls.disableOnEnd=false]
|
|
354
|
-
* Whether to disable when the video ends (e.g., if there is an endscreen)
|
|
355
|
-
* Never shows if the endscreen plugin is present
|
|
415
|
+
* @param {Object} [options={}] Plugin options
|
|
356
416
|
*/
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
var mobileUi = function mobileUi(options) {
|
|
360
|
-
var _this = this;
|
|
361
|
-
|
|
362
|
-
if (options === void 0) {
|
|
363
|
-
options = {};
|
|
364
|
-
}
|
|
365
|
-
|
|
417
|
+
const mobileUi = function (options = {}) {
|
|
366
418
|
if (options.forceForTesting || videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
|
|
367
|
-
this.ready(
|
|
368
|
-
onPlayerReady(
|
|
419
|
+
this.ready(() => {
|
|
420
|
+
onPlayerReady(this, videojs.mergeOptions(defaults, options));
|
|
369
421
|
});
|
|
370
422
|
}
|
|
371
|
-
};
|
|
372
|
-
|
|
423
|
+
};
|
|
373
424
|
|
|
374
|
-
|
|
425
|
+
// Register the plugin with video.js.
|
|
426
|
+
registerPlugin('mobileUi', mobileUi);
|
|
375
427
|
|
|
428
|
+
// Include the version number.
|
|
376
429
|
mobileUi.VERSION = version;
|
|
377
430
|
|
|
378
|
-
export default
|
|
431
|
+
export { mobileUi as default };
|