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.
@@ -1,21 +1,22 @@
1
- /*! @name videojs-mobile-ui @version 0.7.0 @license MIT */
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.7.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
- function TouchOverlay(player, options) {
29
- var _this;
30
-
31
- _this = _Component.call(this, player, options) || this;
32
- _this.seekSeconds = options.seekSeconds;
33
- _this.tapTimeout = options.tapTimeout; // Add play toggle overlay
34
-
35
- _this.addChild('playToggle', {}); // Clear overlay when playback starts or with control fade
36
-
37
-
38
- player.on(['playing', 'userinactive'], function (e) {
39
- _this.removeClass('show-play-toggle');
40
- }); // A 0 inactivity timeout won't work here
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
- if (_this.player_.options_.inactivityTimeout === 0) {
43
- _this.player_.options_.inactivityTimeout = 5000;
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
- _this.enable();
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
- return _this;
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.firstTapCaptured) {
88
- this.firstTapCaptured = false;
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
- var defaults = {
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
- iOS: false,
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
- var screen = window.screen;
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
- var getOrientation = function getOrientation() {
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
- var orientationString = ((screen.orientation || {}).type || screen.mozOrientation || screen.msOrientation || '').split('-')[0];
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
- } // iOS only supports window.orientation
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
- }; // Cross-compatibility for Video.js 5 and 6.
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
- var locked = false;
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
- if (options.fullscreen.lockOnRotate && screen.orientation && screen.orientation.lock) {
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(function (e) {
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', function () {
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', function () {
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
- player.on('ended', function (_) {
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(function () {
368
- onPlayerReady(_this, videojs.mergeOptions(defaults, options));
301
+ this.ready(() => {
302
+ onPlayerReady(this, videojs.obj.merge(defaults, options));
369
303
  });
370
304
  }
371
- }; // Register the plugin with video.js.
372
-
305
+ };
373
306
 
374
- registerPlugin('mobileUi', mobileUi); // Include the version number.
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;