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.
Files changed (45) hide show
  1. package/README.md +114 -46
  2. package/dist/videojs-mobile-ui.cjs.js +275 -223
  3. package/dist/videojs-mobile-ui.css +2 -2
  4. package/dist/videojs-mobile-ui.es.js +270 -217
  5. package/dist/videojs-mobile-ui.js +278 -265
  6. package/dist/videojs-mobile-ui.min.js +2 -2
  7. package/docs/api/TouchOverlay.html +964 -0
  8. package/docs/api/fonts/OpenSans-Bold-webfont.eot +0 -0
  9. package/docs/api/fonts/OpenSans-Bold-webfont.svg +1830 -0
  10. package/docs/api/fonts/OpenSans-Bold-webfont.woff +0 -0
  11. package/docs/api/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
  12. package/docs/api/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
  13. package/docs/api/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
  14. package/docs/api/fonts/OpenSans-Italic-webfont.eot +0 -0
  15. package/docs/api/fonts/OpenSans-Italic-webfont.svg +1830 -0
  16. package/docs/api/fonts/OpenSans-Italic-webfont.woff +0 -0
  17. package/docs/api/fonts/OpenSans-Light-webfont.eot +0 -0
  18. package/docs/api/fonts/OpenSans-Light-webfont.svg +1831 -0
  19. package/docs/api/fonts/OpenSans-Light-webfont.woff +0 -0
  20. package/docs/api/fonts/OpenSans-LightItalic-webfont.eot +0 -0
  21. package/docs/api/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
  22. package/docs/api/fonts/OpenSans-LightItalic-webfont.woff +0 -0
  23. package/docs/api/fonts/OpenSans-Regular-webfont.eot +0 -0
  24. package/docs/api/fonts/OpenSans-Regular-webfont.svg +1831 -0
  25. package/docs/api/fonts/OpenSans-Regular-webfont.woff +0 -0
  26. package/docs/api/global.html +957 -0
  27. package/docs/api/index.html +159 -0
  28. package/docs/api/plugin.js.html +221 -0
  29. package/docs/api/scripts/linenumber.js +25 -0
  30. package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -0
  31. package/docs/api/scripts/prettify/lang-css.js +2 -0
  32. package/docs/api/scripts/prettify/prettify.js +28 -0
  33. package/docs/api/styles/jsdoc-default.css +358 -0
  34. package/docs/api/styles/prettify-jsdoc.css +111 -0
  35. package/docs/api/styles/prettify-tomorrow.css +132 -0
  36. package/docs/api/swipeFullscreen.js.html +173 -0
  37. package/docs/api/touchOverlay.js.html +211 -0
  38. package/index.html +206 -65
  39. package/package.json +19 -16
  40. package/src/plugin.css +21 -3
  41. package/src/plugin.js +32 -59
  42. package/src/swipeFullscreen.js +117 -0
  43. package/src/touchOverlay.js +62 -56
  44. package/test/plugin.test.js +128 -20
  45. package/test/swipeFullscreen.test.js +365 -0
@@ -1,29 +1,41 @@
1
- /*! @name videojs-mobile-ui @version 0.7.0 @license MIT */
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.7.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
- function TouchOverlay(player, options) {
37
- var _this;
38
-
39
- _this = _Component.call(this, player, options) || this;
40
- _this.seekSeconds = options.seekSeconds;
41
- _this.tapTimeout = options.tapTimeout; // Add play toggle overlay
42
-
43
- _this.addChild('playToggle', {}); // Clear overlay when playback starts or with control fade
44
-
45
-
46
- player.on(['playing', 'userinactive'], function (e) {
47
- _this.removeClass('show-play-toggle');
48
- }); // A 0 inactivity timeout won't work here
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
- if (_this.player_.options_.inactivityTimeout === 0) {
51
- _this.player_.options_.inactivityTimeout = 5000;
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
- _this.enable();
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
- return _this;
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
- event.preventDefault();
94
-
95
- if (this.firstTapCaptured) {
96
- this.firstTapCaptured = false;
97
-
98
- if (this.timeout) {
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
- * Toggles display of play toggle
114
- *
115
- * @param {Event} event
116
- * The touch event
117
- *
146
+ * Enables touch handler
118
147
  */
119
- ;
120
-
121
- _proto.handleSingleTap = function handleSingleTap(event) {
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
- * Seeks by configured number of seconds if left or right part of video double tapped
127
- *
128
- * @param {Event} event
129
- * The touch event
130
- *
154
+ * Disables touch handler
131
155
  */
132
- ;
133
-
134
- _proto.handleDoubleTap = function handleDoubleTap(event) {
135
- var _this3 = this;
156
+ disable() {
157
+ this.off('touchend', this.handleTap);
158
+ }
159
+ }
160
+ Component.registerComponent('TouchOverlay', TouchOverlay);
136
161
 
137
- var rect = this.el_.getBoundingClientRect();
138
- var x = event.changedTouches[0].clientX - rect.left; // Check if double tap is in left or right area
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
- if (x < rect.width * 0.4) {
141
- this.player_.currentTime(Math.max(0, this.player_.currentTime() - this.seekSeconds));
142
- this.addClass('reverse');
143
- } else if (x > rect.width - rect.width * 0.4) {
144
- this.player_.currentTime(Math.min(this.player_.duration(), this.player_.currentTime() + this.seekSeconds));
145
- this.removeClass('reverse');
146
- } else {
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
- } // Remove play toggle if showing
149
-
150
-
151
- this.removeClass('show-play-toggle'); // Remove and readd class to trigger animation
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
- * Enables touch handler
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
- * Disables touch handler
226
+ * Monitor the touch end to determine a valid swipe
227
+ *
228
+ * @param {TouchEvent} e Triggering touch event
169
229
  */
170
- ;
171
-
172
- _proto.disable = function disable() {
173
- this.off('touchend', this.handleTap);
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
- return TouchOverlay;
177
- }(Component);
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
- iOS: false,
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
- var screen = window__default['default'].screen;
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
- var orientationString = ((screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation || '').split('-')[0];
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
- } // iOS only supports window.orientation
212
-
313
+ }
213
314
 
214
- if (typeof window__default['default'].orientation === 'number') {
215
- if (window__default['default'].orientation === 0 || window__default['default'].orientation === 180) {
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
- }; // Cross-compatibility for Video.js 5 and 6.
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 {Object} [options={}]
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
- } // Insert before the control bar
257
-
340
+ }
258
341
 
259
- var controlBarIdx;
260
- var versionParts = videojs__default['default'].VERSION.split('.');
261
- var major = parseInt(versionParts[0], 10);
262
- var minor = parseInt(versionParts[1], 10); // Video.js < 7.7.0 doesn't account for precedding components that don't have elements
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
- var locked = false;
278
-
279
- var rotationHandler = function rotationHandler() {
280
- var currentOrientation = getOrientation();
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() === false) {
284
- player.requestFullscreen();
285
-
286
- if (options.fullscreen.lockOnRotate && screen.orientation && screen.orientation.lock) {
287
- screen.orientation.lock('landscape').then(function () {
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(function (e) {
290
- videojs__default['default'].log('Browser refused orientation lock:', e);
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['default'].browser.IS_IOS) {
303
- window__default['default'].addEventListener('orientationchange', rotationHandler);
304
- player.on('dispose', function () {
305
- window__default['default'].removeEventListener('orientationchange', rotationHandler);
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', function () {
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
- player.on('ended', function (_) {
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
- * A video.js plugin.
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
- var mobileUi = function mobileUi(options) {
368
- var _this = this;
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
- }; // Register the plugin with video.js.
380
-
430
+ };
381
431
 
382
- registerPlugin('mobileUi', mobileUi); // Include the version number.
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.7.0 @license MIT */
2
- @-webkit-keyframes fadeAndScale{0%,to{opacity:0}25%{opacity:1}}@keyframes fadeAndScale{0%,to{opacity:0}25%{opacity:1}}.video-js.vjs-has-started .vjs-touch-overlay{position:absolute;pointer-events:auto;top:0}.video-js .vjs-touch-overlay{display:block;width:100%;height:100%;pointer-events:none}.video-js .vjs-touch-overlay.skip{opacity:0;-webkit-animation:fadeAndScale .6s linear;animation:fadeAndScale .6s 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-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-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-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-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-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-touch-overlay.show-play-toggle .vjs-play-control{opacity:1;pointer-events:auto}.video-js.vjs-mobile-ui-disable-end.vjs-ended .vjs-touch-overlay{display:none}
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}