Browse Source

Merge branch '1.11.x' of https://github.com/chamilo/chamilo-lms into 1.11.x

Alex Aragón 6 years ago
parent
commit
389a69aef0
31 changed files with 319 additions and 368 deletions
  1. 4 4
      app/Resources/public/assets/mediaelement/.bower.json
  2. 90 0
      app/Resources/public/assets/mediaelement/build/lang/ms.js
  3. 23 9
      app/Resources/public/assets/mediaelement/build/mediaelement-and-player.js
  4. 0 0
      app/Resources/public/assets/mediaelement/build/mediaelement-and-player.min.js
  5. 2 2
      app/Resources/public/assets/mediaelement/build/mediaelement.js
  6. 0 0
      app/Resources/public/assets/mediaelement/build/mediaelement.min.js
  7. 0 0
      app/Resources/public/assets/mediaelement/build/renderers/dailymotion.min.js
  8. 1 1
      app/Resources/public/assets/mediaelement/build/renderers/facebook.js
  9. 0 0
      app/Resources/public/assets/mediaelement/build/renderers/facebook.min.js
  10. 0 0
      app/Resources/public/assets/mediaelement/build/renderers/soundcloud.min.js
  11. 0 0
      app/Resources/public/assets/mediaelement/build/renderers/twitch.min.js
  12. 3 3
      app/Resources/public/assets/mediaelement/build/renderers/vimeo.js
  13. 0 0
      app/Resources/public/assets/mediaelement/build/renderers/vimeo.min.js
  14. 19 1
      app/Resources/public/assets/mediaelement/changelog.md
  15. 16 0
      app/Resources/public/css/base.css
  16. 4 4
      app/Resources/public/css/scorm.css
  17. 4 11
      main/document/document.php
  18. 8 64
      main/document/showinframes.php
  19. 0 82
      main/exercise/exercise.class.php
  20. 16 17
      main/exercise/upload_exercise.php
  21. 1 1
      main/inc/introductionSection.inc.php
  22. 56 126
      main/inc/lib/document.lib.php
  23. 1 1
      main/inc/lib/sessionmanager.lib.php
  24. 15 7
      main/lp/learnpath.class.php
  25. 6 2
      main/session/resume_session.php
  26. 2 2
      main/template/default/layout/footer.js.tpl
  27. 14 9
      main/work/view.php
  28. 24 17
      main/work/work.lib.php
  29. 0 2
      src/Chamilo/ThemeBundle/Resources/views/Layout/footer.js.twig
  30. 9 1
      tests/behat/features/toolExercise.feature
  31. 1 2
      tests/behat/features/toolWork.feature

+ 4 - 4
app/Resources/public/assets/mediaelement/.bower.json

@@ -23,12 +23,12 @@
     "./build/mediaelement-and-player.js",
     "./build/mediaelementplayer.css"
   ],
-  "version": "4.2.8",
-  "_release": "4.2.8",
+  "version": "4.2.9",
+  "_release": "4.2.9",
   "_resolution": {
     "type": "version",
-    "tag": "4.2.8",
-    "commit": "0896fce181f4f1450bdc1c70598e66fe0bfa872b"
+    "tag": "4.2.9",
+    "commit": "6d665634da067ac075cd49631e646c7b16f25510"
   },
   "_source": "https://github.com/johndyer/mediaelement.git",
   "_target": "4.*",

+ 90 - 0
app/Resources/public/assets/mediaelement/build/lang/ms.js

@@ -0,0 +1,90 @@
+'use strict';/*!
+ * This is a `i18n` language object.
+ *
+ * Malay (for inter-country use - see the countries mentioned in infobox`s `native to` at https://en.wikipedia.org/wiki/Malay_language)
+ *
+ * @author
+ *   muhdnurhidayat (Twitter: @mnh48com)
+ *   Sascha Greuel (Twitter: @SoftCreatR)
+ *
+ * @see core/i18n.js
+ */
+(function (exports) {
+	if (exports.ms === undefined) {
+		exports.ms = {
+			'mejs.plural-form': 0,			
+			'mejs.download-file': 'Muat Turun Fail',			
+			'mejs.install-flash': 'Anda sedang menggunakan pelayar internet yang tidak mempunyai pemain Flash. Sila aktifkan pemalam pemain Flash anda atau muat turun versi terbaru dari https://get.adobe.com/flashplayer/',			
+			'mejs.fullscreen': 'Skrin penuh',			
+			'mejs.play': 'Main',
+			'mejs.pause': 'Jeda',			
+			'mejs.time-slider': 'Lungsur Masa',
+			'mejs.time-help-text': 'Gunakan kekunci Anak Panah Kiri/Kanan untuk bergerak satu saat, Anak Panah Atas/Bawah untuk bergerak sepuluh saat.',
+			'mejs.live-broadcast' : 'Siaran Langsung',			
+			'mejs.volume-help-text': 'Gunakan kekunci Anak Panah Atas/Bawah untuk menguatkan atau memperlahankan bunyi.',
+			'mejs.unmute': 'Nyahsenyap',
+			'mejs.mute': 'Senyap',
+			'mejs.volume-slider': 'Lungsur Bunyi',			
+			'mejs.video-player': 'Pemain Video',
+			'mejs.audio-player': 'Pemain Audio',			
+			'mejs.captions-subtitles': 'Sarikata',
+			'mejs.captions-chapters': 'Bab',
+			'mejs.none': 'Tiada',
+			'mejs.afrikaans': 'Bahasa Afrikaans',
+			'mejs.albanian': 'Bahasa Albania',
+			'mejs.arabic': 'Bahasa Arab',
+			'mejs.belarusian': 'Bahasa Belarus',
+			'mejs.bulgarian': 'Bahasa Bulgaria',
+			'mejs.catalan': 'Bahasa Catalonia',
+			'mejs.chinese': 'Bahasa Cina',
+			'mejs.chinese-simplified': 'Bahasa Cina (Ringkas)',
+			'mejs.chinese-traditional': 'Bahasa Cina (Tradisional)',
+			'mejs.croatian': 'Bahasa Croatia',
+			'mejs.czech': 'Bahasa Czech',
+			'mejs.danish': 'Bahasa Denmark',
+			'mejs.dutch': 'Bahasa Belanda',
+			'mejs.english': 'Bahasa Inggeris',
+			'mejs.estonian': 'Bahasa Estonia',
+			'mejs.filipino': 'Bahasa Filipino',
+			'mejs.finnish': 'Bahasa Finland',
+			'mejs.french': 'Bahasa Perancis',
+			'mejs.galician': 'Bahasa Galicia',
+			'mejs.german': 'Bahasa Jerman',
+			'mejs.greek': 'Bahasa Greek',
+			'mejs.haitian-creole': 'Bahasa Kreol Haiti',
+			'mejs.hebrew': 'Bahasa Ibrani',
+			'mejs.hindi': 'Bahasa Hindi',
+			'mejs.hungarian': 'Bahasa Hungary',
+			'mejs.icelandic': 'Bahasa Iceland',
+			'mejs.indonesian': 'Bahasa Indonesia',
+			'mejs.irish': 'Bahasa Ireland',
+			'mejs.italian': 'Bahasa Itali',
+			'mejs.japanese': 'Bahasa Jepun',
+			'mejs.korean': 'Bahasa Korea',
+			'mejs.latvian': 'Bahasa Latvia',
+			'mejs.lithuanian': 'Bahasa Lithuania',
+			'mejs.macedonian': 'Bahasa Macedonia',
+			'mejs.malay': 'Bahasa Melayu',
+			'mejs.maltese': 'Bahasa Malta',
+			'mejs.norwegian': 'Bahasa Norway',
+			'mejs.persian': 'Bahasa Parsi',
+			'mejs.polish': 'Bahasa Poland',
+			'mejs.portuguese': 'Bahasa Portugis',
+			'mejs.romanian': 'Bahasa Romania',
+			'mejs.russian': 'Bahasa Rusia',
+			'mejs.serbian': 'Bahasa Serbia',
+			'mejs.slovak': 'Bahasa Slovak',
+			'mejs.slovenian': 'Bahasa Slovene',
+			'mejs.spanish': 'Bahasa Sepanyol',
+			'mejs.swahili': 'Bahasa Swahili',
+			'mejs.swedish': 'Bahasa Sweden',
+			'mejs.tagalog': 'Bahasa Tagalog',
+			'mejs.thai': 'Bahasa Thai',
+			'mejs.turkish': 'Bahasa Turki',
+			'mejs.ukrainian': 'Bahasa Ukraine',
+			'mejs.vietnamese': 'Bahasa Vietnam',
+			'mejs.welsh': 'Bahasa Wales',
+			'mejs.yiddish': 'Bahasa Yiddish'
+		};
+	}
+})(mejs.i18n);

+ 23 - 9
app/Resources/public/assets/mediaelement/build/mediaelement-and-player.js

@@ -1017,7 +1017,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
 
 var mejs = {};
 
-mejs.version = '4.2.8';
+mejs.version = '4.2.9';
 
 mejs.html5media = {
 	properties: ['volume', 'src', 'currentTime', 'muted', 'duration', 'paused', 'ended', 'buffered', 'error', 'networkState', 'readyState', 'seeking', 'seekable', 'currentSrc', 'preload', 'bufferedBytes', 'bufferedTime', 'initialTime', 'startOffsetTime', 'defaultPlaybackRate', 'playbackRate', 'played', 'autoplay', 'loop', 'controls'],
@@ -1248,7 +1248,7 @@ Object.assign(_player2.default.prototype, {
 
 		t.exitFullscreenCallback = function (e) {
 			var key = e.which || e.keyCode || 0;
-			if (key === 27 && (Features.HAS_TRUE_NATIVE_FULLSCREEN && Features.IS_FULLSCREEN || t.isFullScreen)) {
+			if (t.options.enableKeyboard && key === 27 && (Features.HAS_TRUE_NATIVE_FULLSCREEN && Features.IS_FULLSCREEN || t.isFullScreen)) {
 				player.exitFullScreen();
 			}
 		};
@@ -1302,6 +1302,10 @@ Object.assign(_player2.default.prototype, {
 		    isNative = t.media.rendererName !== null && /(html5|native)/i.test(t.media.rendererName),
 		    containerStyles = getComputedStyle(t.getElement(t.container));
 
+		if (!t.isVideo) {
+			return;
+		}
+
 		if (t.options.useFakeFullscreen === false && Features.IS_IOS && Features.HAS_IOS_FULLSCREEN && typeof t.media.originalNode.webkitEnterFullscreen === 'function' && t.media.originalNode.canPlayType((0, _media.getTypeFromFile)(t.media.getSrc()))) {
 			t.media.originalNode.webkitEnterFullscreen();
 			return;
@@ -1390,6 +1394,10 @@ Object.assign(_player2.default.prototype, {
 		var t = this,
 		    isNative = t.media.rendererName !== null && /(native|html5)/i.test(t.media.rendererName);
 
+		if (!t.isVideo) {
+			return;
+		}
+
 		clearTimeout(t.containerSizeTimeout);
 
 		if (Features.HAS_TRUE_NATIVE_FULLSCREEN && (Features.IS_FULLSCREEN || t.isFullScreen)) {
@@ -1778,7 +1786,7 @@ Object.assign(_player2.default.prototype, {
 		    handleMouseup = function handleMouseup() {
 			if (mouseIsDown && t.getCurrentTime() !== null && t.newTime.toFixed(4) !== t.getCurrentTime().toFixed(4)) {
 				t.setCurrentTime(t.newTime);
-				t.setCurrentRail();
+				t.setCurrentRailHandle(t.newTime);
 				t.updateCurrent(t.newTime);
 			}
 			if (t.forcedHandlePause) {
@@ -1799,7 +1807,7 @@ Object.assign(_player2.default.prototype, {
 				startedPaused = t.paused;
 			}
 
-			if (t.options.keyActions.length) {
+			if (t.options.enableKeyboard && t.options.keyActions.length) {
 
 				var keyCode = e.which || e.keyCode || 0,
 				    duration = t.getDuration(),
@@ -2178,7 +2186,7 @@ Object.assign(_player2.default.prototype, {
 
 		var duration = t.getDuration();
 
-		if (isNaN(duration) || duration === Infinity || duration < 0) {
+		if (t.media !== undefined && (isNaN(duration) || duration === Infinity || duration < 0)) {
 			t.media.duration = t.options.duration = duration = 0;
 		}
 
@@ -3218,7 +3226,7 @@ Object.assign(_player2.default.prototype, {
 			mouseIsOver = false;
 		});
 		mute.addEventListener('keydown', function (e) {
-			if (t.options.keyActions.length) {
+			if (t.options.enableKeyboard && t.options.keyActions.length) {
 				var keyCode = e.which || e.keyCode || 0,
 				    volume = media.volume;
 
@@ -5167,11 +5175,12 @@ var MediaElementPlayer = function () {
 
 					delete t.node.autoplay;
 
+					t.node.setAttribute('src', '');
 					if (t.media.canPlayType((0, _media.getTypeFromFile)(src)) !== '') {
 						t.node.setAttribute('src', src);
 					}
 
-					if (~rendererName.indexOf('iframe')) {
+					if (rendererName && rendererName.indexOf('iframe') > -1) {
 						var layer = _document2.default.getElementById(t.media.id + '-iframe-overlay');
 						layer.remove();
 					}
@@ -5218,7 +5227,7 @@ var MediaElementPlayer = function () {
 				t.getElement(t.container).parentNode.insertBefore(t.node, t.getElement(t.container));
 			}
 
-			if (typeof t.media.renderer.destroy === 'function') {
+			if (t.media.renderer && typeof t.media.renderer.destroy === 'function') {
 				t.media.renderer.destroy();
 			}
 
@@ -5443,6 +5452,11 @@ var DefaultPlayer = function () {
 		get: function get() {
 			return this.getDuration();
 		}
+	}, {
+		key: 'remainingTime',
+		get: function get() {
+			return this.getDuration() - this.currentTime();
+		}
 	}, {
 		key: 'volume',
 		set: function set(volume) {
@@ -7473,7 +7487,7 @@ var SUPPORT_POINTER_EVENTS = exports.SUPPORT_POINTER_EVENTS = function () {
 	element.style.pointerEvents = 'auto';
 	element.style.pointerEvents = 'x';
 	documentElement.appendChild(element);
-	var supports = getComputedStyle && getComputedStyle(element, '').pointerEvents === 'auto';
+	var supports = getComputedStyle && (getComputedStyle(element, '') || {}).pointerEvents === 'auto';
 	element.remove();
 	return !!supports;
 }();

File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/mediaelement-and-player.min.js


+ 2 - 2
app/Resources/public/assets/mediaelement/build/mediaelement.js

@@ -1017,7 +1017,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
 
 var mejs = {};
 
-mejs.version = '4.2.8';
+mejs.version = '4.2.9';
 
 mejs.html5media = {
 	properties: ['volume', 'src', 'currentTime', 'muted', 'duration', 'paused', 'ended', 'buffered', 'error', 'networkState', 'readyState', 'seeking', 'seekable', 'currentSrc', 'preload', 'bufferedBytes', 'bufferedTime', 'initialTime', 'startOffsetTime', 'defaultPlaybackRate', 'playbackRate', 'played', 'autoplay', 'loop', 'controls'],
@@ -3192,7 +3192,7 @@ var SUPPORT_POINTER_EVENTS = exports.SUPPORT_POINTER_EVENTS = function () {
 	element.style.pointerEvents = 'auto';
 	element.style.pointerEvents = 'x';
 	documentElement.appendChild(element);
-	var supports = getComputedStyle && getComputedStyle(element, '').pointerEvents === 'auto';
+	var supports = getComputedStyle && (getComputedStyle(element, '') || {}).pointerEvents === 'auto';
 	element.remove();
 	return !!supports;
 }();

File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/mediaelement.min.js


File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/renderers/dailymotion.min.js


+ 1 - 1
app/Resources/public/assets/mediaelement/build/renderers/facebook.js

@@ -315,7 +315,7 @@ var FacebookRenderer = {
 		fbContainer.id = fb.id;
 		fbContainer.className = 'fb-video';
 		fbContainer.setAttribute('data-href', src);
-		fbContainer.setAttribute('data-allowfullscreen', true);
+		fbContainer.setAttribute('data-allowfullscreen', 'true');
 		fbContainer.setAttribute('data-controls', !!mediaElement.originalNode.controls);
 		mediaElement.originalNode.parentNode.insertBefore(fbContainer, mediaElement.originalNode);
 		mediaElement.originalNode.style.display = 'none';

File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/renderers/facebook.min.js


File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/renderers/soundcloud.min.js


File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/renderers/twitch.min.js


+ 3 - 3
app/Resources/public/assets/mediaelement/build/renderers/vimeo.js

@@ -367,9 +367,9 @@ var vimeoIframeRenderer = {
 		vimeoContainer.setAttribute('height', height);
 		vimeoContainer.setAttribute('frameBorder', '0');
 		vimeoContainer.setAttribute('src', '' + standardUrl + queryArgs);
-		vimeoContainer.setAttribute('webkitallowfullscreen', '');
-		vimeoContainer.setAttribute('mozallowfullscreen', '');
-		vimeoContainer.setAttribute('allowfullscreen', '');
+		vimeoContainer.setAttribute('webkitallowfullscreen', 'true');
+		vimeoContainer.setAttribute('mozallowfullscreen', 'true');
+		vimeoContainer.setAttribute('allowfullscreen', 'true');
 
 		mediaElement.originalNode.parentNode.insertBefore(vimeoContainer, mediaElement.originalNode);
 		mediaElement.originalNode.style.display = 'none';

File diff suppressed because it is too large
+ 0 - 0
app/Resources/public/assets/mediaelement/build/renderers/vimeo.min.js


+ 19 - 1
app/Resources/public/assets/mediaelement/changelog.md

@@ -1,5 +1,23 @@
 ### Version History
 
+*4.2.9 (2018/03/27)*
+
+* Fixed typo in documentation (https://github.com/mediaelement/mediaelement/pull/2512) @moagggi
+* Added remainingTime getter (https://github.com/mediaelement/mediaelement/pull/2505) @Lewiscowles1986
+* Fixed iframe parameters formatting for Vimeo/Facebook (https://github.com/mediaelement/mediaelement/pull/2498) @skreutzer
+* Added Malay translation (https://github.com/mediaelement/mediaelement/pull/2490) @MuhdNurHidayat
+* Fixed `getComputedStyle` in Firefox (https://github.com/mediaelement/mediaelement/pull/2487) @pgrzeszczak-neducatio
+* Fixed documentation for React usage @rafa8626
+* Added LICENSE file @rafa8626
+* Added conditionals to avoid executing `fullscreen` methods in audio tags @rafa8626
+* Added conditionals to avoid triggering keyboard events if `enableKeyboard` is false @rafa8626 
+* Added missing conditionals when destroying media @rafa8626
+* Modified Malay language in the demo @rafa8626
+* Set empty source when destroying player to prevent #2499 @rafa8626
+* Added conditional to avoid setting duration when `media` has been destroyed @rafa8626
+* Replaced callback when seeking in paused media to achieve correct behavior @rafa8626  
+* Updated documentation about using `startLanguage` and `toggleCaptionsButtonWhenOnlyOne` (https://github.com/mediaelement/mediaelement/pull/2520) @dmdewey
+
 *4.2.8 (2018/01/16)*
 
 * Clarify effect of setting `toggleCaptionsButtonWhenOnlyOne` (https://github.com/mediaelement/mediaelement/pull/2471) @cjcolvar
@@ -27,7 +45,7 @@
 * Fixed issues related to duplicated calls when triggering error and fixed style for poster when error is displayed @rafa8626
 * Fixed issue with captions not being rendered inside video frame on any state @rafa8626
 * Integrated `destroy` method in `MediaElement` class @rafa8626
-* Added validation to modify `SoundCloud` iframe atributes when using `video` tag @rafa8626
+* Added validation to modify `SoundCloud` iframe attributes when using `video` tag @rafa8626
 * Fixed issue when checking for native dimensions of `video` element to set responsive dimensions correctly @rafa8626
 * Added missing workflow to make `loop` work correctly in YouTube according to documentation @rafa8626
 * Changed paths for `hls.js` and `flv.js` renderers to always be up-to-date @rafa8626

+ 16 - 0
app/Resources/public/css/base.css

@@ -9423,3 +9423,19 @@ div.dropdown-menu.open {
 ul.dropdown-menu.inner > li > a {
     white-space: initial;
 }
+
+/* start document mp3 preview */
+.preview .mejs__container {
+    background: #aaa;
+}
+
+.preview .mejs__controls {
+    padding: 0 0 0 0;
+    background: none;
+}
+
+.preview  .mejs__button>button {
+    margin: 16px 6px;
+}
+
+/* end document mp3 preview */

+ 4 - 4
app/Resources/public/css/scorm.css

@@ -304,6 +304,10 @@ See https://support.chamilo.org/issues/6976
     background-color: #00829C;
 }
 
+.scorm_item_normal.scorm_highlight a {
+    /* color: #FFFFFF; once again this make links invisible!! */
+}
+
 /* END SCORM CSS BASE*/
 #scorm-info {
     padding: 0;
@@ -566,10 +570,6 @@ See https://support.chamilo.org/issues/6976
     border-right: 1px solid #e6e6e6;
 }
 
-.scorm_item_normal.scorm_highlight a {
-    color: #FFFFFF;
-}
-
 .scorm-collapse-list {
     padding: 0;
     margin: 0 0 10px 0;

+ 4 - 11
main/document/document.php

@@ -883,14 +883,6 @@ if (isset($_GET['createdir'])) {
     $interbreadcrumb[] = ['url' => '#', 'name' => get_lang('CreateDir')];
 }
 
-$js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
-
-$htmlHeadXtra[] = '<link rel="stylesheet" href="'.$js_path
-    .'jquery-jplayer/skin/chamilo/jplayer.blue.monday.css" type="text/css">';
-$htmlHeadXtra[] = '<script type="text/javascript" src="'.$js_path
-    .'jquery-jplayer/jplayer/jquery.jplayer.min.js"></script>';
-$mediaplayer_path = api_get_path(WEB_LIBRARY_PATH).'mediaplayer/player.swf';
-
 $documentAndFolders = DocumentManager::getAllDocumentData(
     $courseInfo,
     $curdirpath,
@@ -942,7 +934,7 @@ if (!empty($documentAndFolders)) {
                     'extension' => $extension,
                     'count' => $count,
                 ];
-                $jquery .= DocumentManager::generate_jplayer_jquery($params);
+                $jquery .= DocumentManager::generateAudioJavascript($params);
                 $count++;
             }
         }
@@ -1821,6 +1813,7 @@ $userIsSubscribed = CourseManager::is_user_subscribed_in_course(
 );
 
 $getSizeURL = api_get_path(WEB_AJAX_PATH).'document.ajax.php?a=get_dir_size&'.api_get_cidreq();
+
 if (!empty($documentAndFolders)) {
     if ($groupId == 0 || $userAccess) {
         $count = 1;
@@ -1883,8 +1876,8 @@ if (!empty($documentAndFolders)) {
 
             // Icons (clickable)
             $row[] = DocumentManager::create_document_link(
+                $http_www,
                 $document_data,
-                $courseInfo,
                 true,
                 $count,
                 $is_visible,
@@ -1904,8 +1897,8 @@ if (!empty($documentAndFolders)) {
             $session_img = api_get_session_image($document_data['session_id'], $_user['status']);
 
             $link = DocumentManager::create_document_link(
+                $http_www,
                 $document_data,
-                $courseInfo,
                 false,
                 null,
                 $is_visible,

+ 8 - 64
main/document/showinframes.php

@@ -102,11 +102,10 @@ if (!$is_allowed_to_edit && !$is_visible) {
 }
 
 $pathinfo = pathinfo($header_file);
-$jplayer_supported_files = ['mp4', 'ogv', 'flv', 'm4v', 'webm'];
-$jplayer_supported = false;
-
-if (in_array(strtolower($pathinfo['extension']), $jplayer_supported_files)) {
-    $jplayer_supported = true;
+$playerSupportedFiles = ['mp4', 'ogv', 'flv', 'm4v', 'webm'];
+$playerSupported = false;
+if (in_array(strtolower($pathinfo['extension']), $playerSupportedFiles)) {
+    $playerSupported = true;
 }
 
 $group_id = api_get_group_id();
@@ -195,21 +194,6 @@ $web_odf_supported_files = DocumentManager::get_web_odf_extension_list();
 $web_odf_supported_files[] = 'pdf';
 if (in_array(strtolower($pathinfo['extension']), $web_odf_supported_files)) {
     $show_web_odf = true;
-    /*
-    $htmlHeadXtra[] = api_get_js('webodf/webodf.js');
-    $htmlHeadXtra[] = api_get_css(api_get_path(WEB_LIBRARY_PATH).'javascript/webodf/webodf.css');
-    $htmlHeadXtra[] = '
-    <script charset="utf-8">
-        function init() {
-                var odfelement = document.getElementById("odf"),
-                odfcanvas = new odf.OdfCanvas(odfelement);
-                odfcanvas.load("'.$file_url_web.'");
-        }
-        $(document).ready(function() {
-            window.setTimeout(init, 0);
-        });
-  </script>';
-    */
     $htmlHeadXtra[] = '
     <script>
         resizeIframe = function() {
@@ -246,45 +230,8 @@ if ($isChatFolder) {
 }
 
 $execute_iframe = true;
-if ($jplayer_supported) {
+if ($playerSupported) {
     $extension = api_strtolower($pathinfo['extension']);
-    if ($extension == 'mp4') {
-        $extension = 'm4v';
-    }
-    if ($extension == 'webm') {
-        $extension = 'webmv';
-    }
-    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
-    $htmlHeadXtra[] = '<link rel="stylesheet" href="'.$js_path.'jquery-jplayer/skin/blue.monday/css/jplayer.blue.monday.css" type="text/css">';
-    $htmlHeadXtra[] = '<script type="text/javascript" src="'.$js_path.'jquery-jplayer/jplayer/jquery.jplayer.min.js"></script>';
-
-    $jquery = '
-        $("#jquery_jplayer_1").jPlayer({
-            ready: function() {
-                $(this).jPlayer("setMedia", {
-                    '.$extension.' : "'.$document_data['direct_url'].'"
-                });
-            },
-            cssSelectorAncestor: "#jp_container_1",
-            swfPath: "'.$js_path.'jquery-jplayer/jplayer/",
-            supplied: "'.$extension.'",
-            useStateClassSkin: true,
-            autoBlur: false,
-            keyEnabled: false,
-            remainingDuration: true,
-            toggleDuration: true,
-            solution: "html, flash",
-            errorAlerts: false,
-            warningAlerts: false
-        });
-    ';
-
-    $htmlHeadXtra[] = '<script>
-        $(document).ready( function() {
-            //Experimental changes to preview mp3, ogg files
-        '.$jquery.'
-        });
-    </script>';
     $execute_iframe = false;
 }
 
@@ -297,7 +244,7 @@ if ($is_freemind_available) {
     $execute_iframe = false;
 }
 
-if (!$jplayer_supported && $execute_iframe) {
+if (!$playerSupported && $execute_iframe) {
     $htmlHeadXtra[] = '<script>
     <!--
         var jQueryFrameReadyConfigPath = \''.api_get_jquery_web_path().'\';
@@ -349,11 +296,8 @@ if ($show_web_odf) {
 
 echo '</div>';
 
-if ($jplayer_supported) {
-    echo DocumentManager::generate_video_preview($document_data);
-
-    // media_element blocks jplayer disable it
-    Display::$global_template->assign('show_media_element', 0);
+if ($playerSupported) {
+    echo DocumentManager::generateVideoPreview($file_url_web, $extension);
 }
 
 if ($is_freemind_available) {

+ 0 - 82
main/exercise/exercise.class.php

@@ -5974,88 +5974,6 @@ class Exercise
         return $html;
     }
 
-    /**
-     * Create a quiz from quiz data.
-     *
-     * @param string  Title
-     * @param int     Time before it expires (in minutes)
-     * @param int     Type of exercise
-     * @param int     Whether it's randomly picked questions (1) or not (0)
-     * @param int     Whether the exercise is visible to the user (1) or not (0)
-     * @param int     Whether the results are show to the user (0) or not (1)
-     * @param int     Maximum number of attempts (0 if no limit)
-     * @param int     Feedback type
-     * @param int $propagateNegative
-     *
-     * @todo this was function was added due the import exercise via CSV
-     *
-     * @return int New exercise ID
-     */
-    public function createExercise(
-        $title,
-        $expired_time = 0,
-        $type = 2,
-        $random = 0,
-        $active = 1,
-        $results_disabled = 0,
-        $max_attempt = 0,
-        $feedback = 3,
-        $propagateNegative = 0
-    ) {
-        $tbl_quiz = Database::get_course_table(TABLE_QUIZ_TEST);
-        $type = intval($type);
-        $random = intval($random);
-        $active = intval($active);
-        $results_disabled = intval($results_disabled);
-        $max_attempt = intval($max_attempt);
-        $feedback = intval($feedback);
-        $expired_time = intval($expired_time);
-        $title = Database::escape_string($title);
-        $propagateNegative = intval($propagateNegative);
-        $sessionId = api_get_session_id();
-        $course_id = api_get_course_int_id();
-        // Save a new quiz
-        $sql = "INSERT INTO $tbl_quiz (
-                c_id,
-                title,
-                type,
-                random,
-                active,
-                results_disabled,
-                max_attempt,
-                start_time,
-                end_time,
-                feedback_type,
-                expired_time,
-                session_id,
-                propagate_neg
-            )
-            VALUES (
-                '$course_id',
-                '$title',
-                $type,
-                $random,
-                $active,
-                $results_disabled,
-                $max_attempt,
-                '',
-                '',
-                $feedback,
-                $expired_time,
-                $sessionId,
-                $propagateNegative
-            )";
-        Database::query($sql);
-        $quiz_id = Database::insert_id();
-
-        if ($quiz_id) {
-            $sql = "UPDATE $tbl_quiz SET id = iid WHERE iid = {$quiz_id} ";
-            Database::query($sql);
-        }
-
-        return $quiz_id;
-    }
-
     /**
      * Returns the exercise result.
      *

+ 16 - 17
main/exercise/upload_exercise.php

@@ -266,17 +266,16 @@ function lp_upload_quiz_action_handling()
 
         // Quiz object
         $exercise = new Exercise();
-        $quiz_id = $exercise->createExercise(
-            $quizTitle,
-            $expired_time,
-            $type,
-            $random,
-            $active,
-            $results,
-            $max_attempt,
-            $feedback,
-            $propagateNegative
-        );
+        $exercise->updateTitle($quizTitle);
+        $exercise->updateExpiredTime($expired_time);
+        $exercise->updateType($type);
+        $exercise->setRandom($random);
+        $exercise->active = $active;
+        $exercise->updateResultsDisabled($results);
+        $exercise->updateAttempts($max_attempt);
+        $exercise->updateFeedbackType($feedback);
+        $exercise->updatePropagateNegative($propagateNegative);
+        $quiz_id = $exercise->save();
 
         if ($quiz_id) {
             // insert into the item_property table
@@ -387,7 +386,7 @@ function lp_upload_quiz_action_handling()
                                 $score = 0;
                                 if (strtolower($answer_data['extra']) == 'x') {
                                     $correct = 1;
-                                    $score = isset($scoreList[$i]) ? $scoreList[$i] : null;
+                                    $score = isset($scoreList[$i]) ? $scoreList[$i] : 0;
                                     $comment = isset($feedbackTrueList[$i]) ? $feedbackTrueList[$i] : '';
                                 } else {
                                     $comment = isset($feedbackFalseList[$i]) ? $feedbackFalseList[$i] : '';
@@ -439,7 +438,7 @@ function lp_upload_quiz_action_handling()
                                     $id
                                 );
 
-                                $total += $score;
+                                $total += (float) $score;
                                 $id++;
                             }
 
@@ -461,7 +460,7 @@ function lp_upload_quiz_action_handling()
                                         $questionObj->updateWeighting($total);
                                         break;
                                 }
-                                $questionObj->save();
+                                $questionObj->save($exercise);
                             }
                         }
                         break;
@@ -470,7 +469,7 @@ function lp_upload_quiz_action_handling()
                         $questionObj = Question::read($question_id, $courseId);
                         if ($questionObj) {
                             $questionObj->updateWeighting($globalScore);
-                            $questionObj->save();
+                            $questionObj->save($exercise);
                         }
                         break;
                     case FILL_IN_BLANKS:
@@ -503,7 +502,7 @@ function lp_upload_quiz_action_handling()
                         $questionObj = Question::read($question_id, $courseId);
                         if ($questionObj) {
                             $questionObj->updateWeighting($globalScore);
-                            $questionObj->save();
+                            $questionObj->save($exercise);
                         }
                         break;
                     case MATCHING:
@@ -534,7 +533,7 @@ function lp_upload_quiz_action_handling()
                         $questionObj = Question::read($question_id, $courseId);
                         if ($questionObj) {
                             $questionObj->updateWeighting($globalScore);
-                            $questionObj->save();
+                            $questionObj->save($exercise);
                         }
                         break;
                 }

+ 1 - 1
main/inc/introductionSection.inc.php

@@ -345,7 +345,7 @@ if ($intro_dispCommand) {
 }
 
 $nameSection = get_lang('AddCustomCourseIntro');
-if($moduleId != 'course_homepage'){
+if ($moduleId != 'course_homepage') {
     $nameSection = get_lang('AddCustomToolsIntro');
 }
 

+ 56 - 126
main/inc/lib/document.lib.php

@@ -104,6 +104,7 @@ class DocumentManager
             'etx' => 'text/x-setext',
             'exe' => 'application/octet-stream',
             'ez' => 'application/andrew-inset',
+            'flv' => 'video/flv',
             'gif' => 'image/gif',
             'gtar' => 'application/x-gtar',
             'gz' => 'application/x-gzip',
@@ -375,6 +376,7 @@ class DocumentManager
                     header('Content-type: application/octet-stream');
                     break;
             }
+
             header('Content-type: '.$contentType);
             header('Content-Length: '.$len);
             $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
@@ -3076,29 +3078,16 @@ class DocumentManager
      *
      * @return string
      */
-    public static function generate_jplayer_jquery($params = [])
+    public static function generateAudioJavascript($params = [])
     {
-        $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
-
         $js = '
-            $("#jquery_jplayer_'.$params['count'].'").jPlayer({
-                ready: function() {
-                    $(this).jPlayer("setMedia", {
-                        '.$params['extension'].' : "'.$params['url'].'"
-                    });
-                },
-                play: function() { // To avoid both jPlayers playing together.
-                    $(this).jPlayer("pauseOthers");
-                },
-                //errorAlerts: true,
-                //warningAlerts: true,
-                swfPath: "'.$js_path.'jquery-jplayer/jplayer/",
-                //supplied: "m4a, oga, mp3, ogg, wav",
-                supplied: "'.$params['extension'].'",
-                wmode: "window",
-                solution: "flash, html",  // Do not change this setting
-                cssSelectorAncestor: "#jp_container_'.$params['count'].'",
-            });  	 '."\n\n";
+            $(\'video:not(.skip), audio.audio_preview\').mediaelementplayer({
+                features: [\'playpause\'],
+                audioWidth: 30,
+                audioHeight: 30,
+                success: function(mediaElement, originalNode, instance) {                
+                }
+            });';
 
         return $js;
     }
@@ -3106,94 +3095,34 @@ class DocumentManager
     /**
      * Shows a play icon next to the document title in the document list.
      *
-     * @param int
-     * @param string
+     * @param string $documentWebPath
+     * @param array  $documentInfo
      *
-     * @return string html content
+     * @return string
      */
-    public static function generate_media_preview($i, $type = 'simple')
+    public static function generateAudioPreview($documentWebPath, $documentInfo)
     {
-        $i = intval($i);
-        $extra_controls = $progress = '';
-        if ($type == 'advanced') {
-            $extra_controls = ' <li><a href="javascript:;" class="jp-stop" tabindex="1">stop</a></li>
-                                <li><a href="#" class="jp-mute" tabindex="1">mute</a></li>
-                                <li><a href="#" class="jp-unmute" tabindex="1">unmute</a></li>';
-            $progress = '<div class="jp-progress">
-                                <div class="jp-seek-bar">
-                                    <div class="jp-play-bar"></div>
-                                </div>
-                            </div>';
-        }
-
-        //Shows only the play button
-        $html = '<div id="jquery_jplayer_'.$i.'" class="jp-jplayer"></div>
-                <div id="jp_container_'.$i.'" class="jp-audio">
-                    <div class="jp-type-single">
-                        <div class="jp-gui jp-interface">
-                            <ul class="jp-controls">
-                                <li><a href="javascript:;" class="jp-play" tabindex="1">play</a></li>
-                                <li><a href="javascript:;" class="jp-pause" tabindex="1">pause</a></li>
-                                '.$extra_controls.'
-                            </ul>
-                            '.$progress.'
-                        </div>
-                    </div>
-                </div>';
+        $filePath = $documentWebPath.$documentInfo['path'];
+        $extension = $documentInfo['file_extension'];
+        $html = '<span class="preview"> <audio class="audio_preview skip" src="'.$filePath.'" type="audio/'.$extension.'" > </audio></span>';
 
         return $html;
     }
 
     /**
-     * @param array $document_data
+     * @param string $file
+     * @param string $extension
      *
      * @return string
      */
-    public static function generate_video_preview($document_data = [])
+    public static function generateVideoPreview($file, $extension)
     {
-        $html = '
-        <div id="jp_container_1" class="jp-video center-block" role="application" aria-label="media player">
-            <div class="jp-type-single">
-                <div id="jquery_jplayer_1" class="jp-jplayer"></div>
-                <div class="jp-gui">
-                    <div class="jp-video-play">
-                    </div>
-                    <div class="jp-interface">
-                        <div class="jp-progress">
-                            <div class="jp-seek-bar">
-                                <div class="jp-play-bar"></div>
-                            </div>
-                        </div>
-                        <div class="jp-current-time" role="timer" aria-label="time">&nbsp;</div>
-                        <div class="jp-duration" role="timer" aria-label="duration">&nbsp;</div>
-                        <div class="jp-controls-holder">
-                          <div class="jp-controls">
-                            <button class="jp-play" role="button" tabindex="0">play</button>
-                            <button class="jp-stop" role="button" tabindex="0">stop</button>
-                          </div>
-                          <div class="jp-volume-controls">
-                            <button class="jp-mute" role="button" tabindex="0">mute</button>
-                            <button class="jp-volume-max" role="button" tabindex="0">max volume</button>
-                            <div class="jp-volume-bar">
-                                <div class="jp-volume-bar-value"></div>
-                            </div>
-                          </div>
-                          <div class="jp-toggles">
-                            <button class="jp-repeat" role="button" tabindex="0">repeat</button>
-                            <button class="jp-full-screen" role="button" tabindex="0">full screen</button>
-                          </div>
-                        </div>
-                        <div class="jp-details">
-                          <div class="jp-title" aria-label="title">&nbsp;</div>
-                        </div>
-                    </div>
-                </div>
-                <div class="jp-no-solution">
-                    <span>'.get_lang('UpdateRequire').'</span>
-                    '.get_lang("ToPlayTheMediaYouWillNeedToUpdateYourBrowserToARecentVersionYouCanAlsoDownloadTheFile").'
-                </div>
-            </div>
-        </div>';
+        $type = '';
+        /*if ($extension != 'flv') {
+
+        }*/
+        //$type = "video/$extension";
+        $html = '<video id="myvideo"  src="'.$file.'" controls '.$type.'">';
 
         return $html;
     }
@@ -4971,20 +4900,20 @@ class DocumentManager
     /**
      * Create a html hyperlink depending on if it's a folder or a file.
      *
-     * @param array $document_data
-     * @param array $course_info
-     * @param bool  $show_as_icon      - if it is true, only a clickable icon will be shown
-     * @param int   $visibility        (1/0)
-     * @param int   $counter
-     * @param int   $size
-     * @param bool  $isAllowedToEdit
-     * @param bool  $isCertificateMode
+     * @param string $documentWebPath
+     * @param array  $document_data
+     * @param bool   $show_as_icon - if it is true, only a clickable icon will be shown
+     * @param int    $visibility   (1/0)
+     * @param int    $counter
+     * @param int    $size
+     * @param bool   $isAllowedToEdit
+     * @param bool   $isCertificateMode
      *
      * @return string url
      */
     public static function create_document_link(
+        $documentWebPath,
         $document_data,
-        $course_info,
         $show_as_icon = false,
         $counter = null,
         $visibility,
@@ -4993,10 +4922,10 @@ class DocumentManager
         $isCertificateMode = false
     ) {
         global $dbl_click_id;
+        $www = $documentWebPath;
 
-        $current_session_id = api_get_session_id();
+        $sessionId = api_get_session_id();
         $courseParams = api_get_cidreq();
-        $www = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/document';
         $webODFList = self::get_web_odf_extension_list();
 
         // Get the title or the basename depending on what we're using
@@ -5019,11 +4948,11 @@ class DocumentManager
 
         if (!$show_as_icon) {
             // Build download link (icon)
-            $forcedownload_link = ($filetype == 'folder') ? api_get_self().'?'.$courseParams.'&action=downloadfolder&id='.$document_data['id'] : api_get_self().'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
+            $forcedownload_link = $filetype == 'folder' ? api_get_self().'?'.$courseParams.'&action=downloadfolder&id='.$document_data['id'] : api_get_self().'?'.$courseParams.'&amp;action=download&amp;id='.$document_data['id'];
             // Folder download or file download?
-            $forcedownload_icon = ($filetype == 'folder') ? 'save_pack.png' : 'save.png';
+            $forcedownload_icon = $filetype == 'folder' ? 'save_pack.png' : 'save.png';
             // Prevent multiple clicks on zipped folder download
-            $prevent_multiple_click = ($filetype == 'folder') ? " onclick=\"javascript: if(typeof clic_$dbl_click_id == 'undefined' || !clic_$dbl_click_id) { clic_$dbl_click_id=true; window.setTimeout('clic_".($dbl_click_id++)."=false;',10000); } else { return false; }\"" : '';
+            $prevent_multiple_click = $filetype == 'folder' ? " onclick=\"javascript: if(typeof clic_$dbl_click_id == 'undefined' || !clic_$dbl_click_id) { clic_$dbl_click_id=true; window.setTimeout('clic_".($dbl_click_id++)."=false;',10000); } else { return false; }\"" : '';
         }
 
         $target = '_self';
@@ -5091,6 +5020,8 @@ class DocumentManager
         $curdirpath = isset($_GET['curdirpath']) ? Security::remove_XSS($_GET['curdirpath']) : null;
         $send_to = null;
         $checkExtension = $path;
+        $extension = pathinfo($path, PATHINFO_EXTENSION);
+        $document_data['file_extension'] = $extension;
 
         if (!$show_as_icon) {
             if ($filetype == 'folder') {
@@ -5099,9 +5030,9 @@ class DocumentManager
                     api_get_setting('students_download_folders') == 'true'
                 ) {
                     // filter: when I am into a shared folder, I can only show "my shared folder" for donwload
-                    if (self::is_shared_folder($curdirpath, $current_session_id)) {
+                    if (self::is_shared_folder($curdirpath, $sessionId)) {
                         if (preg_match('/shared_folder\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
-                            preg_match('/shared_folder_session_'.$current_session_id.'\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
+                            preg_match('/shared_folder_session_'.$sessionId.'\/sf_user_'.api_get_user_id().'$/', urldecode($forcedownload_link)) ||
                             $isAllowedToEdit || api_is_platform_admin()
                         ) {
                             $force_download_html = ($size == 0) ? '' : '<a href="'.$forcedownload_link.'" style="float:right"'.$prevent_multiple_click.'>'.
@@ -5136,7 +5067,6 @@ class DocumentManager
             }
 
             $pdf_icon = '';
-            $extension = pathinfo($path, PATHINFO_EXTENSION);
             if (!$isAllowedToEdit &&
                 api_get_setting('students_export2pdf') == 'true' &&
                 $filetype == 'file' &&
@@ -5152,7 +5082,7 @@ class DocumentManager
             }
 
             if ($filetype == 'file') {
-                // Sound preview with jplayer
+                // Sound preview
                 if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
                     (preg_match('/wav$/i', urldecode($checkExtension))) ||
                     preg_match('/ogg$/i', urldecode($checkExtension))
@@ -5214,16 +5144,16 @@ class DocumentManager
             // Icon column
             if (preg_match('/shared_folder/', urldecode($checkExtension)) &&
                 preg_match('/shared_folder$/', urldecode($checkExtension)) == false &&
-                preg_match('/shared_folder_session_'.$current_session_id.'$/', urldecode($url)) == false
+                preg_match('/shared_folder_session_'.$sessionId.'$/', urldecode($url)) == false
             ) {
                 if ($filetype == 'file') {
-                    //Sound preview with jplayer
+                    //Sound preview
                     if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
                         (preg_match('/wav$/i', urldecode($checkExtension))) ||
                         preg_match('/ogg$/i', urldecode($checkExtension))) {
-                        $sound_preview = self::generate_media_preview($counter);
+                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
 
-                        return $sound_preview;
+                        return $soundPreview;
                     } elseif (
                         // Show preview
                         preg_match('/swf$/i', urldecode($checkExtension)) ||
@@ -5258,9 +5188,9 @@ class DocumentManager
                     if (preg_match('/mp3$/i', urldecode($checkExtension)) ||
                         (preg_match('/wav$/i', urldecode($checkExtension))) ||
                         preg_match('/ogg$/i', urldecode($checkExtension))) {
-                        $sound_preview = self::generate_media_preview($counter);
+                        $soundPreview = self::generateAudioPreview($documentWebPath, $document_data);
 
-                        return $sound_preview;
+                        return $soundPreview;
                     } elseif (
                         //Show preview
                         preg_match('/html$/i', urldecode($checkExtension)) ||
@@ -5303,7 +5233,7 @@ class DocumentManager
     public static function build_document_icon_tag($type, $path, $isAllowedToEdit = null)
     {
         $basename = basename($path);
-        $current_session_id = api_get_session_id();
+        $sessionId = api_get_session_id();
         if (is_null($isAllowedToEdit)) {
             $isAllowedToEdit = api_is_allowed_to_edit(null, true);
         }
@@ -5328,7 +5258,7 @@ class DocumentManager
                 $basename = get_lang('UserFolder').' '.$userInfo['complete_name'];
                 $user_image = true;
             } elseif (strstr($path, 'shared_folder_session_')) {
-                $sessionName = api_get_session_name($current_session_id);
+                $sessionName = api_get_session_name($sessionId);
                 if ($isAllowedToEdit) {
                     $basename = '***('.$sessionName.')*** '.get_lang('HelpUsersFolder');
                 } else {
@@ -5693,16 +5623,16 @@ class DocumentManager
      * Checks whether the user is in shared folder.
      *
      * @param string $curdirpath
-     * @param int    $current_session_id
+     * @param int    $sessionId
      *
      * @return bool Return true when user is into shared folder
      */
-    public static function is_shared_folder($curdirpath, $current_session_id)
+    public static function is_shared_folder($curdirpath, $sessionId)
     {
         $clean_curdirpath = Security::remove_XSS($curdirpath);
         if ($clean_curdirpath == '/shared_folder') {
             return true;
-        } elseif ($clean_curdirpath == '/shared_folder_session_'.$current_session_id) {
+        } elseif ($clean_curdirpath == '/shared_folder_session_'.$sessionId) {
             return true;
         } else {
             return false;

+ 1 - 1
main/inc/lib/sessionmanager.lib.php

@@ -4101,7 +4101,7 @@ class SessionManager
 
         $selectedField = '
             u.user_id, u.lastname, u.firstname, u.username, su.relation_type, au.access_url_id,
-            su.moved_to, su.moved_status, su.moved_at
+            su.moved_to, su.moved_status, su.moved_at, su.registered_at
         ';
 
         if ($getCount) {

+ 15 - 7
main/lp/learnpath.class.php

@@ -2296,7 +2296,7 @@ class learnpath
             $type_quiz = false;
 
             foreach ($list as $toc) {
-                if ($toc['id'] == $_SESSION['oLP']->current && ($toc['type'] == 'quiz')) {
+                if ($toc['id'] == $_SESSION['oLP']->current && $toc['type'] == 'quiz') {
                     $type_quiz = true;
                 }
             }
@@ -3189,7 +3189,7 @@ class learnpath
         if (empty($course_id)) {
             $course_id = api_get_course_int_id();
         } else {
-            $course_id = intval($course_id);
+            $course_id = (int) $course_id;
         }
         $list = [];
 
@@ -3197,8 +3197,8 @@ class learnpath
             return $list;
         }
 
-        $lp = intval($lp);
-        $parent = intval($parent);
+        $lp = (int) $lp;
+        $parent = (int) $parent;
 
         $tbl_lp_item = Database::get_course_table(TABLE_LP_ITEM);
         $sql = "SELECT iid FROM $tbl_lp_item
@@ -12788,7 +12788,8 @@ EOD;
                     .'&lp_view_id='.$lpViewId.'&'.$extraParams;
             case TOOL_FORUM:
                 return $main_dir_path.'forum/viewforum.php?forum='.$id.'&lp=true&'.$extraParams;
-            case TOOL_THREAD:  //forum post
+            case TOOL_THREAD:
+                // forum post
                 $tbl_topics = Database::get_course_table(TABLE_FORUM_THREAD);
                 if (empty($id)) {
                     return '';
@@ -12811,8 +12812,15 @@ EOD;
                     ->getRepository('ChamiloCourseBundle:CDocument')
                     ->findOneBy(['cId' => $course_id, 'iid' => $id]);
 
-                if (!$document) {
-                    return '';
+                if (empty($document)) {
+                    // Try with normal id
+                    $document = $em
+                        ->getRepository('ChamiloCourseBundle:CDocument')
+                        ->findOneBy(['cId' => $course_id, 'id' => $id]);
+
+                    if (empty($document)) {
+                        return '';
+                    }
                 }
 
                 $documentPathInfo = pathinfo($document->getPath());

+ 6 - 2
main/session/resume_session.php

@@ -265,7 +265,8 @@ if (!empty($userList)) {
     );
     $table->setHeaderContents(0, 0, get_lang('User'));
     $table->setHeaderContents(0, 1, get_lang('Status'));
-    $table->setHeaderContents(0, 2, get_lang('Actions'));
+    $table->setHeaderContents(0, 2, get_lang('Registered'));
+    $table->setHeaderContents(0, 3, get_lang('Actions'));
 
     $row = 1;
     foreach ($userList as $user) {
@@ -334,8 +335,11 @@ if (!empty($userList)) {
                 $status = get_lang('Student');
         }
 
+        $registered = !empty($user['registered_at']) ? Display::dateToStringAgoAndLongDate($user['registered_at']) : '';
+
         $table->setCellContents($row, 1, $status);
-        $table->setCellContents($row, 2, $link);
+        $table->setCellContents($row, 2, $registered);
+        $table->setCellContents($row, 3, $link);
         $row++;
     }
     $userListToShow .= $table->toHtml();

+ 2 - 2
main/template/default/layout/footer.js.tpl

@@ -91,11 +91,11 @@
             $("#" + inputId).filterByText($("#" + inputId + "-filter"));
         });
 
-        $(".jp-jplayer audio").addClass('skip');
-
         // Mediaelement
         if ( {{ show_media_element }} == 1) {
             $('video:not(.skip), audio:not(.skip)').mediaelementplayer({
+                pluginPath: '{{ _p.web }}web/assets/mediaelement/build/',
+                renderers: ['html5', 'flash_video', 'native_flv'],
                 success: function(mediaElement, originalNode, instance) {
                 }
             });

+ 14 - 9
main/work/view.php

@@ -177,15 +177,20 @@ if ((user_is_author($id) || $isDrhOfCourse || (api_is_allowed_to_edit() || api_i
                     ),
                     api_get_path(WEB_CODE_PATH).'work/work.php?'.api_get_cidreq()
                 );
-                $actions .= Display::url(
-                    Display::return_icon(
-                        'save.png',
-                        get_lang('Download'),
-                        null,
-                        ICON_SIZE_MEDIUM
-                    ),
-                    $work['download_url']
-                );
+
+                // Check if file can be downloaded
+                $file = getFileContents($work['id'], $courseInfo, api_get_session_id(), false);
+                if (!empty($file)) {
+                    $actions .= Display::url(
+                        Display::return_icon(
+                            'save.png',
+                            get_lang('Download'),
+                            null,
+                            ICON_SIZE_MEDIUM
+                        ),
+                        $work['download_url']
+                    );
+                }
             }
         }
 

+ 24 - 17
main/work/work.lib.php

@@ -2892,9 +2892,7 @@ function allowOnlySubscribedUser($userId, $workId, $courseId)
         return true;
     }
 
-    if (userIsSubscribedToWork($userId, $workId, $courseId) == false) {
-        api_not_allowed(true);
-    }
+    return userIsSubscribedToWork($userId, $workId, $courseId);
 }
 
 /**
@@ -5120,16 +5118,16 @@ function getFile($id, $course_info, $download = true, $isCorrection = false)
  * Get the file contents for an assigment.
  *
  * @param int   $id
- * @param array $course_info
- * @param int Session ID
- * @param $correction
+ * @param array $courseInfo
+ * @param int   $sessionId
+ * @param bool  $correction
  *
  * @return array|bool
  */
-function getFileContents($id, $course_info, $sessionId = 0, $correction = false)
+function getFileContents($id, $courseInfo, $sessionId = 0, $correction = false)
 {
-    $id = intval($id);
-    if (empty($course_info) || empty($id)) {
+    $id = (int) $id;
+    if (empty($courseInfo) || empty($id)) {
         return false;
     }
     if (empty($sessionId)) {
@@ -5137,10 +5135,11 @@ function getFileContents($id, $course_info, $sessionId = 0, $correction = false)
     }
 
     $table = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
-    if (!empty($course_info['real_id'])) {
-        $sql = 'SELECT *
-                FROM '.$table.'
-                WHERE c_id = '.$course_info['real_id'].' AND id = "'.$id.'"';
+    if (!empty($courseInfo['real_id'])) {
+        $sql = "SELECT *
+                FROM $table
+                WHERE c_id = ".$courseInfo['real_id']." AND id = $id";
+
         $result = Database::query($sql);
         if ($result && Database::num_rows($result)) {
             $row = Database::fetch_array($result, 'ASSOC');
@@ -5166,12 +5165,16 @@ function getFileContents($id, $course_info, $sessionId = 0, $correction = false)
                 return false;
             }
 
-            allowOnlySubscribedUser(
+            $isAllow = allowOnlySubscribedUser(
                 api_get_user_id(),
                 $row['parent_id'],
-                $course_info['real_id']
+                $courseInfo['real_id']
             );
 
+            if (empty($isAllow)) {
+                return false;
+            }
+
             /*
             field show_score in table course :
                 0 =>    New documents are visible for all users
@@ -5201,7 +5204,7 @@ function getFileContents($id, $course_info, $sessionId = 0, $correction = false)
             */
 
             $work_is_visible = $item_info['visibility'] == 1 && $row['accepted'] == 1;
-            $doc_visible_for_all = (int) $course_info['show_score'] === 0;
+            $doc_visible_for_all = (int) $courseInfo['show_score'] === 0;
 
             $is_editor = api_is_allowed_to_edit(true, true, true);
             $student_is_owner_of_work = user_is_author($row['id'], api_get_user_id());
@@ -5582,7 +5585,11 @@ function protectWork($courseInfo, $workId)
         api_not_allowed(true);
     }
 
-    allowOnlySubscribedUser($userId, $workId, $courseInfo['real_id']);
+    $isAllow = allowOnlySubscribedUser($userId, $workId, $courseInfo['real_id']);
+    if (empty($isAllow)) {
+        api_not_allowed(true);
+    }
+
     $groupInfo = GroupManager::get_group_properties($groupId);
 
     if (!empty($groupId)) {

+ 0 - 2
src/Chamilo/ThemeBundle/Resources/views/Layout/footer.js.twig

@@ -66,8 +66,6 @@
             $("#" + inputId).filterByText($("#" + inputId + "-filter"));
         });
 
-        $(".jp-jplayer audio").addClass('skip');
-
         // Mediaelement
         //jQuery('video:not(.skip), audio:not(.skip)').mediaelementplayer(/* Options */);
 

+ 9 - 1
tests/behat/features/toolExercise.feature

@@ -312,4 +312,12 @@ Feature: Exercise tool
   Scenario: Delete an exercise category
     Given I am on "/main/exercise/tests_category.php?cidReq=TEMP"
     And I follow "Delete"
-    Then I should see "Category deleted"
+    Then I should see "Category deleted"
+
+  Scenario: Import exercise from excel
+    Given I am on "/main/exercise/upload_exercise.php?cidReq=TEMP"
+    Then I should see "Import quiz from Excel"
+    Then I attach the file "/main/exercise/quiz_template.xls" to "user_upload_quiz"
+    And I press "Upload"
+    And wait for the page to be loaded
+    Then I should see "Definition of oligarchy"

+ 1 - 2
tests/behat/features/toolWork.feature

@@ -48,8 +48,7 @@ Feature: Work tool
     And wait for the page to be loaded
     Then I should see "Work description"
     And wait for the page to be loaded
-    Then I follow "Correct and rate"
-    Then I follow "Download"
+    Then I should see "base.css"
 
 #  Scenario: Add a comment and a attachment to the work previously uploaded by student
 #    Given I am a platform administrator

Some files were not shown because too many files changed in this diff