diff --git a/app/Resources/public/assets/mediaelement/plugins/speed/speed-i18n.js b/app/Resources/public/assets/mediaelement/plugins/speed/speed-i18n.js new file mode 100644 index 00000000000..9e2167d6502 --- /dev/null +++ b/app/Resources/public/assets/mediaelement/plugins/speed/speed-i18n.js @@ -0,0 +1,65 @@ +'use strict'; + +if (mejs.i18n.ca !== undefined) { + mejs.i18n.ca['mejs.speed-rate'] = 'Velocitat'; +} +if (mejs.i18n.cs !== undefined) { + mejs.i18n.cs['mejs.speed-rate'] = 'Rychlost'; +} +if (mejs.i18n.de !== undefined) { + mejs.i18n.de['mejs.speed-rate'] = 'Geschwindigkeitsrate'; +} +if (mejs.i18n.es !== undefined) { + mejs.i18n.es['mejs.speed-rate'] = 'Velocidad'; +} +if (mejs.i18n.fa !== undefined) { + mejs.i18n.fa['mejs.speed-rate'] = 'نرخ سرعت'; +} +if (mejs.i18n.fr !== undefined) { + mejs.i18n.fr['mejs.speed-rate'] = 'Vitesse'; +} +if (mejs.i18n.hr !== undefined) { + mejs.i18n.hr['mejs.speed-rate'] = 'Brzina reprodukcije'; +} +if (mejs.i18n.hu !== undefined) { + mejs.i18n.hu['mejs.speed-rate'] = 'Sebesség'; +} +if (mejs.i18n.it !== undefined) { + mejs.i18n.it['mejs.speed-rate'] = 'Velocità'; +} +if (mejs.i18n.ja !== undefined) { + mejs.i18n.ja['mejs.speed-rate'] = '高速'; +} +if (mejs.i18n.ko !== undefined) { + mejs.i18n.ko['mejs.speed-rate'] = '속도 속도'; +} +if (mejs.i18n.nl !== undefined) { + mejs.i18n.nl['mejs.speed-rate'] = 'Snelheidsgraad'; +} +if (mejs.i18n.pl !== undefined) { + mejs.i18n.pl['mejs.speed-rate'] = 'Prędkość'; +} +if (mejs.i18n.pt !== undefined) { + mejs.i18n.pt['mejs.speed-rate'] = 'Taxa de velocidade'; +} +if (mejs.i18n.ro !== undefined) { + mejs.i18n.ro['mejs.speed-rate'] = 'Viteză de viteză'; +} +if (mejs.i18n.ru !== undefined) { + mejs.i18n.ru['mejs.speed-rate'] = 'Скорость воспроизведения'; +} +if (mejs.i18n.sk !== undefined) { + mejs.i18n.sk['mejs.speed-rate'] = 'Rýchlosť'; +} +if (mejs.i18n.sv !== undefined) { + mejs.i18n.sv['mejs.speed-rate'] = 'Hastighet'; +} +if (mejs.i18n.uk !== undefined) { + mejs.i18n.uk['mejs.speed-rate'] = 'Швидкість відтворення'; +} +if (mejs.i18n.zh !== undefined) { + mejs.i18n.zh['mejs.speed-rate'] = '速度'; +} +if (mejs.i18n['zh-CN'] !== undefined) { + mejs.i18n['zh-CN']['mejs.speed-rate'] = '速度'; +} \ No newline at end of file diff --git a/app/Resources/public/assets/mediaelement/plugins/speed/speed.css b/app/Resources/public/assets/mediaelement/plugins/speed/speed.css new file mode 100644 index 00000000000..76579a88951 --- /dev/null +++ b/app/Resources/public/assets/mediaelement/plugins/speed/speed.css @@ -0,0 +1,94 @@ +.mejs__speed-button, +.mejs-speed-button { + position: relative; +} + +.mejs__speed-button > button, +.mejs-speed-button > button { + background: transparent; + color: #fff; + font-size: 11px; + line-height: normal; + margin: 11px 0 0; + width: 36px; +} + +.mejs__speed-selector, +.mejs-speed-selector { + background: rgba(50, 50, 50, 0.7); + border: solid 1px transparent; + border-radius: 0; + height: 150px; + left: -10px; + overflow: hidden; + padding: 0; + position: absolute; + top: -100px; + visibility: hidden; + width: 60px; +} + +.mejs__speed-selector, +.mejs-speed-selector { + visibility: visible; +} + +.mejs__speed-selector-list, +.mejs-speed-selector-list { + display: block; + list-style-type: none !important; + margin: 0; + overflow: hidden; + padding: 0; +} + +.mejs__speed-selector-list-item, +.mejs-speed-selector-list-item { + color: #fff; + display: block; + list-style-type: none !important; + margin: 0 0 6px; + overflow: hidden; + padding: 0 10px; +} + +.mejs__speed-selector-list-item:hover, +.mejs-speed-selector-list-item:hover { + background-color: rgb(200, 200, 200) !important; + background-color: rgba(255, 255, 255, 0.4) !important; +} + +.mejs__speed-selector-input, +.mejs-speed-selector-input { + clear: both; + float: left; + left: -1000px; + margin: 3px 3px 0 5px; + position: absolute; +} + +.mejs__speed-selector-label, +.mejs-speed-selector-label { + color: white; + cursor: pointer; + float: left; + font-size: 11px; + line-height: 15px; + margin-left: 5px; + padding: 4px 0 0; + width: 60px; +} + +.mejs__speed-selected, +.mejs-speed-selected { + color: rgba(33, 248, 248, 1); +} + +.mejs__speed-selector, +.mejs-speed-selector { + visibility: hidden; +} +.mejs__speed-button:hover .mejs__speed-selector, +.mejs-speed-button:hover .mejs-speed-selector { + visibility: visible; +} diff --git a/app/Resources/public/assets/mediaelement/plugins/speed/speed.js b/app/Resources/public/assets/mediaelement/plugins/speed/speed.js new file mode 100644 index 00000000000..1beaeea88dc --- /dev/null +++ b/app/Resources/public/assets/mediaelement/plugins/speed/speed.js @@ -0,0 +1,174 @@ +/*! + * MediaElement.js + * http://www.mediaelementjs.com/ + * + * Wrapper that mimics native HTML5 MediaElement (audio and video) + * using a variety of technologies (pure JavaScript, Flash, iframe) + * + * Copyright 2010-2017, John Dyer (http://j.hn/) + * License: MIT + * + */(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' + getSpeedNameFromValue(t.options.defaultSpeed) + '') + ('
') + ('') + '
'; + + t.addControlElement(player.speedButton, 'speed'); + + for (var _i = 0, _total = speeds.length; _i < _total; _i++) { + + var inputId = t.id + '-speed-' + speeds[_i].value; + + player.speedButton.querySelector('ul').innerHTML += '
  • ' + ('') + ('') + '
  • '; + } + + playbackSpeed = t.options.defaultSpeed; + + player.speedSelector = player.speedButton.querySelector('.' + t.options.classPrefix + 'speed-selector'); + + var inEvents = ['mouseenter', 'focusin'], + outEvents = ['mouseleave', 'focusout'], + radios = player.speedButton.querySelectorAll('input[type="radio"]'), + labels = player.speedButton.querySelectorAll('.' + t.options.classPrefix + 'speed-selector-label'); + + for (var _i2 = 0, _total2 = inEvents.length; _i2 < _total2; _i2++) { + player.speedButton.addEventListener(inEvents[_i2], function () { + mejs.Utils.removeClass(player.speedSelector, t.options.classPrefix + 'offscreen'); + player.speedSelector.style.height = player.speedSelector.querySelector('ul').offsetHeight; + player.speedSelector.style.top = -1 * parseFloat(player.speedSelector.offsetHeight) + 'px'; + }); + } + + for (var _i3 = 0, _total3 = outEvents.length; _i3 < _total3; _i3++) { + player.speedSelector.addEventListener(outEvents[_i3], function () { + mejs.Utils.addClass(this, t.options.classPrefix + 'offscreen'); + }); + } + + for (var _i4 = 0, _total4 = radios.length; _i4 < _total4; _i4++) { + var radio = radios[_i4]; + radio.disabled = false; + radio.addEventListener('click', function () { + var self = this, + newSpeed = self.value; + + playbackSpeed = newSpeed; + media.playbackRate = parseFloat(newSpeed); + player.speedButton.querySelector('button').innerHTML = getSpeedNameFromValue(newSpeed); + var selected = player.speedButton.querySelectorAll('.' + t.options.classPrefix + 'speed-selected'); + for (var _i5 = 0, _total5 = selected.length; _i5 < _total5; _i5++) { + mejs.Utils.removeClass(selected[_i5], t.options.classPrefix + 'speed-selected'); + } + + self.checked = true; + var siblings = mejs.Utils.siblings(self, function (el) { + return mejs.Utils.hasClass(el, t.options.classPrefix + 'speed-selector-label'); + }); + for (var j = 0, _total6 = siblings.length; j < _total6; j++) { + mejs.Utils.addClass(siblings[j], t.options.classPrefix + 'speed-selected'); + } + }); + } + + for (var _i6 = 0, _total7 = labels.length; _i6 < _total7; _i6++) { + labels[_i6].addEventListener('click', function () { + var radio = mejs.Utils.siblings(this, function (el) { + return el.tagName === 'INPUT'; + })[0], + event = mejs.Utils.createEvent('click', radio); + radio.dispatchEvent(event); + }); + } + + player.speedSelector.addEventListener('keydown', function (e) { + e.stopPropagation(); + }); + + media.addEventListener('loadedmetadata', function () { + if (playbackSpeed) { + media.playbackRate = parseFloat(playbackSpeed); + } + }); + }, + cleanspeed: function cleanspeed(player) { + if (player) { + if (player.speedButton) { + player.speedButton.parentNode.removeChild(player.speedButton); + } + if (player.speedSelector) { + player.speedSelector.parentNode.removeChild(player.speedSelector); + } + } + } +}); + +},{}]},{},[1]); diff --git a/app/Resources/public/assets/mediaelement/plugins/speed/speed.min.css b/app/Resources/public/assets/mediaelement/plugins/speed/speed.min.css new file mode 100644 index 00000000000..10d379715fd --- /dev/null +++ b/app/Resources/public/assets/mediaelement/plugins/speed/speed.min.css @@ -0,0 +1 @@ +.mejs-speed-button,.mejs__speed-button{position:relative}.mejs-speed-button>button,.mejs__speed-button>button{background:transparent;color:#fff;font-size:11px;line-height:normal;margin:11px 0 0;width:36px}.mejs-speed-selector,.mejs__speed-selector{background:rgba(50,50,50,.7);border:1px solid transparent;border-radius:0;height:150px;left:-10px;overflow:hidden;padding:0;position:absolute;top:-100px;width:60px;visibility:visible}.mejs-speed-selector-list,.mejs__speed-selector-list{display:block;list-style-type:none!important;margin:0;overflow:hidden;padding:0}.mejs-speed-selector-list-item,.mejs__speed-selector-list-item{color:#fff;display:block;list-style-type:none!important;margin:0 0 6px;overflow:hidden;padding:0 10px}.mejs-speed-selector-list-item:hover,.mejs__speed-selector-list-item:hover{background-color:#c8c8c8!important;background-color:hsla(0,0%,100%,.4)!important}.mejs-speed-selector-input,.mejs__speed-selector-input{clear:both;float:left;left:-1000px;margin:3px 3px 0 5px;position:absolute}.mejs-speed-selector-label,.mejs__speed-selector-label{color:#fff;cursor:pointer;float:left;font-size:11px;line-height:15px;margin-left:5px;padding:4px 0 0;width:60px}.mejs-speed-selected,.mejs__speed-selected{color:#21f8f8}.mejs-speed-selector,.mejs__speed-selector{visibility:hidden}.mejs-speed-button:hover .mejs-speed-selector,.mejs__speed-button:hover .mejs__speed-selector{visibility:visible} \ No newline at end of file diff --git a/app/Resources/public/assets/mediaelement/plugins/speed/speed.min.js b/app/Resources/public/assets/mediaelement/plugins/speed/speed.min.js new file mode 100644 index 00000000000..18d0dd32940 --- /dev/null +++ b/app/Resources/public/assets/mediaelement/plugins/speed/speed.min.js @@ -0,0 +1,12 @@ +/*! + * MediaElement.js + * http://www.mediaelementjs.com/ + * + * Wrapper that mimics native HTML5 MediaElement (audio and video) + * using a variety of technologies (pure JavaScript, Flash, iframe) + * + * Copyright 2010-2017, John Dyer (http://j.hn/) + * License: MIT + * + */ +!function e(t,s,o){function n(l,i){if(!s[l]){if(!t[l]){var a="function"==typeof require&&require;if(!i&&a)return a(l,!0);if(r)return r(l,!0);var d=new Error("Cannot find module '"+l+"'");throw d.code="MODULE_NOT_FOUND",d}var p=s[l]={exports:{}};t[l][0].call(p.exports,function(e){var s=t[l][1][e];return n(s||e)},p,p.exports,e,t,s,o)}return s[l].exports}for(var r="function"==typeof require&&require,l=0;l'+i(n.options.defaultSpeed)+'
      ',n.addControlElement(e.speedButton,"speed");for(var f=0,v=r.length;f"}a=n.options.defaultSpeed,e.speedSelector=e.speedButton.querySelector("."+n.options.classPrefix+"speed-selector");for(var h=["mouseenter","focusin"],S=["mouseleave","focusout"],x=e.speedButton.querySelectorAll('input[type="radio"]'),b=e.speedButton.querySelectorAll("."+n.options.classPrefix+"speed-selector-label"),g=0,y=h.length;gassign('css_static_file_to_string', $css_file_to_string); } + + $defaultFeatures = implode("','", $defaultFeatures); + $this->assign('video_features', $defaultFeatures); } /** @@ -757,6 +770,14 @@ public function set_js_files() 'select2/dist/js/select2.min.js', "select2/dist/js/i18n/$isoCode.js", ]; + + $features = api_get_configuration_value('video_features'); + if (!empty($features) && isset($features['features'])) { + foreach ($features['features'] as $feature) { + $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js"; + } + } + if (CHAMILO_LOAD_WYSIWYG == true) { $bowerJsFiles[] = 'ckeditor/ckeditor.js'; } diff --git a/main/install/configuration.dist.php b/main/install/configuration.dist.php index 17a37d69f45..d0784593e6b 100755 --- a/main/install/configuration.dist.php +++ b/main/install/configuration.dist.php @@ -830,6 +830,9 @@ //$_configuration['allow_exercise_auto_launch'] = false; // ALTER TABLE c_quiz ADD autolaunch TINYINT(1) DEFAULT 0; +// Enable speed controller in video player +// $_configuration['video_features'] = ['features' => ['speed']]; + // ------ Custom DB changes (keep this at the end) // Add user activation by confirmation email // This option prevents the new user to login in the platform if your account is not confirmed via email diff --git a/main/template/default/layout/footer.js.tpl b/main/template/default/layout/footer.js.tpl index 5bd4cf9c034..8b9c7272f64 100644 --- a/main/template/default/layout/footer.js.tpl +++ b/main/template/default/layout/footer.js.tpl @@ -96,6 +96,7 @@ $('video:not(.skip), audio:not(.skip)').mediaelementplayer({ pluginPath: '{{ _p.web }}web/assets/mediaelement/build/', renderers: ['html5', 'flash_video', 'native_flv'], + features: ['{{ video_features }}'], success: function(mediaElement, originalNode, instance) { } });