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
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
/*! @name videojs-mobile-ui @version 0.
|
|
1
|
+
/*! @name videojs-mobile-ui @version 1.0.0 @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 = "1.0.0";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @file touchOverlay.js
|
|
9
|
+
* Touch UI component
|
|
10
|
+
*/
|
|
11
|
+
const Component = videojs.getComponent('Component');
|
|
12
|
+
const dom = videojs.dom || videojs;
|
|
7
13
|
|
|
8
|
-
var Component = videojs.getComponent('Component');
|
|
9
|
-
var dom = videojs.dom || videojs;
|
|
10
14
|
/**
|
|
11
15
|
* The `TouchOverlay` is an overlay to capture tap events.
|
|
12
16
|
*
|
|
13
17
|
* @extends Component
|
|
14
18
|
*/
|
|
15
|
-
|
|
16
|
-
var TouchOverlay = /*#__PURE__*/function (_Component) {
|
|
17
|
-
_inheritsLoose(TouchOverlay, _Component);
|
|
18
|
-
|
|
19
|
+
class TouchOverlay extends Component {
|
|
19
20
|
/**
|
|
20
21
|
* Creates an instance of the this class.
|
|
21
22
|
*
|
|
@@ -25,46 +26,80 @@ var TouchOverlay = /*#__PURE__*/function (_Component) {
|
|
|
25
26
|
* @param {Object} [options]
|
|
26
27
|
* The key/value store of player options.
|
|
27
28
|
*/
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
player.on(['playing', 'userinactive'],
|
|
39
|
-
|
|
40
|
-
});
|
|
29
|
+
constructor(player, options) {
|
|
30
|
+
super(player, options);
|
|
31
|
+
this.seekSeconds = options.seekSeconds;
|
|
32
|
+
this.tapTimeout = options.tapTimeout;
|
|
33
|
+
this.taps = 0;
|
|
34
|
+
|
|
35
|
+
// Add play toggle overlay
|
|
36
|
+
this.addChild('playToggle', {});
|
|
37
|
+
|
|
38
|
+
// Clear overlay when playback starts or with control fade
|
|
39
|
+
player.on(['playing', 'userinactive'], e => {
|
|
40
|
+
this.removeClass('show-play-toggle');
|
|
41
|
+
});
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
// A 0 inactivity timeout won't work here
|
|
44
|
+
if (this.player_.options_.inactivityTimeout === 0) {
|
|
45
|
+
this.player_.options_.inactivityTimeout = 5000;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
|
|
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
|
+
this.taps = 0;
|
|
58
|
+
if (increment < 1) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const rect = this.el_.getBoundingClientRect();
|
|
62
|
+
const x = event.changedTouches[0].clientX - rect.left;
|
|
63
|
+
|
|
64
|
+
// Check if double tap is in left or right area
|
|
65
|
+
if (x < rect.width * 0.4) {
|
|
66
|
+
this.player_.currentTime(Math.max(0, this.player_.currentTime() - increment));
|
|
67
|
+
this.addClass('reverse');
|
|
68
|
+
} else if (x > rect.width - rect.width * 0.4) {
|
|
69
|
+
this.player_.currentTime(Math.min(this.player_.duration(), this.player_.currentTime() + increment));
|
|
70
|
+
this.removeClass('reverse');
|
|
71
|
+
} else {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Remove play toggle if showing
|
|
76
|
+
this.removeClass('show-play-toggle');
|
|
47
77
|
|
|
48
|
-
|
|
78
|
+
// Remove and readd class to trigger animation
|
|
79
|
+
this.setAttribute('data-skip-text', `${increment} ${this.localize('seconds')}`);
|
|
80
|
+
this.removeClass('skip');
|
|
81
|
+
window.requestAnimationFrame(() => {
|
|
82
|
+
this.addClass('skip');
|
|
83
|
+
});
|
|
84
|
+
}, this.tapTimeout);
|
|
85
|
+
this.enable();
|
|
49
86
|
}
|
|
87
|
+
|
|
50
88
|
/**
|
|
51
89
|
* Builds the DOM element.
|
|
52
90
|
*
|
|
53
91
|
* @return {Element}
|
|
54
92
|
* The DOM element.
|
|
55
93
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
var _proto = TouchOverlay.prototype;
|
|
59
|
-
|
|
60
|
-
_proto.createEl = function createEl() {
|
|
61
|
-
var el = dom.createEl('div', {
|
|
94
|
+
createEl() {
|
|
95
|
+
const el = dom.createEl('div', {
|
|
62
96
|
className: 'vjs-touch-overlay',
|
|
63
97
|
// Touch overlay is not tabbable.
|
|
64
98
|
tabIndex: -1
|
|
65
99
|
});
|
|
66
100
|
return el;
|
|
67
101
|
}
|
|
102
|
+
|
|
68
103
|
/**
|
|
69
104
|
* Debounces to either handle a delayed single tap, or a double tap
|
|
70
105
|
*
|
|
@@ -72,110 +107,44 @@ var TouchOverlay = /*#__PURE__*/function (_Component) {
|
|
|
72
107
|
* The touch event
|
|
73
108
|
*
|
|
74
109
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
_proto.handleTap = function handleTap(event) {
|
|
78
|
-
var _this2 = this;
|
|
79
|
-
|
|
110
|
+
handleTap(event) {
|
|
80
111
|
// Don't handle taps on the play button
|
|
81
112
|
if (event.target !== this.el_) {
|
|
82
113
|
return;
|
|
83
114
|
}
|
|
84
|
-
|
|
85
115
|
event.preventDefault();
|
|
86
|
-
|
|
87
|
-
if (this.
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
if (this.timeout) {
|
|
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);
|
|
116
|
+
this.taps += 1;
|
|
117
|
+
if (this.taps === 1) {
|
|
118
|
+
this.removeClass('skip');
|
|
119
|
+
this.toggleClass('show-play-toggle');
|
|
102
120
|
}
|
|
121
|
+
this.handleTaps_(event);
|
|
103
122
|
}
|
|
104
|
-
/**
|
|
105
|
-
* Toggles display of play toggle
|
|
106
|
-
*
|
|
107
|
-
* @param {Event} event
|
|
108
|
-
* The touch event
|
|
109
|
-
*
|
|
110
|
-
*/
|
|
111
|
-
;
|
|
112
|
-
|
|
113
|
-
_proto.handleSingleTap = function handleSingleTap(event) {
|
|
114
|
-
this.removeClass('skip');
|
|
115
|
-
this.toggleClass('show-play-toggle');
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Seeks by configured number of seconds if left or right part of video double tapped
|
|
119
|
-
*
|
|
120
|
-
* @param {Event} event
|
|
121
|
-
* The touch event
|
|
122
|
-
*
|
|
123
|
-
*/
|
|
124
|
-
;
|
|
125
|
-
|
|
126
|
-
_proto.handleDoubleTap = function handleDoubleTap(event) {
|
|
127
|
-
var _this3 = this;
|
|
128
|
-
|
|
129
|
-
var rect = this.el_.getBoundingClientRect();
|
|
130
|
-
var x = event.changedTouches[0].clientX - rect.left; // Check if double tap is in left or right area
|
|
131
123
|
|
|
132
|
-
if (x < rect.width * 0.4) {
|
|
133
|
-
this.player_.currentTime(Math.max(0, this.player_.currentTime() - this.seekSeconds));
|
|
134
|
-
this.addClass('reverse');
|
|
135
|
-
} else if (x > rect.width - rect.width * 0.4) {
|
|
136
|
-
this.player_.currentTime(Math.min(this.player_.duration(), this.player_.currentTime() + this.seekSeconds));
|
|
137
|
-
this.removeClass('reverse');
|
|
138
|
-
} else {
|
|
139
|
-
return;
|
|
140
|
-
} // Remove play toggle if showing
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
this.removeClass('show-play-toggle'); // Remove and readd class to trigger animation
|
|
144
|
-
|
|
145
|
-
this.removeClass('skip');
|
|
146
|
-
window.requestAnimationFrame(function () {
|
|
147
|
-
_this3.addClass('skip');
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
124
|
/**
|
|
151
125
|
* Enables touch handler
|
|
152
126
|
*/
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
_proto.enable = function enable() {
|
|
127
|
+
enable() {
|
|
156
128
|
this.firstTapCaptured = false;
|
|
157
129
|
this.on('touchend', this.handleTap);
|
|
158
130
|
}
|
|
131
|
+
|
|
159
132
|
/**
|
|
160
133
|
* Disables touch handler
|
|
161
134
|
*/
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
_proto.disable = function disable() {
|
|
135
|
+
disable() {
|
|
165
136
|
this.off('touchend', this.handleTap);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return TouchOverlay;
|
|
169
|
-
}(Component);
|
|
170
|
-
|
|
137
|
+
}
|
|
138
|
+
}
|
|
171
139
|
Component.registerComponent('TouchOverlay', TouchOverlay);
|
|
172
140
|
|
|
173
|
-
|
|
141
|
+
// Default options for the plugin.
|
|
142
|
+
const defaults = {
|
|
174
143
|
fullscreen: {
|
|
175
144
|
enterOnRotate: true,
|
|
176
145
|
exitOnRotate: true,
|
|
177
146
|
lockOnRotate: true,
|
|
178
|
-
|
|
147
|
+
lockToLandscapeOnEnter: false,
|
|
179
148
|
disabled: false
|
|
180
149
|
},
|
|
181
150
|
touchControls: {
|
|
@@ -185,37 +154,32 @@ var defaults = {
|
|
|
185
154
|
disabled: false
|
|
186
155
|
}
|
|
187
156
|
};
|
|
188
|
-
|
|
157
|
+
const screen = window.screen;
|
|
158
|
+
|
|
189
159
|
/**
|
|
190
160
|
* Gets 'portrait' or 'lanscape' from the two orientation APIs
|
|
191
161
|
*
|
|
192
162
|
* @return {string} orientation
|
|
193
163
|
*/
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (screen) {
|
|
164
|
+
const getOrientation = () => {
|
|
165
|
+
if (window.screen) {
|
|
197
166
|
// Prefer the string over angle, as 0° can be landscape on some tablets
|
|
198
|
-
|
|
199
|
-
|
|
167
|
+
const orientationString = ((window.screen.orientation || {}).type || window.screen.mozOrientation || window.screen.msOrientation || '').split('-')[0];
|
|
200
168
|
if (orientationString === 'landscape' || orientationString === 'portrait') {
|
|
201
169
|
return orientationString;
|
|
202
170
|
}
|
|
203
|
-
}
|
|
204
|
-
|
|
171
|
+
}
|
|
205
172
|
|
|
173
|
+
// iOS only supports window.orientation
|
|
206
174
|
if (typeof window.orientation === 'number') {
|
|
207
175
|
if (window.orientation === 0 || window.orientation === 180) {
|
|
208
176
|
return 'portrait';
|
|
209
177
|
}
|
|
210
|
-
|
|
211
178
|
return 'landscape';
|
|
212
179
|
}
|
|
213
|
-
|
|
214
180
|
return 'portrait';
|
|
215
|
-
};
|
|
216
|
-
|
|
181
|
+
};
|
|
217
182
|
|
|
218
|
-
var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
219
183
|
/**
|
|
220
184
|
* Add UI and event listeners
|
|
221
185
|
*
|
|
@@ -226,59 +190,30 @@ var registerPlugin = videojs.registerPlugin || videojs.plugin;
|
|
|
226
190
|
* @param {Object} [options={}]
|
|
227
191
|
* A plain object containing options for the plugin.
|
|
228
192
|
*/
|
|
229
|
-
|
|
230
|
-
var onPlayerReady = function onPlayerReady(player, options) {
|
|
193
|
+
const onPlayerReady = (player, options) => {
|
|
231
194
|
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
195
|
if (!options.touchControls.disabled) {
|
|
246
196
|
if (options.touchControls.disableOnEnd || typeof player.endscreen === 'function') {
|
|
247
197
|
player.addClass('vjs-mobile-ui-disable-end');
|
|
248
|
-
} // Insert before the control bar
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
var controlBarIdx;
|
|
252
|
-
var versionParts = videojs.VERSION.split('.');
|
|
253
|
-
var major = parseInt(versionParts[0], 10);
|
|
254
|
-
var minor = parseInt(versionParts[1], 10); // Video.js < 7.7.0 doesn't account for precedding components that don't have elements
|
|
255
|
-
|
|
256
|
-
if (major < 7 || major === 7 && minor < 7) {
|
|
257
|
-
controlBarIdx = Array.prototype.indexOf.call(player.el_.children, player.getChild('ControlBar').el_);
|
|
258
|
-
} else {
|
|
259
|
-
controlBarIdx = player.children_.indexOf(player.getChild('ControlBar'));
|
|
260
198
|
}
|
|
261
199
|
|
|
200
|
+
// Insert before the control bar
|
|
201
|
+
const controlBarIdx = player.children_.indexOf(player.getChild('ControlBar'));
|
|
262
202
|
player.touchOverlay = player.addChild('TouchOverlay', options.touchControls, controlBarIdx);
|
|
263
203
|
}
|
|
264
|
-
|
|
265
204
|
if (options.fullscreen.disabled) {
|
|
266
205
|
return;
|
|
267
206
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
var rotationHandler = function rotationHandler() {
|
|
272
|
-
var currentOrientation = getOrientation();
|
|
273
|
-
|
|
207
|
+
let locked = false;
|
|
208
|
+
const rotationHandler = () => {
|
|
209
|
+
const currentOrientation = getOrientation();
|
|
274
210
|
if (currentOrientation === 'landscape' && options.fullscreen.enterOnRotate) {
|
|
275
211
|
if (player.paused() === false) {
|
|
276
212
|
player.requestFullscreen();
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
screen.orientation.lock('landscape').then(function () {
|
|
213
|
+
if ((options.fullscreen.lockOnRotate || options.fullscreen.lockToLandscapeOnEnter) && screen.orientation && screen.orientation.lock) {
|
|
214
|
+
screen.orientation.lock('landscape').then(() => {
|
|
280
215
|
locked = true;
|
|
281
|
-
}).catch(
|
|
216
|
+
}).catch(e => {
|
|
282
217
|
videojs.log('Browser refused orientation lock:', e);
|
|
283
218
|
});
|
|
284
219
|
}
|
|
@@ -289,36 +224,40 @@ var onPlayerReady = function onPlayerReady(player, options) {
|
|
|
289
224
|
}
|
|
290
225
|
}
|
|
291
226
|
};
|
|
292
|
-
|
|
293
227
|
if (options.fullscreen.enterOnRotate || options.fullscreen.exitOnRotate) {
|
|
294
228
|
if (videojs.browser.IS_IOS) {
|
|
295
229
|
window.addEventListener('orientationchange', rotationHandler);
|
|
296
|
-
player.on('dispose',
|
|
230
|
+
player.on('dispose', () => {
|
|
297
231
|
window.removeEventListener('orientationchange', rotationHandler);
|
|
298
232
|
});
|
|
299
233
|
} else if (screen.orientation) {
|
|
300
234
|
// addEventListener('orientationchange') is not a user interaction on Android
|
|
301
235
|
screen.orientation.onchange = rotationHandler;
|
|
302
|
-
player.on('dispose',
|
|
236
|
+
player.on('dispose', () => {
|
|
303
237
|
screen.orientation.onchange = null;
|
|
304
238
|
});
|
|
305
239
|
}
|
|
306
|
-
|
|
307
|
-
player.on('fullscreenchange', function (_) {
|
|
308
|
-
if (!player.isFullscreen() && locked) {
|
|
309
|
-
screen.orientation.unlock();
|
|
310
|
-
locked = false;
|
|
311
|
-
}
|
|
312
|
-
});
|
|
313
240
|
}
|
|
314
|
-
|
|
315
|
-
|
|
241
|
+
player.on('fullscreenchange', _ => {
|
|
242
|
+
if (player.isFullscreen() && options.fullscreen.lockToLandscapeOnEnter && getOrientation() === 'portrait') {
|
|
243
|
+
screen.orientation.lock('landscape').then(() => {
|
|
244
|
+
locked = true;
|
|
245
|
+
}).catch(e => {
|
|
246
|
+
videojs.log('Browser refused orientation lock:', e);
|
|
247
|
+
});
|
|
248
|
+
} else if (!player.isFullscreen() && locked) {
|
|
249
|
+
screen.orientation.unlock();
|
|
250
|
+
locked = false;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
player.on('ended', _ => {
|
|
316
254
|
if (locked === true) {
|
|
317
255
|
screen.orientation.unlock();
|
|
318
256
|
locked = false;
|
|
319
257
|
}
|
|
320
258
|
});
|
|
321
259
|
};
|
|
260
|
+
|
|
322
261
|
/**
|
|
323
262
|
* A video.js plugin.
|
|
324
263
|
*
|
|
@@ -339,6 +278,9 @@ var onPlayerReady = function onPlayerReady(player, options) {
|
|
|
339
278
|
* Whether to leave fullscreen when rotating to portrait (if not locked)
|
|
340
279
|
* @param {boolean} [options.fullscreen.lockOnRotate=true]
|
|
341
280
|
* Whether to lock orientation when rotating to landscape
|
|
281
|
+
* Unlocked when exiting fullscreen or on 'ended
|
|
282
|
+
* @param {boolean} [options.fullscreen.lockToLandscapeOnEnter=false]
|
|
283
|
+
* Whether to always lock orientation to landscape on fullscreen mode
|
|
342
284
|
* Unlocked when exiting fullscreen or on 'ended'
|
|
343
285
|
* @param {boolean} [options.fullscreen.iOS=false]
|
|
344
286
|
* Deprecated: Whether to disable iOS's native fullscreen so controls can work
|
|
@@ -354,25 +296,18 @@ var onPlayerReady = function onPlayerReady(player, options) {
|
|
|
354
296
|
* Whether to disable when the video ends (e.g., if there is an endscreen)
|
|
355
297
|
* Never shows if the endscreen plugin is present
|
|
356
298
|
*/
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
var mobileUi = function mobileUi(options) {
|
|
360
|
-
var _this = this;
|
|
361
|
-
|
|
362
|
-
if (options === void 0) {
|
|
363
|
-
options = {};
|
|
364
|
-
}
|
|
365
|
-
|
|
299
|
+
const mobileUi = function (options = {}) {
|
|
366
300
|
if (options.forceForTesting || videojs.browser.IS_ANDROID || videojs.browser.IS_IOS) {
|
|
367
|
-
this.ready(
|
|
368
|
-
onPlayerReady(
|
|
301
|
+
this.ready(() => {
|
|
302
|
+
onPlayerReady(this, videojs.obj.merge(defaults, options));
|
|
369
303
|
});
|
|
370
304
|
}
|
|
371
|
-
};
|
|
372
|
-
|
|
305
|
+
};
|
|
373
306
|
|
|
374
|
-
|
|
307
|
+
// Register the plugin with video.js.
|
|
308
|
+
videojs.registerPlugin('mobileUi', mobileUi);
|
|
375
309
|
|
|
310
|
+
// Include the version number.
|
|
376
311
|
mobileUi.VERSION = version;
|
|
377
312
|
|
|
378
313
|
export default mobileUi;
|