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