TheDJ has uploaded a new change for review.

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

Change subject: Add the videojs-ogvjs Tech module
......................................................................

Add the videojs-ogvjs Tech module

This enables video.js playback using ogv.js on Safari and older IE
browsers

Bug: T119048
Change-Id: Ie511c145b9d16be1d234645e69b8c81665448ef9
---
M Gruntfile.js
M TimedMediaHandler.hooks.php
M package.json
M resources/ext.tmh.player.js
A resources/videojs-ogvjs/videojs-ogvjs.js
A resources/videojs-ogvjs/videojs-ogvjs.min.js
6 files changed, 814 insertions(+), 21 deletions(-)


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

diff --git a/Gruntfile.js b/Gruntfile.js
index 04ffaa2..e978e49 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-ogvjs',
                                callback: function ( error, stdout, stderr ) {
                                        grunt.log.write( stdout );
                                        if ( stderr ) {
@@ -63,6 +63,12 @@
                                ],
                                dest: 'resources/videojs/'
                        },
+                       'videojs-ogvjs': {
+                               expand: true,
+                               cwd: 'node_modules/videojs-ogvjs/dist/',
+                               src: [ '**' ],
+                               dest: 'resources/videojs-ogvjs/'
+                       },
                        'videojs-resolution-switcher': {
                                expand: true,
                                cwd: 
'node_modules/videojs-resolution-switcher/lib/',
@@ -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-ogvjs', 
'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..d7ba13f 100644
--- a/TimedMediaHandler.hooks.php
+++ b/TimedMediaHandler.hooks.php
@@ -93,7 +93,22 @@
                        ),
                        'ext.tmh.TimedTextSelector' =>  $baseExtensionResource 
+ array(
                                'scripts' => 
'resources/ext.tmh.TimedTextSelector.js',
-                       )
+                       ),
+                       // Add OgvJs-related modules for Safari/IE/Edge Ogg 
playback
+                               'ext.tmh.OgvJsSupport' => 
$baseExtensionResource + array(
+                                       'scripts' => array(
+                                               
'MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js',
+                                               
'resources/ext.tmh.OgvJsSupport.js',
+                                       ),
+                                       'targets' => array( 'mobile', 'desktop' 
),
+                               ),
+                               'ext.tmh.OgvJs' => $baseExtensionResource + 
array(
+                                       'scripts' => array(
+                                               
'MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js',
+                                       ),
+                                       'dependencies' => 
'ext.tmh.OgvJsSupport',
+                                       'targets' => array( 'mobile', 'desktop' 
),
+                               ),
                );
 
                if ( $wgTmhWebPlayer === 'mwembed' ) {
@@ -144,23 +159,6 @@
                                        'position' => 'top',
                                ),
                        );
-                       // Add OgvJs-related modules for Safari/IE/Edge Ogg 
playback
-                       $wgResourceModules += array(
-                               'ext.tmh.OgvJsSupport' => 
$baseExtensionResource + array(
-                                       'scripts' => array(
-                                               
'MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv-support.js',
-                                               
'resources/ext.tmh.OgvJsSupport.js',
-                                       ),
-                                       'targets' => array( 'mobile', 'desktop' 
),
-                               ),
-                               'ext.tmh.OgvJs' => $baseExtensionResource + 
array(
-                                       'scripts' => array(
-                                               
'MwEmbedModules/EmbedPlayer/binPlayers/ogv.js/ogv.js',
-                                       ),
-                                       'dependencies' => 
'ext.tmh.OgvJsSupport',
-                                       'targets' => array( 'mobile', 'desktop' 
),
-                               ),
-                       );
                } elseif ( $wgTmhWebPlayer === 'videojs' ) {
                        $wgResourceModules += array(
                                'ext.tmh.video-js' => $baseExtensionResource + 
array(
@@ -195,6 +193,14 @@
                                                'zh-TW' => 
'resources/videojs/lang/zh-TW.js',
                                        ),
                                ),
+                               'ext.tmh.videojs-ogvjs' => 
$baseExtensionResource + array(
+                                       'scripts' => 
'resources/videojs-ogvjs/videojs-ogvjs.js',
+                                       'targets' => array( 'mobile', 'desktop' 
),
+                                       'dependencies' => array(
+                                               'ext.tmh.video-js',
+                                               'ext.tmh.OgvJs',
+                                       ),
+                               ),
                                // 'ext.tmh.videojs-offset' => 
$baseExtensionResource + array(
                                        // 'scripts' => 
'resources/videojs-offset/videojs-offset.js',
                                        // 'targets' => array( 'mobile', 
'desktop' ),
@@ -215,6 +221,7 @@
                                        'targets' => array( 'mobile', 'desktop' 
),
                                        'dependencies' => array(
                                                'ext.tmh.video-js',
+                                               'ext.tmh.videojs-ogvjs',
                                                
'ext.tmh.videojs-resolution-switcher',
                                                // 'ext.tmh.videojs-offset',
                                        ),
diff --git a/package.json b/package.json
index d1282b1..21516b1 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
     "grunt-patch": "^0.1.7",
     "jscs-preset-wikimedia": "~1.0.0",
     "video.js": "^5.3.0",
+    "videojs-ogvjs": "^1.0.6",
     "videojs-resolution-switcher": "^0.2.2"
   }
 }
diff --git a/resources/ext.tmh.player.js b/resources/ext.tmh.player.js
index 8766b7a..7af02b7 100755
--- a/resources/ext.tmh.player.js
+++ b/resources/ext.tmh.player.js
@@ -12,11 +12,14 @@
                                inline: false
                        }
                },
-               techOrder: [ 'html5' ],
+               techOrder: [ 'html5', 'ogvjs' ],
                plugins: {
                        videoJsResolutionSwitcher: {
                                sourceOrder: true
                        }
+               },
+               ogvjs: {
+                       base: mw.OgvJsSupport.basePath()
                }
        };
 
diff --git a/resources/videojs-ogvjs/videojs-ogvjs.js 
b/resources/videojs-ogvjs/videojs-ogvjs.js
new file mode 100644
index 0000000..38d32dd
--- /dev/null
+++ b/resources/videojs-ogvjs/videojs-ogvjs.js
@@ -0,0 +1,769 @@
+/**
+ * videojs-ogvjs
+ * @version 1.0.6
+ * @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.videojsOgvjs = 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){
+(function (global){
+'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; }; })();
+
+var _get = function get(_x, _x2, _x3) { var _again = true; _function: while 
(_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if 
(object === null) object = Function.prototype; var desc = 
Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { 
var parent = Object.getPrototypeOf(object); if (parent === null) { return 
undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; 
desc = parent = undefined; continue _function; } } else if ('value' in desc) { 
return desc.value; } else { var getter = desc.get; if (getter === undefined) { 
return undefined; } return getter.call(receiver); } } };
+
+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'); } }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== 
'function' && superClass !== null) { throw new TypeError('Super expression must 
either be null or a function, not ' + typeof superClass); } subClass.prototype 
= Object.create(superClass && superClass.prototype, { constructor: { value: 
subClass, enumerable: false, writable: true, configurable: true } }); if 
(superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, 
superClass) : subClass.__proto__ = superClass; }
+
+var _videoJs = (typeof window !== "undefined" ? window['videojs'] : typeof 
global !== "undefined" ? global['videojs'] : null);
+
+var _videoJs2 = _interopRequireDefault(_videoJs);
+
+var _OGVCompat = (typeof window !== "undefined" ? window['OGVCompat'] : typeof 
global !== "undefined" ? global['OGVCompat'] : null);
+
+var _OGVCompat2 = _interopRequireDefault(_OGVCompat);
+
+var _OGVLoader = (typeof window !== "undefined" ? window['OGVLoader'] : typeof 
global !== "undefined" ? global['OGVLoader'] : null);
+
+var _OGVLoader2 = _interopRequireDefault(_OGVLoader);
+
+var _OGVPlayer = (typeof window !== "undefined" ? window['OGVPlayer'] : typeof 
global !== "undefined" ? global['OGVPlayer'] : null);
+
+var _OGVPlayer2 = _interopRequireDefault(_OGVPlayer);
+
+var Tech = _videoJs2['default'].getComponent('Tech');
+
+/**
+ * Ogvjs Media Controller - Wrapper for Ogvjs Media API
+ *
+ * @param {Object=} options Object of option names and values
+ * @param {Function=} ready Ready callback function
+ * @extends Tech
+ * @class Ogvjs
+ */
+
+var Ogvjs = (function (_Tech) {
+  _inherits(Ogvjs, _Tech);
+
+  function Ogvjs(options, ready) {
+    _classCallCheck(this, Ogvjs);
+
+    _get(Object.getPrototypeOf(Ogvjs.prototype), 'constructor', 
this).call(this, options, ready);
+
+    this.triggerReady();
+  }
+
+  /*
+   * Check if Ogvjs video is supported by this browser/device
+   *
+   * @return {Boolean}
+   */
+
+  /**
+   * Dispose of Ogvjs media element
+   *
+   * @method dispose
+   */
+
+  _createClass(Ogvjs, [{
+    key: 'dispose',
+    value: function dispose() {
+      // Ogvjs.disposeMediaElement(this.el_);
+      _get(Object.getPrototypeOf(Ogvjs.prototype), 'dispose', this).call(this);
+    }
+
+    /**
+     * Create the component's DOM element
+     *
+     * @return {Element}
+     * @method createEl
+     */
+  }, {
+    key: 'createEl',
+    value: function createEl() {
+      var options = this.options_;
+
+      if (options.base) {
+        _OGVLoader2['default'].base = options.base;
+      } else {
+        throw new Error('Please specify the base for the ogv.js library');
+      }
+
+      var el = new _OGVPlayer2['default'](options);
+
+      // simulate timeupdate events, needed for subtitles
+      // @todo switch this to native timeupdate event when available upstream
+      this.lastTime = 0;
+      el.addEventListener('framecallback', this.onFrameUpdate.bind(this));
+      el.src = this.options_.source.src;
+      el.className += ' vjs-tech';
+
+      return el;
+    }
+  }, {
+    key: 'onFrameUpdate',
+    value: function onFrameUpdate(event) {
+      var timeupdateInterval = 0.25;
+      var now = this.el_ ? this.el_.currentTime : this.lastTime;
+
+      // Don't spam time updates on every frame
+      if (Math.abs(now - this.lastTime) >= timeupdateInterval) {
+        this.lastTime = now;
+        this.trigger('timeupdate');
+        this.trigger('durationchange');
+      }
+    }
+
+    /**
+     * Play for Ogvjs tech
+     *
+     * @method play
+     */
+  }, {
+    key: 'play',
+    value: function play() {
+      this.el_.play();
+    }
+
+    /**
+     * Pause for Ogvjs tech
+     *
+     * @method pause
+     */
+  }, {
+    key: 'pause',
+    value: function pause() {
+      this.el_.pause();
+    }
+
+    /**
+     * Paused for Ogvjs tech
+     *
+     * @return {Boolean}
+     * @method paused
+     */
+  }, {
+    key: 'paused',
+    value: function paused() {
+      return this.el_.paused;
+    }
+
+    /**
+     * Get current time
+     *
+     * @return {Number}
+     * @method currentTime
+     */
+  }, {
+    key: 'currentTime',
+    value: function currentTime() {
+      return this.el_.currentTime;
+    }
+
+    /**
+     * Set current time
+     *
+     * @param {Number} seconds Current time of video
+     * @method setCurrentTime
+     */
+  }, {
+    key: 'setCurrentTime',
+    value: function setCurrentTime(seconds) {
+      try {
+        this.el_.currentTime = seconds;
+      } catch (e) {
+        _videoJs2['default'].log(e, 'Video is not ready. (Video.js)');
+      }
+    }
+
+    /**
+     * Get duration
+     *
+     * @return {Number}
+     * @method duration
+     */
+  }, {
+    key: 'duration',
+    value: function duration() {
+      return this.el_.duration || 0;
+    }
+
+    /**
+     * Get a TimeRange object that represents the intersection
+     * of the time ranges for which the user agent has all
+     * relevant media
+     *
+     * @return {TimeRangeObject}
+     * @method buffered
+     */
+  }, {
+    key: 'buffered',
+    value: function buffered() {
+      return this.el_.buffered;
+    }
+
+    /**
+     * Get volume level
+     *
+     * @return {Number}
+     * @method volume
+     */
+  }, {
+    key: 'volume',
+    value: function volume() {
+      return this.el_.volume ? this.el_.volume : 1;
+    }
+
+    /**
+     * Set volume level
+     *
+     * @param {Number} percentAsDecimal Volume percent as a decimal
+     * @method setVolume
+     */
+  }, {
+    key: 'setVolume',
+    value: function setVolume(percentAsDecimal) {
+      if (this.el_.volume) {
+        this.el_.volume = percentAsDecimal;
+      }
+    }
+
+    /**
+     * Get if muted
+     *
+     * @return {Boolean}
+     * @method muted
+     */
+  }, {
+    key: 'muted',
+    value: function muted() {
+      return this.el_.muted ? this.el_.muted : false;
+    }
+
+    /**
+     * Set muted
+     *
+     * @param {Boolean} If player is to be muted or note
+     * @method setMuted
+     */
+  }, {
+    key: 'setMuted',
+    value: function setMuted(muted) {
+      if (this.el_.muted) {
+        this.el_.muted = muted;
+      }
+    }
+
+    /**
+     * Get player width
+     *
+     * @return {Number}
+     * @method width
+     */
+  }, {
+    key: 'width',
+    value: function width() {
+      return this.el_.offsetWidth;
+    }
+
+    /**
+     * Get player height
+     *
+     * @return {Number}
+     * @method height
+     */
+  }, {
+    key: 'height',
+    value: function height() {
+      return this.el_.offsetHeight;
+    }
+
+    /**
+     * Get if there is fullscreen support
+     *
+     * @return {Boolean}
+     * @method supportsFullScreen
+     */
+  }, {
+    key: 'supportsFullScreen',
+    value: function supportsFullScreen() {
+      if (typeof this.el_.webkitEnterFullScreen === 'function') {
+        var userAgent = window.navigator.userAgent;
+
+        // Seems to be broken in Chromium/Chrome && Safari in Leopard
+        if (/Android/.test(userAgent) || !/Chrome|Mac OS X 
10.5/.test(userAgent)) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    /**
+     * Request to enter fullscreen
+     *
+     * @method enterFullScreen
+     */
+  }, {
+    key: 'enterFullScreen',
+    value: function enterFullScreen() {
+      var video = this.el_;
+
+      if ('webkitDisplayingFullscreen' in video) {
+        this.one('webkitbeginfullscreen', function () {
+          this.one('webkitendfullscreen', function () {
+            this.trigger('fullscreenchange', { isFullscreen: false });
+          });
+
+          this.trigger('fullscreenchange', { isFullscreen: true });
+        });
+      }
+
+      if (video.paused && video.networkState <= video.HAVE_METADATA) {
+        // attempt to prime the video element for programmatic access
+        // this isn't necessary on the desktop but shouldn't hurt
+        this.el_.play();
+
+        // playing and pausing synchronously during the transition to 
fullscreen
+        // can get iOS ~6.1 devices into a play/pause loop
+        this.setTimeout(function () {
+          video.pause();
+          video.webkitEnterFullScreen();
+        }, 0);
+      } else {
+        video.webkitEnterFullScreen();
+      }
+    }
+
+    /**
+     * Request to exit fullscreen
+     *
+     * @method exitFullScreen
+     */
+  }, {
+    key: 'exitFullScreen',
+    value: function exitFullScreen() {
+      this.el_.webkitExitFullScreen();
+    }
+
+    /**
+     * Get/set video
+     *
+     * @param {Object=} src Source object
+     * @return {Object}
+     * @method src
+     */
+  }, {
+    key: 'src',
+    value: function src(_src) {
+      if (typeof _src === 'undefined') {
+        return this.el_.src;
+      }
+      // Setting src through `src` instead of `setSrc` will be deprecated
+      this.setSrc(_src);
+    }
+
+    /**
+     * Set video
+     *
+     * @param {Object} src Source object
+     * @deprecated
+     * @method setSrc
+     */
+  }, {
+    key: 'setSrc',
+    value: function setSrc(src) {
+      this.el_.src = src;
+    }
+
+    /**
+     * Load media into player
+     *
+     * @method load
+     */
+  }, {
+    key: 'load',
+    value: function load() {
+      this.el_.load();
+    }
+
+    /**
+     * Get current source
+     *
+     * @return {Object}
+     * @method currentSrc
+     */
+  }, {
+    key: 'currentSrc',
+    value: function currentSrc() {
+      if (this.currentSource_) {
+        return this.currentSource_.src;
+      }
+      return this.el_.currentSrc;
+    }
+
+    /**
+     * Get poster
+     *
+     * @return {String}
+     * @method poster
+     */
+  }, {
+    key: 'poster',
+    value: function poster() {
+      return this.el_.poster;
+    }
+
+    /**
+     * Set poster
+     *
+     * @param {String} val URL to poster image
+     * @method
+     */
+  }, {
+    key: 'setPoster',
+    value: function setPoster(val) {
+      this.el_.poster = val;
+    }
+
+    /**
+     * Get preload attribute
+     *
+     * @return {String}
+     * @method preload
+     */
+    // preload() { return this.el_.preload; }
+
+    /**
+     * Set preload attribute
+     *
+     * @param {String} val Value for preload attribute
+     * @method setPreload
+     */
+    // setPreload(val) { this.el_.preload = val; }
+
+    /**
+     * Get autoplay attribute
+     *
+     * @return {String}
+     * @method autoplay
+     */
+    // autoplay() { return this.el_.autoplay; }
+
+    /**
+     * Set autoplay attribute
+     *
+     * @param {String} val Value for preload attribute
+     * @method setAutoplay
+     */
+    // setAutoplay(val) { this.el_.autoplay = val; }
+
+    /**
+     * Get controls attribute
+     *
+     * @return {String}
+     * @method controls
+     */
+  }, {
+    key: 'controls',
+    value: function controls() {
+      return this.el_.controls;
+    }
+
+    /**
+     * Set controls attribute
+     *
+     * @param {String} val Value for controls attribute
+     * @method setControls
+     */
+  }, {
+    key: 'setControls',
+    value: function setControls(val) {
+      this.el_.controls = !!val;
+    }
+
+    /**
+     * Get loop attribute
+     *
+     * @return {String}
+     * @method loop
+     */
+    // loop() { return this.el_.loop; }
+
+    /**
+     * Set loop attribute
+     *
+     * @param {String} val Value for loop attribute
+     * @method setLoop
+     */
+    // setLoop(val) { this.el_.loop = val; }
+
+    /**
+     * Get error value
+     *
+     * @return {String}
+     * @method error
+     */
+  }, {
+    key: 'error',
+    value: function error() {
+      return this.el_.error;
+    }
+
+    /**
+     * Get whether or not the player is in the "seeking" state
+     *
+     * @return {Boolean}
+     * @method seeking
+     */
+  }, {
+    key: 'seeking',
+    value: function seeking() {
+      return this.el_.seeking;
+    }
+
+    /**
+     * Get a TimeRanges object that represents the
+     * ranges of the media resource to which it is possible
+     * for the user agent to seek.
+     *
+     * @return {TimeRangeObject}
+     * @method seekable
+     */
+  }, {
+    key: 'seekable',
+    value: function seekable() {
+      return this.el_.seekable;
+    }
+
+    /**
+     * Get if video ended
+     *
+     * @return {Boolean}
+     * @method ended
+     */
+  }, {
+    key: 'ended',
+    value: function ended() {
+      return this.el_.ended;
+    }
+
+    /**
+     * Get the value of the muted content attribute
+     * This attribute has no dynamic effect, it only
+     * controls the default state of the element
+     *
+     * @return {Boolean}
+     * @method defaultMuted
+     */
+    // defaultMuted() { return this.el_.defaultMuted; }
+
+    /**
+     * Get desired speed at which the media resource is to play
+     *
+     * @return {Number}
+     * @method playbackRate
+     */
+    // playbackRate() { return this.el_.playbackRate; }
+
+    /**
+     * Returns a TimeRanges object that represents the ranges of the
+     * media resource that the user agent has played.
+     * @return {TimeRangeObject} the range of points on the media
+     * timeline that has been reached through normal playback
+     * @see 
https://html.spec.whatwg.org/multipage/embedded-content.html#dom-media-played
+     */
+    // played() { return this.el_.played; }
+
+    /**
+     * Set desired speed at which the media resource is to play
+     *
+     * @param {Number} val Speed at which the media resource is to play
+     * @method setPlaybackRate
+     */
+    // setPlaybackRate(val) { this.el_.playbackRate = val; }
+
+    /**
+     * Get the current state of network activity for the element, from
+     * the list below
+     * NETWORK_EMPTY (numeric value 0)
+     * NETWORK_IDLE (numeric value 1)
+     * NETWORK_LOADING (numeric value 2)
+     * NETWORK_NO_SOURCE (numeric value 3)
+     *
+     * @return {Number}
+     * @method networkState
+     */
+    // networkState() { return this.el_.networkState; }
+
+    /**
+     * Get a value that expresses the current state of the element
+     * with respect to rendering the current playback position, from
+     * the codes in the list below
+     * HAVE_NOTHING (numeric value 0)
+     * HAVE_METADATA (numeric value 1)
+     * HAVE_CURRENT_DATA (numeric value 2)
+     * HAVE_FUTURE_DATA (numeric value 3)
+     * HAVE_ENOUGH_DATA (numeric value 4)
+     *
+     * @return {Number}
+     * @method readyState
+     */
+    // readyState() { return this.el_.readyState; }
+
+    /**
+     * Get width of video
+     *
+     * @return {Number}
+     * @method videoWidth
+     */
+  }, {
+    key: 'videoWidth',
+    value: function videoWidth() {
+      return this.el_.videoWidth;
+    }
+
+    /**
+     * Get height of video
+     *
+     * @return {Number}
+     * @method videoHeight
+     */
+  }, {
+    key: 'videoHeight',
+    value: function videoHeight() {
+      return this.el_.videoHeight;
+    }
+  }]);
+
+  return Ogvjs;
+})(Tech);
+
+Ogvjs.isSupported = function () {
+  return _OGVCompat2['default'].supported('OGVPlayer');
+};
+
+/*
+   * Check if the tech can support the given source
+   * @param  {Object} srcObj  The source object
+   * @return {String}         'probably', 'maybe', or '' (empty string)
+   */
+Ogvjs.canPlaySource = function (srcObj) {
+  return srcObj.type.indexOf('/ogg') !== -1 ? 'maybe' : '';
+};
+
+/*
+ * Check if the volume can be changed in this browser/device.
+ * Volume cannot be changed in a lot of mobile devices.
+ * Specifically, it can't be changed from 1 on iOS.
+ *
+ * @return {Boolean}
+ */
+Ogvjs.canControlVolume = function () {
+  return false;
+};
+
+/*
+ * Check if playbackRate is supported in this browser/device.
+ *
+ * @return {Number} [description]
+ */
+Ogvjs.canControlPlaybackRate = function () {
+  return false;
+};
+
+/*
+ * Check to see if native text tracks are supported by this browser/device
+ *
+ * @return {Boolean}
+ */
+Ogvjs.supportsNativeTextTracks = function () {
+  return false;
+};
+
+/**
+ * An array of events available on the Ogvjs tech.
+ *
+ * @private
+ * @type {Array}
+ */
+Ogvjs.Events = ['loadstart', 'suspend', 'abort', 'error', 'emptied', 
'stalled', 'loadedmetadata', 'loadeddata', 'canplay', 'canplaythrough', 
'playing', 'waiting', 'seeking', 'seeked', 'ended', 'durationchange', 
'timeupdate', 'progress', 'play', 'pause', 'ratechange', 'volumechange'];
+
+/*
+ * Set the tech's volume control support status
+ *
+ * @type {Boolean}
+ */
+Ogvjs.prototype.featuresVolumeControl = Ogvjs.canControlVolume();
+
+/*
+ * Set the tech's playbackRate support status
+ *
+ * @type {Boolean}
+ */
+Ogvjs.prototype.featuresPlaybackRate = Ogvjs.canControlPlaybackRate();
+
+/*
+ * Set the the tech's fullscreen resize support status.
+ * HTML video is able to automatically resize when going to fullscreen.
+ * (No longer appears to be used. Can probably be removed.)
+ */
+Ogvjs.prototype.featuresFullscreenResize = true;
+
+/*
+ * Set the tech's progress event support status
+ * (this disables the manual progress events of the Tech)
+ */
+Ogvjs.prototype.featuresProgressEvents = true;
+
+/*
+ * Sets the tech's status on native text track support
+ *
+ * @type {Boolean}
+ */
+Ogvjs.prototype.featuresNativeTextTracks = Ogvjs.supportsNativeTextTracks();
+
+Ogvjs.disposeMediaElement = function (el) {
+  if (!el) {
+    return;
+  }
+
+  if (el.parentNode) {
+    el.parentNode.removeChild(el);
+  }
+
+  // remove any child track or source nodes to prevent their loading
+  while (el.hasChildNodes()) {
+    el.removeChild(el.firstChild);
+  }
+
+  // remove any src reference. not setting `src=''` because that causes a 
warning
+  // in firefox
+  el.removeAttribute('src');
+
+  // force the media element to update its loading state by calling load()
+  // however IE on Windows 7N has a bug that throws an error so need a 
try/catch (#793)
+  if (typeof el.load === 'function') {
+    // wrapping in an iife so it's not deoptimized (#1060#discussion_r10324473)
+    (function () {
+      try {
+        el.load();
+      } catch (e) {
+        // not supported
+      }
+    })();
+  }
+};
+
+Tech.registerTech('Ogvjs', Ogvjs);
+exports['default'] = Ogvjs;
+module.exports = exports['default'];
+}).call(this,typeof global !== "undefined" ? global : typeof self !== 
"undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}]},{},[1])(1)
+});
\ No newline at end of file
diff --git a/resources/videojs-ogvjs/videojs-ogvjs.min.js 
b/resources/videojs-ogvjs/videojs-ogvjs.min.js
new file mode 100644
index 0000000..705f44d
--- /dev/null
+++ b/resources/videojs-ogvjs/videojs-ogvjs.min.js
@@ -0,0 +1,7 @@
+/**
+ * videojs-ogvjs
+ * @version 1.0.6
+ * @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.videojsOgvjs=e()}}(function(){return function 
e(t,n,r){function o(u,l){if(!n[u]){if(!t[u]){var a="function"==typeof 
require&&require;if(!l&&a)return a(u,!0);if(i)return i(u,!0);var s=new 
Error("Cannot find module '"+u+"'");throw s.code="MODULE_NOT_FOUND",s}var 
f=n[u]={exports:{}};t[u][0].call(f.exports,function(e){var n=t[u][1][e];return 
o(n?n:e)},f,f.exports,e,t,n,r)}return n[u].exports}for(var i="function"==typeof 
require&&require,u=0;u<r.length;u++)o(r[u]);return 
o}({1:[function(e,t,n){(function(e){"use strict";function r(e){return 
e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new 
TypeError("Cannot call a class as a function")}function 
i(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression 
must either be null or a function, not "+typeof 
t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(n,"__esModule",{value:!0});var
 u=function(){function e(e,t){for(var n=0;n<t.length;n++){var 
r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in 
r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return 
function(t,n,r){return 
n&&e(t.prototype,n),r&&e(t,r),t}}(),l=function(e,t,n){for(var r=!0;r;){var 
o=e,i=t,u=n;r=!1,null===o&&(o=Function.prototype);var 
l=Object.getOwnPropertyDescriptor(o,i);if(void 0!==l){if("value"in l)return 
l.value;var a=l.get;if(void 0===a)return;return a.call(u)}var 
s=Object.getPrototypeOf(o);if(null===s)return;e=s,t=i,n=u,r=!0,l=s=void 
0}},a="undefined"!=typeof window?window.videojs:"undefined"!=typeof 
e?e.videojs:null,s=r(a),f="undefined"!=typeof 
window?window.OGVCompat:"undefined"!=typeof 
e?e.OGVCompat:null,c=r(f),d="undefined"!=typeof 
window?window.OGVLoader:"undefined"!=typeof 
e?e.OGVLoader:null,p=r(d),y="undefined"!=typeof 
window?window.OGVPlayer:"undefined"!=typeof 
e?e.OGVPlayer:null,h=r(y),v=s["default"].getComponent("Tech"),k=function(e){function
 
t(e,n){o(this,t),l(Object.getPrototypeOf(t.prototype),"constructor",this).call(this,e,n),this.triggerReady()}return
 
i(t,e),u(t,[{key:"dispose",value:function(){l(Object.getPrototypeOf(t.prototype),"dispose",this).call(this)}},{key:"createEl",value:function(){var
 e=this.options_;if(!e.base)throw new Error("Please specify the base for the 
ogv.js library");p["default"].base=e.base;var t=new h["default"](e);return 
this.lastTime=0,t.addEventListener("framecallback",this.onFrameUpdate.bind(this)),t.src=this.options_.source.src,t.className+="
 vjs-tech",t}},{key:"onFrameUpdate",value:function(e){var 
t=.25,n=this.el_?this.el_.currentTime:this.lastTime;Math.abs(n-this.lastTime)>=t&&(this.lastTime=n,this.trigger("timeupdate"),this.trigger("durationchange"))}},{key:"play",value:function(){this.el_.play()}},{key:"pause",value:function(){this.el_.pause()}},{key:"paused",value:function(){return
 this.el_.paused}},{key:"currentTime",value:function(){return 
this.el_.currentTime}},{key:"setCurrentTime",value:function(e){try{this.el_.currentTime=e}catch(t){s["default"].log(t,"Video
 is not ready. (Video.js)")}}},{key:"duration",value:function(){return 
this.el_.duration||0}},{key:"buffered",value:function(){return 
this.el_.buffered}},{key:"volume",value:function(){return 
this.el_.volume?this.el_.volume:1}},{key:"setVolume",value:function(e){this.el_.volume&&(this.el_.volume=e)}},{key:"muted",value:function(){return
 
this.el_.muted?this.el_.muted:!1}},{key:"setMuted",value:function(e){this.el_.muted&&(this.el_.muted=e)}},{key:"width",value:function(){return
 this.el_.offsetWidth}},{key:"height",value:function(){return 
this.el_.offsetHeight}},{key:"supportsFullScreen",value:function(){if("function"==typeof
 this.el_.webkitEnterFullScreen){var 
e=window.navigator.userAgent;if(/Android/.test(e)||!/Chrome|Mac OS X 
10.5/.test(e))return!0}return!1}},{key:"enterFullScreen",value:function(){var 
e=this.el_;"webkitDisplayingFullscreen"in 
e&&this.one("webkitbeginfullscreen",function(){this.one("webkitendfullscreen",function(){this.trigger("fullscreenchange",{isFullscreen:!1})}),this.trigger("fullscreenchange",{isFullscreen:!0})}),e.paused&&e.networkState<=e.HAVE_METADATA?(this.el_.play(),this.setTimeout(function(){e.pause(),e.webkitEnterFullScreen()},0)):e.webkitEnterFullScreen()}},{key:"exitFullScreen",value:function(){this.el_.webkitExitFullScreen()}},{key:"src",value:function(e){return"undefined"==typeof
 e?this.el_.src:void 
this.setSrc(e)}},{key:"setSrc",value:function(e){this.el_.src=e}},{key:"load",value:function(){this.el_.load()}},{key:"currentSrc",value:function(){return
 
this.currentSource_?this.currentSource_.src:this.el_.currentSrc}},{key:"poster",value:function(){return
 
this.el_.poster}},{key:"setPoster",value:function(e){this.el_.poster=e}},{key:"controls",value:function(){return
 
this.el_.controls}},{key:"setControls",value:function(e){this.el_.controls=!!e}},{key:"error",value:function(){return
 this.el_.error}},{key:"seeking",value:function(){return 
this.el_.seeking}},{key:"seekable",value:function(){return 
this.el_.seekable}},{key:"ended",value:function(){return 
this.el_.ended}},{key:"videoWidth",value:function(){return 
this.el_.videoWidth}},{key:"videoHeight",value:function(){return 
this.el_.videoHeight}}]),t}(v);k.isSupported=function(){return 
c["default"].supported("OGVPlayer")},k.canPlaySource=function(e){return-1!==e.type.indexOf("/ogg")?"maybe":""},k.canControlVolume=function(){return!1},k.canControlPlaybackRate=function(){return!1},k.supportsNativeTextTracks=function(){return!1},k.Events=["loadstart","suspend","abort","error","emptied","stalled","loadedmetadata","loadeddata","canplay","canplaythrough","playing","waiting","seeking","seeked","ended","durationchange","timeupdate","progress","play","pause","ratechange","volumechange"],k.prototype.featuresVolumeControl=k.canControlVolume(),k.prototype.featuresPlaybackRate=k.canControlPlaybackRate(),k.prototype.featuresFullscreenResize=!0,k.prototype.featuresProgressEvents=!0,k.prototype.featuresNativeTextTracks=k.supportsNativeTextTracks(),k.disposeMediaElement=function(e){if(e){for(e.parentNode&&e.parentNode.removeChild(e);e.hasChildNodes();)e.removeChild(e.firstChild);e.removeAttribute("src"),"function"==typeof
 
e.load&&!function(){try{e.load()}catch(t){}}()}},v.registerTech("Ogvjs",k),n["default"]=k,t.exports=n["default"]}).call(this,"undefined"!=typeof
 global?global:"undefined"!=typeof self?self:"undefined"!=typeof 
window?window:{})},{}]},{},[1])(1)});
\ No newline at end of file

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie511c145b9d16be1d234645e69b8c81665448ef9
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