TheDJ has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/258359

Change subject: Make controlbar layout depend on the player width
......................................................................

Make controlbar layout depend on the player width

Uses a new videojs plugin to apply layout classes depending on the
width of the player. As fewer width is available, controls like
time remaining, fullscreen or progress are dropped from the layout.

Bug: T119049
Change-Id: I60307f1ccd5300359920c4ce6e63144eece2e75d
---
M Gruntfile.js
M TimedMediaHandler.hooks.php
M package.json
M resources/ext.tmh.player.js
A resources/videojs-responsive-layout/videojs-responsive-layout.js
A resources/videojs-responsive-layout/videojs-responsive-layout.min.js
6 files changed, 515 insertions(+), 3 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/TimedMediaHandler 
refs/changes/59/258359/1

diff --git a/Gruntfile.js b/Gruntfile.js
index 04ffaa2..2f60a17 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -35,7 +35,7 @@
                },
                exec: {
                        'npm-update-videojs': {
-                               cmd: 'npm update video.js 
videojs-resolution-switcher',
+                               cmd: 'npm update video.js 
videojs-resolution-switcher videojs-responsive-layout',
                                callback: function ( error, stdout, stderr ) {
                                        grunt.log.write( stdout );
                                        if ( stderr ) {
@@ -68,6 +68,12 @@
                                cwd: 
'node_modules/videojs-resolution-switcher/lib/',
                                src: [ '**' ],
                                dest: 'resources/videojs-resolution-switcher/'
+                       },
+                       'videojs-responsive-layout': {
+                               expand: true,
+                               cwd: 
'node_modules/videojs-responsive-layout/dist/',
+                               src: [ '**' ],
+                               dest: 'resources/videojs-responsive-layout/'
                        }
                },
                patch: {
@@ -83,7 +89,7 @@
                }
        } );
 
-       grunt.registerTask( 'update-videojs', [ 'exec:npm-update-videojs', 
'copy:video.js', 'copy:videojs-resolution-switcher', 'patch:video.js' ] );
+       grunt.registerTask( 'update-videojs', [ 'exec:npm-update-videojs', 
'copy:video.js', 'copy:videojs-resolution-switcher', 
'copy:videojs-responsive-layout', 'patch:video.js' ] );
        grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] 
);
        grunt.registerTask( 'default', 'test' );
 };
diff --git a/TimedMediaHandler.hooks.php b/TimedMediaHandler.hooks.php
index e234930..3174622 100644
--- a/TimedMediaHandler.hooks.php
+++ b/TimedMediaHandler.hooks.php
@@ -210,12 +210,20 @@
                                                'ext.tmh.video-js',
                                        ),
                                 ),
+                               'ext.tmh.videojs-responsive-layout' => 
$baseExtensionResource + array(
+                                       'scripts' => 
'resources/videojs-responsive-layout/videojs-responsive-layout.js',
+                                       'targets' => array( 'mobile', 'desktop' 
),
+                                       'dependencies' => array(
+                                               'ext.tmh.video-js',
+                                       ),
+                                ),
                                'ext.tmh.player' => $baseExtensionResource + 
array(
                                        'scripts' => 
'resources/ext.tmh.player.js',
                                        'targets' => array( 'mobile', 'desktop' 
),
                                        'dependencies' => array(
                                                'ext.tmh.video-js',
                                                
'ext.tmh.videojs-resolution-switcher',
+                                               
'ext.tmh.videojs-responsive-layout',
                                                // 'ext.tmh.videojs-offset',
                                        ),
                                ),
diff --git a/package.json b/package.json
index cb4b116..b620925 100644
--- a/package.json
+++ b/package.json
@@ -16,5 +16,9 @@
     "jscs-preset-wikimedia": "~1.0.0",
     "video.js": "^5.3.0",
     "videojs-resolution-switcher": "^0.2.2"
+  },
+  "dependencies": {
+    "videojs-resolution-switcher": "^0.2.2",
+    "videojs-responsive-layout": "^1.0.0"
   }
 }
diff --git a/resources/ext.tmh.player.js b/resources/ext.tmh.player.js
index 8766b7a..53bed57 100755
--- a/resources/ext.tmh.player.js
+++ b/resources/ext.tmh.player.js
@@ -16,7 +16,8 @@
                plugins: {
                        videoJsResolutionSwitcher: {
                                sourceOrder: true
-                       }
+                       },
+                       responsiveLayout: {}
                }
        };
 
diff --git a/resources/videojs-responsive-layout/videojs-responsive-layout.js 
b/resources/videojs-responsive-layout/videojs-responsive-layout.js
new file mode 100644
index 0000000..10178a3
--- /dev/null
+++ b/resources/videojs-responsive-layout/videojs-responsive-layout.js
@@ -0,0 +1,486 @@
+/**
+ * videojs-responsive-layout
+ * @version 1.0.0
+ * @copyright 2015 Derk-Jan Hartman
+ * @license (MIT OR Apache-2.0)
+ */
+(function(f){if(typeof exports==="object"&&typeof 
module!=="undefined"){module.exports=f()}else if(typeof 
define==="function"&&define.amd){define([],f)}else{var g;if(typeof 
window!=="undefined"){g=window}else if(typeof 
global!=="undefined"){g=global}else if(typeof 
self!=="undefined"){g=self}else{g=this}g.videojsResponsiveLayout = 
f()}})(function(){var define,module,exports;return (function e(t,n,r){function 
s(o,u){if(!n[o]){if(!t[o]){var a=typeof 
require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var 
f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var 
l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return 
s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof 
require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return 
s})({1:[function(require,module,exports){
+
+},{}],2:[function(require,module,exports){
+var throttle = require('./throttle');
+
+/**
+ * Debounce execution of a function. Debouncing, unlike throttling,
+ * guarantees that a function is only executed a single time, either at the
+ * very beginning of a series of calls, or at the very end.
+ *
+ * @param  {Number}   delay         A zero-or-greater delay in milliseconds. 
For event callbacks, values around 100 or 250 (or even higher) are most useful.
+ * @param  {Boolean}  atBegin       Optional, defaults to false. If atBegin is 
false or unspecified, callback will only be executed `delay` milliseconds
+ *                                  after the last debounced-function call. If 
atBegin is true, callback will be executed only at the first debounced-function 
call.
+ *                                  (After the throttled-function has not been 
called for `delay` milliseconds, the internal counter is reset).
+ * @param  {Function} callback      A function to be executed after delay 
milliseconds. The `this` context and all arguments are passed through, as-is,
+ *                                  to `callback` when the debounced-function 
is executed.
+ *
+ * @return {Function} A new, debounced function.
+ */
+module.exports = function ( delay, atBegin, callback ) {
+       return callback === undefined ? throttle(delay, atBegin, false) : 
throttle(delay, callback, atBegin !== false);
+};
+
+},{"./throttle":4}],3:[function(require,module,exports){
+module.exports = {
+       throttle: require('./throttle'),
+       debounce: require('./debounce')
+};
+
+},{"./debounce":2,"./throttle":4}],4:[function(require,module,exports){
+var $ = require('jquery');
+
+/**
+ * Throttle execution of a function. Especially useful for rate limiting
+ * execution of handlers on events like resize and scroll.
+ *
+ * @param  {Number}    delay          A zero-or-greater delay in milliseconds. 
For event callbacks, values around 100 or 250 (or even higher) are most useful.
+ * @param  {Boolean}   noTrailing     Optional, defaults to false. If 
noTrailing is true, callback will only execute every `delay` milliseconds while 
the
+ *                                    throttled-function is being called. If 
noTrailing is false or unspecified, callback will be executed one final time
+ *                                    after the last throttled-function call. 
(After the throttled-function has not been called for `delay` milliseconds,
+ *                                    the internal counter is reset)
+ * @param  {Function}  callback       A function to be executed after delay 
milliseconds. The `this` context and all arguments are passed through, as-is,
+ *                                    to `callback` when the 
throttled-function is executed.
+ * @param  {Boolean}   debounceMode   If `debounceMode` is true (at begin), 
schedule `clear` to execute after `delay` ms. If `debounceMode` is false (at 
end),
+ *                                    schedule `callback` to execute after 
`delay` ms.
+ *
+ * @return {Function}  A new, throttled, function.
+ */
+module.exports = function ( delay, noTrailing, callback, debounceMode ) {
+
+       // After wrapper has stopped being called, this timeout ensures that
+       // `callback` is executed at the proper times in `throttle` and `end`
+       // debounce modes.
+       var timeoutID;
+
+       // Keep track of the last time `callback` was executed.
+       var lastExec = 0;
+
+       // `noTrailing` defaults to falsy.
+       if ( typeof(noTrailing) !== 'boolean' ) {
+               debounceMode = callback;
+               callback = noTrailing;
+               noTrailing = undefined;
+       }
+
+       // The `wrapper` function encapsulates all of the throttling / 
debouncing
+       // functionality and when executed will limit the rate at which 
`callback`
+       // is executed.
+       function wrapper () {
+
+               var self = this;
+               var elapsed = Number(new Date()) - lastExec;
+               var args = arguments;
+
+               // Execute `callback` and update the `lastExec` timestamp.
+               function exec () {
+                       lastExec = Number(new Date());
+                       callback.apply(self, args);
+               }
+
+               // If `debounceMode` is true (at begin) this is used to clear 
the flag
+               // to allow future `callback` executions.
+               function clear () {
+                       timeoutID = undefined;
+               }
+
+               if ( debounceMode && !timeoutID ) {
+                       // Since `wrapper` is being called for the first time 
and
+                       // `debounceMode` is true (at begin), execute 
`callback`.
+                       exec();
+               }
+
+               // Clear any existing timeout.
+               if ( timeoutID ) {
+                       clearTimeout(timeoutID);
+               }
+
+               if ( debounceMode === undefined && elapsed > delay ) {
+                       // In throttle mode, if `delay` time has been exceeded, 
execute
+                       // `callback`.
+                       exec();
+
+               } else if ( noTrailing !== true ) {
+                       // In trailing throttle mode, since `delay` time has 
not been
+                       // exceeded, schedule `callback` to execute `delay` ms 
after most
+                       // recent execution.
+                       //
+                       // If `debounceMode` is true (at begin), schedule 
`clear` to execute
+                       // after `delay` ms.
+                       //
+                       // If `debounceMode` is false (at end), schedule 
`callback` to
+                       // execute after `delay` ms.
+                       timeoutID = setTimeout(debounceMode ? clear : exec, 
debounceMode === undefined ? delay - elapsed : delay);
+               }
+
+       }
+
+       // Set the guid of `wrapper` function to the same of original callback, 
so
+       // it can be removed in jQuery 1.4+ .unbind or .die by using the 
original
+       // callback as a reference.
+       if ( $ && $.guid ) {
+               wrapper.guid = callback.guid = callback.guid || $.guid++;
+       }
+
+       // Return the wrapper function.
+       return wrapper;
+
+};
+
+},{"jquery":1}],5:[function(require,module,exports){
+(function (global){
+/* jshint esnext:true */
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+  value: true
+});
+
+var _createClass = (function () { function defineProperties(target, props) { 
for (var i = 0; i < props.length; i++) { var descriptor = props[i]; 
descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable 
= true; if ('value' in descriptor) descriptor.writable = true; 
Object.defineProperty(target, descriptor.key, descriptor); } } return function 
(Constructor, protoProps, staticProps) { if (protoProps) 
defineProperties(Constructor.prototype, protoProps); if (staticProps) 
defineProperties(Constructor, staticProps); return Constructor; }; })();
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 
'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof 
Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+
+var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof 
global !== "undefined" ? global['videojs'] : null);
+
+var _videoJs2 = _interopRequireDefault(_videoJs);
+
+var debounce = require('throttle-debounce').debounce;
+
+// Default options for the plugin.
+var defaults = {
+  debounceDelay: 400
+};
+
+/**
+ * Retrieve the outerWidth of an element, including margins
+ *
+ * @function getElementOuterWidth
+ * @param    {Element} el to measure
+ * @return   {number} the width of the element in pixels
+ */
+var _getElementOuterWidth = function _getElementOuterWidth(el) {
+  var width = el.offsetWidth;
+  var style = getComputedStyle(el);
+
+  width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
+  return width;
+};
+
+/**
+ * Retrieve the width an element
+ *
+ * @function getElementWidth
+ * @param    {Element} el to measure
+ * @return   {number} the width of the element in pixels
+ */
+var _getElementWidth = function _getElementWidth(el) {
+  return parseInt(getComputedStyle(el).width, 10);
+};
+
+/**
+ * Check if an element is currently visible.
+ *
+ * Use this to filter on elements that should be taken into account during 
calculations.
+ *
+ * @function isElementVisible
+ * @param    {Element} el to test
+ * @return   {boolean} true if el is visible
+ */
+var _isElementVisible = function _isElementVisible(el) {
+  return el.offsetWidth > 0 || el.offsetHeight > 0;
+};
+
+/**
+ * Set a video.js layout class on an element
+ *
+ * A layout can be: vjs-layout-tiny, vjs-layout-x-small, vjs-layout-small.
+ * Anything else will reset back to defaults
+ *
+ * @function setVideoJsLayout
+ * @param    {Player} player to apply the layout to
+ * @param    {string} layoutClass name of the class to be set
+ * @return   {boolean} true if el is visible
+ */
+var setVideoJsLayout = function setVideoJsLayout(player, layoutClass) {
+  var el = player.el();
+
+  if (layoutClass === 'vjs-layout-tiny') {
+    _videoJs2['default'].addClass(el, 'vjs-layout-tiny');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-small');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-x-small');
+  } else if (layoutClass === 'vjs-layout-x-small') {
+    _videoJs2['default'].addClass(el, 'vjs-layout-x-small');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-tiny');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-small');
+  } else if (layoutClass === 'vjs-layout-small') {
+    _videoJs2['default'].addClass(el, 'vjs-layout-small');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-tiny');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-x-small');
+  } else {
+    _videoJs2['default'].removeClass(el, 'vjs-layout-tiny');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-x-small');
+    _videoJs2['default'].removeClass(el, 'vjs-layout-small');
+  }
+};
+
+var makeBigger = function makeBigger(player) {
+  var el = player.el();
+
+  if (_videoJs2['default'].hasClass(el, 'vjs-layout-tiny')) {
+    setVideoJsLayout(player, 'vjs-layout-x-small');
+  } else if (_videoJs2['default'].hasClass(el, 'vjs-layout-x-small')) {
+    setVideoJsLayout(player, 'vjs-layout-small');
+  } else if (_videoJs2['default'].hasClass(el, 'vjs-layout-small')) {
+    setVideoJsLayout(player, 'default');
+  } else {
+    return;
+  }
+  player.trigger('resize');
+};
+
+var makeSmaller = function makeSmaller(player) {
+  var el = player.el();
+
+  if (_videoJs2['default'].hasClass(el, 'vjs-layout-tiny')) {
+    return;
+  } else if (_videoJs2['default'].hasClass(el, 'vjs-layout-x-small')) {
+    setVideoJsLayout(player, 'vjs-layout-tiny');
+  } else if (_videoJs2['default'].hasClass(el, 'vjs-layout-small')) {
+    setVideoJsLayout(player, 'vjs-layout-x-small');
+  } else {
+    setVideoJsLayout(player, 'vjs-layout-small');
+  }
+  player.trigger('resize');
+};
+
+var updateVideoJsLayout = function updateVideoJsLayout(layouter, playerWidth, 
controlBarWidth, controlWidth) {
+  var progressWidth = 
_getElementOuterWidth(layouter.el.querySelectorAll('.vjs-progress-control')[0]);
+
+  if (controlBarWidth > playerWidth) {
+    makeSmaller(layouter.player);
+  } else if ((_videoJs2['default'].hasClass(layouter.el, 'vjs-layout-x-small') 
|| _videoJs2['default'].hasClass(layouter.el, 'vjs-layout-small')) &&
+  // progressbar more that twice it's default size
+  progressWidth > controlWidth * 2) {
+    makeBigger(layouter.player);
+  } else if (playerWidth > controlBarWidth + controlWidth && 
!_videoJs2['default'].hasClass(layouter.el, 'vjs-layout-x-small') && 
!_videoJs2['default'].hasClass(layouter.el, 'vjs-layout-small')) {
+    makeBigger(layouter.player);
+  }
+};
+
+var dimensionsCheck = function dimensionsCheck() {
+  if (!this.el) {
+    return;
+  }
+  var playerWidth = this.getPlayerWidth();
+  var controlWidth = this.getControlWidth();
+  var controlBarWidth = this.getControlBarWidth();
+
+  if (this.options.updateVideoJsLayout) {
+    this.options.updateVideoJsLayout(this, playerWidth, controlBarWidth, 
controlWidth);
+  } else {
+    updateVideoJsLayout(this, playerWidth, controlBarWidth, controlWidth);
+  }
+};
+
+var installStylesheet = function installStylesheet() {
+  var style = document.getElementById('vjs-responsive-layout');
+
+  if (!style) {
+    var styleRule = '\n      .vjs-responsive-layout .vjs-progress-control {\n  
      min-width: 4em;\n      }\n    ';
+    var head = document.getElementsByTagName('head')[0];
+
+    style = document.createElement('style');
+    style.id = 'vjs-responsive-layout';
+
+    if (style.styleSheet) {
+      style.styleSheet.cssText = styleRule;
+    } else {
+      style.textContent = styleRule;
+    }
+    head.insertBefore(style, head.firstChild);
+  }
+};
+
+var Layouter = (function () {
+  function Layouter(player, options) {
+    _classCallCheck(this, Layouter);
+
+    this.player_ = player;
+    this.options_ = options;
+    this.debouncedCheckSize_ = debounce(options.debounceDelay, 
dimensionsCheck);
+  }
+
+  /**
+   * A video.js plugin.
+   *
+   * In the plugin function, the value of `this` is a video.js `Player`
+   * instance. You cannot rely on the player being in a "ready" state here,
+   * depending on how the plugin is invoked. This may or may not be important
+   * to you; if not, remove the wait for "ready"!
+   *
+   * @function responsiveLayout
+   * @param    {Object} [options={}]
+   *           An object of options left to the plugin author to define.
+   */
+
+  _createClass(Layouter, [{
+    key: 'ready',
+    value: function ready() {
+      var _this = this;
+
+      installStylesheet();
+      this.player.addClass('vjs-responsive-layout');
+
+      this.windowResizeListener_ = window.addEventListener('resize', function 
() {
+        return _this.debouncedCheckSize_();
+      });
+
+      this.player.on(['play', 'resize'], function () {
+        return _this.debouncedCheckSize_();
+      });
+      this.player.on('dispose', function () {
+        window.removeEventListener('resize', this.windowResizeListener_);
+      });
+
+      // Let's do the first measure
+      this.player.trigger('resize');
+    }
+
+    /**
+     * Retrieve player to which this Layouter object belongs
+     *
+     * @property player
+     * @return   {number} the width of the controlbar in pixels
+     */
+  }, {
+    key: 'getControlWidth',
+
+    /**
+     * Retrieve current width of a control in the video.js controlbar
+     *
+     * This function relies on the presence of the play control. If you
+     * mess with it's visibility, things likely will break :)
+     *
+     * @function getControlBarWidth
+     * @return   {number} the width of the controlbar in pixels
+     */
+    value: function getControlWidth() {
+      return 
_getElementOuterWidth(this.el.querySelectorAll('.vjs-play-control')[0]);
+    }
+
+    /**
+     * Retrieve current width of the video.js controlbar
+     *
+     * @function getControlBarWidth
+     * @return   {number} the width of the controlbar in pixels
+     */
+  }, {
+    key: 'getControlBarWidth',
+    value: function getControlBarWidth() {
+      var controlBarWidth = 0;
+      var cbElements = this.el.querySelectorAll('.vjs-control-bar > *');
+
+      Array.from(cbElements).forEach(function (el) {
+        if (_isElementVisible(el)) {
+          controlBarWidth += _getElementOuterWidth(el);
+        }
+      });
+      return controlBarWidth;
+    }
+
+    /**
+     * Retrieve current width of the video.js player element
+     *
+     * @function getPlayerWidth
+     * @return   {number} the width of the player in pixels
+     */
+  }, {
+    key: 'getPlayerWidth',
+    value: function getPlayerWidth() {
+      return _getElementWidth(this.el);
+    }
+
+    /**
+     * Retrieve the outerWidth of an element, including margins
+     *
+     * @function outerWidth
+     * @param    {Element} el to measure
+     * @return   {number} the width of the element in pixels
+     */
+  }, {
+    key: 'player',
+    get: function get() {
+      return this.player_;
+    }
+  }, {
+    key: 'el',
+    get: function get() {
+      return this.player_.el();
+    }
+  }, {
+    key: 'options',
+    get: function get() {
+      return this.options_;
+    }
+  }], [{
+    key: 'getElementOuterWidth',
+    value: function getElementOuterWidth(el) {
+      return _getElementOuterWidth(el);
+    }
+
+    /**
+     * Retrieve the width an element
+     *
+     * @function getElementWidth
+     * @param    {Element} el to measure
+     * @return   {number} the width of the element in pixels
+     */
+  }, {
+    key: 'getElementWidth',
+    value: function getElementWidth(el) {
+      return _getElementWidth(el);
+    }
+
+    /**
+     * Check if an element is currently visible.
+     *
+     * Use this to filter on elements that should be taken into account during 
calculations.
+     *
+     * @function isElementVisible
+     * @param    {Element} el to test
+     * @return   {boolean} true if el is visible
+     */
+  }, {
+    key: 'isElementVisible',
+    value: function isElementVisible(el) {
+      return _isElementVisible(el);
+    }
+  }]);
+
+  return Layouter;
+})();
+
+var responsiveLayout = function responsiveLayout(options) {
+  var layout = new Layouter(this, _videoJs2['default'].mergeOptions(defaults, 
options));
+
+  this.ready(function () {
+    layout.ready();
+  });
+};
+
+// Register the plugin with video.js.
+_videoJs2['default'].plugin('responsiveLayout', responsiveLayout);
+
+exports['default'] = responsiveLayout;
+module.exports = exports['default'];
+}).call(this,typeof global !== "undefined" ? global : typeof self !== 
"undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"throttle-debounce":3}]},{},[5])(5)
+});
\ No newline at end of file
diff --git 
a/resources/videojs-responsive-layout/videojs-responsive-layout.min.js 
b/resources/videojs-responsive-layout/videojs-responsive-layout.min.js
new file mode 100644
index 0000000..f80aba3
--- /dev/null
+++ b/resources/videojs-responsive-layout/videojs-responsive-layout.min.js
@@ -0,0 +1,7 @@
+/**
+ * videojs-responsive-layout
+ * @version 1.0.0
+ * @copyright 2015 Derk-Jan Hartman
+ * @license (MIT OR Apache-2.0)
+ */
+!function(e){if("object"==typeof exports&&"undefined"!=typeof 
module)module.exports=e();else if("function"==typeof 
define&&define.amd)define([],e);else{var t;t="undefined"!=typeof 
window?window:"undefined"!=typeof global?global:"undefined"!=typeof 
self?self:this,t.videojsResponsiveLayout=e()}}(function(){return function 
e(t,n,l){function o(a,r){if(!n[a]){if(!t[a]){var u="function"==typeof 
require&&require;if(!r&&u)return u(a,!0);if(s)return s(a,!0);var i=new 
Error("Cannot find module '"+a+"'");throw i.code="MODULE_NOT_FOUND",i}var 
f=n[a]={exports:{}};t[a][0].call(f.exports,function(e){var n=t[a][1][e];return 
o(n?n:e)},f,f.exports,e,t,n,l)}return n[a].exports}for(var s="function"==typeof 
require&&require,a=0;a<l.length;a++)o(l[a]);return 
o}({1:[function(e,t,n){},{}],2:[function(e,t,n){var 
l=e("./throttle");t.exports=function(e,t,n){return void 
0===n?l(e,t,!1):l(e,n,t!==!1)}},{"./throttle":4}],3:[function(e,t,n){t.exports={throttle:e("./throttle"),debounce:e("./debounce")}},{"./debounce":2,"./throttle":4}],4:[function(e,t,n){var
 l=e("jquery");t.exports=function(e,t,n,o){function s(){function 
l(){r=Number(new Date),n.apply(u,f)}function s(){a=void 0}var 
u=this,i=Number(new Date)-r,f=arguments;o&&!a&&l(),a&&clearTimeout(a),void 
0===o&&i>e?l():t!==!0&&(a=setTimeout(o?s:l,void 0===o?e-i:e))}var 
a,r=0;return"boolean"!=typeof t&&(o=n,n=t,t=void 
0),l&&l.guid&&(s.guid=n.guid=n.guid||l.guid++),s}},{jquery:1}],5:[function(e,t,n){(function(l){"use
 strict";function o(e){return e&&e.__esModule?e:{"default":e}}function 
s(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a 
function")}Object.defineProperty(n,"__esModule",{value:!0});var 
a=function(){function e(e,t){for(var n=0;n<t.length;n++){var 
l=t[n];l.enumerable=l.enumerable||!1,l.configurable=!0,"value"in 
l&&(l.writable=!0),Object.defineProperty(e,l.key,l)}}return 
function(t,n,l){return 
n&&e(t.prototype,n),l&&e(t,l),t}}(),r="undefined"!=typeof 
window?window.videojs:"undefined"!=typeof 
l?l.videojs:null,u=o(r),i=e("throttle-debounce").debounce,f={debounceDelay:400},d=function(e){var
 t=e.offsetWidth,n=getComputedStyle(e);return 
t+=parseInt(n.marginLeft,10)+parseInt(n.marginRight,10)},y=function(e){return 
parseInt(getComputedStyle(e).width,10)},v=function(e){return 
e.offsetWidth>0||e.offsetHeight>0},c=function(e,t){var 
n=e.el();"vjs-layout-tiny"===t?(u["default"].addClass(n,"vjs-layout-tiny"),u["default"].removeClass(n,"vjs-layout-small"),u["default"].removeClass(n,"vjs-layout-x-small")):"vjs-layout-x-small"===t?(u["default"].addClass(n,"vjs-layout-x-small"),u["default"].removeClass(n,"vjs-layout-tiny"),u["default"].removeClass(n,"vjs-layout-small")):"vjs-layout-small"===t?(u["default"].addClass(n,"vjs-layout-small"),u["default"].removeClass(n,"vjs-layout-tiny"),u["default"].removeClass(n,"vjs-layout-x-small")):(u["default"].removeClass(n,"vjs-layout-tiny"),u["default"].removeClass(n,"vjs-layout-x-small"),u["default"].removeClass(n,"vjs-layout-small"))},h=function(e){var
 
t=e.el();if(u["default"].hasClass(t,"vjs-layout-tiny"))c(e,"vjs-layout-x-small");else
 
if(u["default"].hasClass(t,"vjs-layout-x-small"))c(e,"vjs-layout-small");else{if(!u["default"].hasClass(t,"vjs-layout-small"))return;c(e,"default")}e.trigger("resize")},p=function(e){var
 
t=e.el();u["default"].hasClass(t,"vjs-layout-tiny")||(u["default"].hasClass(t,"vjs-layout-x-small")?c(e,"vjs-layout-tiny"):u["default"].hasClass(t,"vjs-layout-small")?c(e,"vjs-layout-x-small"):c(e,"vjs-layout-small"),e.trigger("resize"))},m=function(e,t,n,l){var
 
o=d(e.el.querySelectorAll(".vjs-progress-control")[0]);n>t?p(e.player):(u["default"].hasClass(e.el,"vjs-layout-x-small")||u["default"].hasClass(e.el,"vjs-layout-small"))&&o>2*l?h(e.player):t>n+l&&!u["default"].hasClass(e.el,"vjs-layout-x-small")&&!u["default"].hasClass(e.el,"vjs-layout-small")&&h(e.player)},j=function(){if(this.el){var
 
e=this.getPlayerWidth(),t=this.getControlWidth(),n=this.getControlBarWidth();this.options.updateVideoJsLayout?this.options.updateVideoJsLayout(this,e,n,t):m(this,e,n,t)}},g=function(){var
 e=document.getElementById("vjs-responsive-layout");if(!e){var t="\n      
.vjs-responsive-layout .vjs-progress-control {\n        min-width: 4em;\n      
}\n    
",n=document.getElementsByTagName("head")[0];e=document.createElement("style"),e.id="vjs-responsive-layout",e.styleSheet?e.styleSheet.cssText=t:e.textContent=t,n.insertBefore(e,n.firstChild)}},C=function(){function
 
e(t,n){s(this,e),this.player_=t,this.options_=n,this.debouncedCheckSize_=i(n.debounceDelay,j)}return
 a(e,[{key:"ready",value:function(){var 
e=this;g(),this.player.addClass("vjs-responsive-layout"),this.windowResizeListener_=window.addEventListener("resize",function(){return
 e.debouncedCheckSize_()}),this.player.on(["play","resize"],function(){return 
e.debouncedCheckSize_()}),this.player.on("dispose",function(){window.removeEventListener("resize",this.windowResizeListener_)}),this.player.trigger("resize")}},{key:"getControlWidth",value:function(){return
 
d(this.el.querySelectorAll(".vjs-play-control")[0])}},{key:"getControlBarWidth",value:function(){var
 e=0,t=this.el.querySelectorAll(".vjs-control-bar > *");return 
Array.from(t).forEach(function(t){v(t)&&(e+=d(t))}),e}},{key:"getPlayerWidth",value:function(){return
 y(this.el)}},{key:"player",get:function(){return 
this.player_}},{key:"el",get:function(){return 
this.player_.el()}},{key:"options",get:function(){return 
this.options_}}],[{key:"getElementOuterWidth",value:function(e){return 
d(e)}},{key:"getElementWidth",value:function(e){return 
y(e)}},{key:"isElementVisible",value:function(e){return 
v(e)}}]),e}(),w=function(e){var t=new 
C(this,u["default"].mergeOptions(f,e));this.ready(function(){t.ready()})};u["default"].plugin("responsiveLayout",w),n["default"]=w,t.exports=n["default"]}).call(this,"undefined"!=typeof
 global?global:"undefined"!=typeof self?self:"undefined"!=typeof 
window?window:{})},{"throttle-debounce":3}]},{},[5])(5)});
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/258359
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I60307f1ccd5300359920c4ce6e63144eece2e75d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/TimedMediaHandler
Gerrit-Branch: master
Gerrit-Owner: TheDJ <hartman.w...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to