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 <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits