videojs-mobile-ui 0.8.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/CHANGELOG.md +0 -31
- package/README.md +110 -50
- package/dist/videojs-mobile-ui.cjs.js +265 -222
- package/dist/videojs-mobile-ui.css +2 -2
- package/dist/videojs-mobile-ui.es.js +259 -215
- package/dist/videojs-mobile-ui.js +268 -264
- package/dist/videojs-mobile-ui.min.js +2 -2
- package/docs/api/swipeFullscreen.js.html +173 -0
- package/index.html +238 -176
- package/package.json +15 -15
- package/src/plugin.css +21 -3
- package/src/plugin.js +17 -54
- 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
|
+
}
|
|
47
86
|
|
|
48
|
-
|
|
87
|
+
// Remove play toggle if showing
|
|
88
|
+
this.removeClass('show-play-toggle');
|
|
89
|
+
|
|
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,111 +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,
|
|
179
|
-
|
|
280
|
+
swipeToFullscreen: false,
|
|
281
|
+
swipeFromFullscreen: false,
|
|
180
282
|
disabled: false
|
|
181
283
|
},
|
|
182
284
|
touchControls: {
|
|
@@ -186,37 +288,33 @@ var defaults = {
|
|
|
186
288
|
disabled: false
|
|
187
289
|
}
|
|
188
290
|
};
|
|
189
|
-
|
|
291
|
+
const screen = window.screen;
|
|
292
|
+
const registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
293
|
+
|
|
190
294
|
/**
|
|
191
295
|
* Gets 'portrait' or 'lanscape' from the two orientation APIs
|
|
192
296
|
*
|
|
193
297
|
* @return {string} orientation
|
|
194
298
|
*/
|
|
195
|
-
|
|
196
|
-
var getOrientation = function getOrientation() {
|
|
299
|
+
const getOrientation = () => {
|
|
197
300
|
if (screen) {
|
|
198
301
|
// Prefer the string over angle, as 0° can be landscape on some tablets
|
|
199
|
-
|
|
200
|
-
|
|
302
|
+
const orientationString = ((screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation || '').split('-')[0];
|
|
201
303
|
if (orientationString === 'landscape' || orientationString === 'portrait') {
|
|
202
304
|
return orientationString;
|
|
203
305
|
}
|
|
204
|
-
}
|
|
205
|
-
|
|
306
|
+
}
|
|
206
307
|
|
|
308
|
+
// iOS only supports window.orientation
|
|
207
309
|
if (typeof window.orientation === 'number') {
|
|
208
310
|
if (window.orientation === 0 || window.orientation === 180) {
|
|
209
311
|
return 'portrait';
|
|
210
312
|
}
|
|
211
|
-
|
|
212
313
|
return 'landscape';
|
|
213
314
|
}
|
|
214
|
-
|
|
215
315
|
return 'portrait';
|
|
216
|
-
};
|
|
217
|
-
|
|
316
|
+
};
|
|
218
317
|
|
|
219
|
-
var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
220
318
|
/**
|
|
221
319
|
* Add UI and event listeners
|
|
222
320
|
*
|
|
@@ -224,63 +322,49 @@ var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
|
224
322
|
* @param {Player} player
|
|
225
323
|
* A Video.js player object.
|
|
226
324
|
*
|
|
227
|
-
* @param {
|
|
325
|
+
* @param {MobileUiOptions} [options={}]
|
|
228
326
|
* A plain object containing options for the plugin.
|
|
229
327
|
*/
|
|
230
|
-
|
|
231
|
-
var onPlayerReady = function onPlayerReady(player, options) {
|
|
328
|
+
const onPlayerReady = (player, options) => {
|
|
232
329
|
player.addClass('vjs-mobile-ui');
|
|
233
|
-
|
|
234
|
-
if (options.fullscreen.iOS) {
|
|
235
|
-
videojs.log.warn('videojs-mobile-ui: `fullscreen.iOS` is deprecated. Use Video.js option `preferFullWindow` instead.');
|
|
236
|
-
|
|
237
|
-
if (videojs.browser.IS_IOS && videojs.browser.IOS_VERSION > 9 && !player.el_.ownerDocument.querySelector('.bc-iframe')) {
|
|
238
|
-
player.tech_.el_.setAttribute('playsinline', 'playsinline');
|
|
239
|
-
|
|
240
|
-
player.tech_.supportsFullScreen = function () {
|
|
241
|
-
return false;
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
330
|
if (!options.touchControls.disabled) {
|
|
247
331
|
if (options.touchControls.disableOnEnd || typeof player.endscreen === 'function') {
|
|
248
332
|
player.addClass('vjs-mobile-ui-disable-end');
|
|
249
|
-
}
|
|
250
|
-
|
|
333
|
+
}
|
|
251
334
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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);
|
|
256
340
|
|
|
341
|
+
// Video.js < 7.7.0 doesn't account for precedding components that don't have elements
|
|
257
342
|
if (major < 7 || major === 7 && minor < 7) {
|
|
258
343
|
controlBarIdx = Array.prototype.indexOf.call(player.el_.children, player.getChild('ControlBar').el_);
|
|
259
344
|
} else {
|
|
260
345
|
controlBarIdx = player.children_.indexOf(player.getChild('ControlBar'));
|
|
261
346
|
}
|
|
262
|
-
|
|
263
347
|
player.touchOverlay = player.addChild('TouchOverlay', options.touchControls, controlBarIdx);
|
|
264
348
|
}
|
|
265
|
-
|
|
266
349
|
if (options.fullscreen.disabled) {
|
|
267
350
|
return;
|
|
268
351
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
352
|
+
if (options.fullscreen.swipeToFullscreen || options.fullscreen.swipeFromFullscreen) {
|
|
353
|
+
initSwipe(player, options);
|
|
354
|
+
}
|
|
355
|
+
let locked = false;
|
|
356
|
+
const rotationHandler = () => {
|
|
357
|
+
const currentOrientation = getOrientation();
|
|
275
358
|
if (currentOrientation === 'landscape' && options.fullscreen.enterOnRotate) {
|
|
276
|
-
if (player.paused()
|
|
277
|
-
player.requestFullscreen()
|
|
278
|
-
|
|
359
|
+
if (!player.paused() && !player.isFullscreen()) {
|
|
360
|
+
player.requestFullscreen().catch(err => {
|
|
361
|
+
player.log.warn('Browser refused fullscreen request:', err);
|
|
362
|
+
});
|
|
279
363
|
if ((options.fullscreen.lockOnRotate || options.fullscreen.lockToLandscapeOnEnter) && screen.orientation && screen.orientation.lock) {
|
|
280
|
-
screen.orientation.lock('landscape').then(
|
|
364
|
+
screen.orientation.lock('landscape').then(() => {
|
|
281
365
|
locked = true;
|
|
282
|
-
}).catch(
|
|
283
|
-
videojs.log('Browser refused orientation lock:',
|
|
366
|
+
}).catch(err => {
|
|
367
|
+
videojs.log.warn('Browser refused orientation lock:', err);
|
|
284
368
|
});
|
|
285
369
|
}
|
|
286
370
|
}
|
|
@@ -290,27 +374,25 @@ var onPlayerReady = function onPlayerReady(player, options) {
|
|
|
290
374
|
}
|
|
291
375
|
}
|
|
292
376
|
};
|
|
293
|
-
|
|
294
377
|
if (options.fullscreen.enterOnRotate || options.fullscreen.exitOnRotate) {
|
|
295
378
|
if (videojs.browser.IS_IOS) {
|
|
296
379
|
window.addEventListener('orientationchange', rotationHandler);
|
|
297
|
-
player.on('dispose',
|
|
380
|
+
player.on('dispose', () => {
|
|
298
381
|
window.removeEventListener('orientationchange', rotationHandler);
|
|
299
382
|
});
|
|
300
383
|
} else if (screen.orientation) {
|
|
301
384
|
// addEventListener('orientationchange') is not a user interaction on Android
|
|
302
385
|
screen.orientation.onchange = rotationHandler;
|
|
303
|
-
player.on('dispose',
|
|
386
|
+
player.on('dispose', () => {
|
|
304
387
|
screen.orientation.onchange = null;
|
|
305
388
|
});
|
|
306
389
|
}
|
|
307
390
|
}
|
|
308
|
-
|
|
309
|
-
player.on('fullscreenchange', function (_) {
|
|
391
|
+
player.on('fullscreenchange', _ => {
|
|
310
392
|
if (player.isFullscreen() && options.fullscreen.lockToLandscapeOnEnter && getOrientation() === 'portrait') {
|
|
311
|
-
screen.orientation.lock('landscape').then(
|
|
393
|
+
screen.orientation.lock('landscape').then(() => {
|
|
312
394
|
locked = true;
|
|
313
|
-
}).catch(
|
|
395
|
+
}).catch(e => {
|
|
314
396
|
videojs.log('Browser refused orientation lock:', e);
|
|
315
397
|
});
|
|
316
398
|
} else if (!player.isFullscreen() && locked) {
|
|
@@ -318,70 +400,32 @@ var onPlayerReady = function onPlayerReady(player, options) {
|
|
|
318
400
|
locked = false;
|
|
319
401
|
}
|
|
320
402
|
});
|
|
321
|
-
player.on('ended',
|
|
403
|
+
player.on('ended', _ => {
|
|
322
404
|
if (locked === true) {
|
|
323
405
|
screen.orientation.unlock();
|
|
324
406
|
locked = false;
|
|
325
407
|
}
|
|
326
408
|
});
|
|
327
409
|
};
|
|
410
|
+
|
|
328
411
|
/**
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
* Adds a monile UI for player control, and fullscreen orientation control
|
|
412
|
+
* Adds a mobile UI for player control, and fullscreen orientation control
|
|
332
413
|
*
|
|
333
414
|
* @function mobileUi
|
|
334
|
-
* @param {Object} [options={}]
|
|
335
|
-
* Plugin options.
|
|
336
|
-
* @param {boolean} [options.forceForTesting=false]
|
|
337
|
-
* Enables the display regardless of user agent, for testing purposes
|
|
338
|
-
* @param {Object} [options.fullscreen={}]
|
|
339
|
-
* Fullscreen options.
|
|
340
|
-
* @param {boolean} [options.fullscreen.disabled=false]
|
|
341
|
-
* If true no fullscreen handling except the *deprecated* iOS fullwindow hack
|
|
342
|
-
* @param {boolean} [options.fullscreen.enterOnRotate=true]
|
|
343
|
-
* Whether to go fullscreen when rotating to landscape
|
|
344
|
-
* @param {boolean} [options.fullscreen.exitOnRotate=true]
|
|
345
|
-
* Whether to leave fullscreen when rotating to portrait (if not locked)
|
|
346
|
-
* @param {boolean} [options.fullscreen.lockOnRotate=true]
|
|
347
|
-
* Whether to lock orientation when rotating to landscape
|
|
348
|
-
* Unlocked when exiting fullscreen or on 'ended
|
|
349
|
-
* @param {boolean} [options.fullscreen.lockToLandscapeOnEnter=false]
|
|
350
|
-
* Whether to always lock orientation to landscape on fullscreen mode
|
|
351
|
-
* Unlocked when exiting fullscreen or on 'ended'
|
|
352
|
-
* @param {boolean} [options.fullscreen.iOS=false]
|
|
353
|
-
* Deprecated: Whether to disable iOS's native fullscreen so controls can work
|
|
354
|
-
* @param {Object} [options.touchControls={}]
|
|
355
|
-
* Touch UI options.
|
|
356
|
-
* @param {boolean} [options.touchControls.disabled=false]
|
|
357
|
-
* If true no touch controls are added.
|
|
358
|
-
* @param {int} [options.touchControls.seekSeconds=10]
|
|
359
|
-
* Number of seconds to seek on double-tap
|
|
360
|
-
* @param {int} [options.touchControls.tapTimeout=300]
|
|
361
|
-
* Interval in ms to be considered a doubletap
|
|
362
|
-
* @param {boolean} [options.touchControls.disableOnEnd=false]
|
|
363
|
-
* Whether to disable when the video ends (e.g., if there is an endscreen)
|
|
364
|
-
* Never shows if the endscreen plugin is present
|
|
415
|
+
* @param {Object} [options={}] Plugin options
|
|
365
416
|
*/
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
var mobileUi = function mobileUi(options) {
|
|
369
|
-
var _this = this;
|
|
370
|
-
|
|
371
|
-
if (options === void 0) {
|
|
372
|
-
options = {};
|
|
373
|
-
}
|
|
374
|
-
|
|
417
|
+
const mobileUi = function (options = {}) {
|
|
375
418
|
if (options.forceForTesting || videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
|
|
376
|
-
this.ready(
|
|
377
|
-
onPlayerReady(
|
|
419
|
+
this.ready(() => {
|
|
420
|
+
onPlayerReady(this, videojs.mergeOptions(defaults, options));
|
|
378
421
|
});
|
|
379
422
|
}
|
|
380
|
-
};
|
|
381
|
-
|
|
423
|
+
};
|
|
382
424
|
|
|
383
|
-
|
|
425
|
+
// Register the plugin with video.js.
|
|
426
|
+
registerPlugin('mobileUi', mobileUi);
|
|
384
427
|
|
|
428
|
+
// Include the version number.
|
|
385
429
|
mobileUi.VERSION = version;
|
|
386
430
|
|
|
387
|
-
export default
|
|
431
|
+
export { mobileUi as default };
|