diff --git a/www/addons/mod/assign/controllers/edit.js b/www/addons/mod/assign/controllers/edit.js index dea46dc7582..9b05553adef 100644 --- a/www/addons/mod/assign/controllers/edit.js +++ b/www/addons/mod/assign/controllers/edit.js @@ -65,13 +65,13 @@ angular.module('mm.addons.mod_assign') // Cannot connect. Get cached data. return $mmaModAssign.getSubmissionStatus(assign.id, userId, isBlind).then(function(response) { var userSubmission = $mmaModAssign.getSubmissionObjectFromAttempt(assign, response.lastattempt); - if (userSubmission && (userSubmission.status == 'new' || userSubmission.status == 'reopened')) { - // It's a new submission, allow creating it in offline. + if ($mmaModAssignHelper.canEditSubmissionOffline(assign, userSubmission)) { return response; - } else { - // User is editing a submission, we don't allow it in offline for now so reject. - return $q.reject(error); } + + // Submission cannot be edited in offline, reject. + $scope.allowOffline = false; + return $q.reject(error); }); }).then(function(response) { if (!response.lastattempt.canedit) { @@ -80,7 +80,7 @@ angular.module('mm.addons.mod_assign') } $scope.userSubmission = $mmaModAssign.getSubmissionObjectFromAttempt(assign, response.lastattempt); - $scope.allowOffline = $scope.userSubmission.status == 'new' || $scope.userSubmission.status == 'reopened'; + $scope.allowOffline = true; // If offline isn't allowed we shouldn't have reached this point. // Only show submission statement if we are editing our own submission. if (assign.requiresubmissionstatement && !assign.submissiondrafts && userId == $mmSite.getUserId()) { diff --git a/www/addons/mod/assign/services/helper.js b/www/addons/mod/assign/services/helper.js index d994c5c6b25..f43c1e8a936 100644 --- a/www/addons/mod/assign/services/helper.js +++ b/www/addons/mod/assign/services/helper.js @@ -26,6 +26,36 @@ angular.module('mm.addons.mod_assign') var self = {}; + /** + * Check if a submission can be edited in offline. + * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignHelper#canEditSubmissionOffline + * @param {Object} assign Assignment. + * @param {Object} submission Submission. + * @return {Boolean} True if can edit offline, false otherwise. + */ + self.canEditSubmissionOffline = function(assign, submission) { + if (!submission) { + return false; + } + + if (submission.status == 'new' || submission.status == 'reopened') { + // It's a new submission, allow creating it in offline. + return true; + } + + for (var i = 0; i < submission.plugins.length; i++) { + var plugin = submission.plugins[i]; + if (!$mmaModAssignSubmissionDelegate.canPluginEditOffline(assign, submission, plugin)) { + return false; + } + } + + return true; + }; + /** * Clear plugins temporary data because a submission was cancelled. * diff --git a/www/addons/mod/assign/services/submissiondelegate.js b/www/addons/mod/assign/services/submissiondelegate.js index 0cfbb9c27a5..9fdc2345d6c 100644 --- a/www/addons/mod/assign/services/submissiondelegate.js +++ b/www/addons/mod/assign/services/submissiondelegate.js @@ -53,6 +53,27 @@ angular.module('mm.addons.mod_assign') updatePromises = {}, lastUpdateHandlersStart; + /** + * Check if the plugin can be edited in offline for existing submissions. + * In general, this should return false if the plugin uses Moodle filters. The reason is that the app only prefetches + * filtered data, and the user should edit unfiltered data. + * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionDelegate#canPluginEditOffline + * @param {Object} assign Assignment. + * @param {Object} submission Submission. + * @param {Object} plugin Plugin. + * @return {Boolean} Whether the plugin can be edited in offline for existing submissions. + */ + self.canPluginEditOffline = function(assign, submission, plugin) { + var handler = self.getPluginHandler(plugin.type); + if (handler && handler.canEditOffline) { + return handler.canEditOffline(assign, submission, plugin); + } + return false; + }; + /** * Clear some temporary data because a submission was cancelled. * @@ -381,40 +402,44 @@ angular.module('mm.addons.mod_assign') * @param {String|Object|Function} handler Must be resolved to an object defining the following properties. Or to a function * returning an object defining these properties. See {@link $mmUtil#resolveObject}. * - isEnabled (Boolean|Promise) Whether or not the handler is enabled on a site level. - * When using a promise, it should return a boolean. + * When using a promise, it should return a boolean. * - isEnabledForEdit (Boolean|Promise) Whether or not the handler is enabled for edit on a site - * level. When using a promise, it should return a boolean. - * This should return true if the plugin has no submission component. + * level. When using a promise, it should return a boolean. + * This should return true if the plugin has no submission component. * - getDirectiveName(plugin, edit) (String) Optional. Returns the name of the directive to render - * the plugin. + * the plugin. * - prepareSubmissionData(assign, submission, plugin, inputData, pluginData, offline, userId, siteId). - * Should prepare and add to pluginData the data to send to server - * based in the input. Return promise if async. + * Should prepare and add to pluginData the data to send to server based in the + * input. Return promise if async. * - copySubmissionData(assign, plugin, pluginData). Function meant to copy a submission. Should - * add to pluginData the data to send to server based in the data - * in plugin (previous attempt). + * add to pluginData the data to send to server based in the data in plugin + * (previous attempt). * - hasDataChanged(assign, submission, plugin, inputData) (Promise|Boolean) Check if the - * submission data has changed for this plugin. + * submission data has changed for this plugin. * - clearTmpData(assign, submission, plugin, inputData). Optional. Should clear temporary data - * for a cancelled submission. + * for a cancelled submission. * - getSizeForCopy(assign, plugin). Optional. Get the size of data (in bytes) this plugin will - * send to copy a previous attempt. + * send to copy a previous attempt. * - getSizeForEdit(assign, submission, plugin, inputData). Optional. Get the size of data (in - * bytes) this plugin will send to add or edit a submission. + * bytes) this plugin will send to add or edit a submission. * - getPluginFiles(assign, submission, plugin, siteId). Optional. Get files used by this plugin. - * The files returned by this function will be prefetched when the - * user prefetches the assign. + * The files returned by this function will be prefetched when the user + * prefetches the assign. * - prefetch(assign, submission, plugin, siteId). Optional. Prefetch any required data for the - * plugin. This should NOT prefetch files. Files to be prefetched - * should be returned by the getPluginFiles function. + * plugin. This should NOT prefetch files. Files to be prefetched should be + * returned by the getPluginFiles function. * - deleteOfflineData(assign, submission, plugin, offlineData, siteId). Optional. Delete any - * stored data for the plugin and submission. + * stored data for the plugin and submission. * - prepareSyncData(assign, submission, plugin, offlineData, pluginData, siteId). Optional. Should - * prepare and add to pluginData the data to send to server based in - * the offline data stored. This is to perform a synchronziation. + * prepare and add to pluginData the data to send to server based in the offline + * data stored. This is to perform a synchronziation. * - getPluginName(plugin). Optional. Should return a human readable String. If not present, default - * translation will be applied, if translation not found, optional - * name will be used. + * translation will be applied. If translation not found, optional name will + * be used. + * - canEditOffline(assign, submission, plugin). Optional. True if the plugin can be edited in + * offline for existing submissions. In general, this should return false if the + * plugin uses Moodle filters. The reason is that the app only prefetches filtered + * data, and the user should edit unfiltered data. Defaults to false. */ self.registerHandler = function(addon, pluginType, handler) { if (typeof handlers[pluginType] !== 'undefined') { diff --git a/www/addons/mod/assign/submission/comments/handlers.js b/www/addons/mod/assign/submission/comments/handlers.js index 56b7cbf496f..76474509ae7 100644 --- a/www/addons/mod/assign/submission/comments/handlers.js +++ b/www/addons/mod/assign/submission/comments/handlers.js @@ -25,9 +25,30 @@ angular.module('mm.addons.mod_assign') var self = {}; + /** + * Check if the plugin can be edited in offline for existing submissions. + * In general, this should return false if the plugin uses Moodle filters. The reason is that the app only prefetches + * filtered data, and the user should edit unfiltered data. + * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionCommentsHandler#canEditOffline + * @param {Object} assign Assignment. + * @param {Object} submission Submission. + * @param {Object} plugin Plugin. + * @return {Boolean} Whether the plugin can be edited in offline for existing submissions. + */ + self.canEditOffline = function(assign, submission, plugin) { + // This plugin is read only, but return true to prevent blocking the edition. + return true; + }; + /** * Whether or not the rule is enabled for the site. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionCommentsHandler#isEnabled * @return {Promise} Promise resolved with true if enabled, rejected or resolved with false otherwise. */ self.isEnabled = function() { @@ -39,7 +60,10 @@ angular.module('mm.addons.mod_assign') * This should return true if the plugin has no submission component (allow_submissions=false), * otherwise the user won't be able to edit submissions at all. * - * @return {Boolean} + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionCommentsHandler#isEnabledForEdit + * @return {Boolean} Whether the plugin is enabled. */ self.isEnabledForEdit = function() { return true; @@ -48,6 +72,9 @@ angular.module('mm.addons.mod_assign') /** * Get the name of the directive to render this plugin. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionCommentsHandler#getDirectiveName * @param {Object} plugin Plugin to get the directive for. * @param {Boolean} edit True if editing a submission, false if read only. * @return {String} Directive name. @@ -59,6 +86,9 @@ angular.module('mm.addons.mod_assign') /** * Prefetch submission data. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionCommentsHandler#prefetch * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin. diff --git a/www/addons/mod/assign/submission/file/directive.js b/www/addons/mod/assign/submission/file/directive.js index 641936595d6..5345298b55b 100644 --- a/www/addons/mod/assign/submission/file/directive.js +++ b/www/addons/mod/assign/submission/file/directive.js @@ -22,7 +22,7 @@ angular.module('mm.addons.mod_assign') * @name mmaModAssignSubmissionFile */ .directive('mmaModAssignSubmissionFile', function($mmaModAssign, $mmaModAssignSubmissionFileSession, $mmaModAssignHelper, - $mmaModAssignOffline, mmaModAssignSubmissionFileName, $mmFileUploaderHelper) { + $mmaModAssignOffline, mmaModAssignSubmissionFileName, $mmFileUploaderHelper, $q) { return { restrict: 'A', priority: 100, @@ -32,18 +32,27 @@ angular.module('mm.addons.mod_assign') return; } - scope.files = $mmaModAssign.getSubmissionPluginAttachments(scope.plugin); - // Get the offline data. - $mmaModAssignOffline.getSubmission(scope.assign.id).then(function(offlineData) { - if (offlineData && offlineData.plugindata && offlineData.plugindata.files_filemanager && - offlineData.plugindata.files_filemanager.offline) { - // Has offline files. - return $mmaModAssignHelper.getStoredSubmissionFiles(scope.assign.id, mmaModAssignSubmissionFileName) - .then(function(files) { - files = $mmFileUploaderHelper.markOfflineFiles(files); - scope.files = scope.files.concat(files); + $mmaModAssignOffline.getSubmission(scope.assign.id).catch(function() { + // Error getting data, assume there's no offline submission. + }).then(function(offlineData) { + if (offlineData && offlineData.plugindata && offlineData.plugindata.files_filemanager) { + // Has offline data. + var promise; + if (offlineData.plugindata.files_filemanager.offline) { + promise = $mmaModAssignHelper.getStoredSubmissionFiles(scope.assign.id, mmaModAssignSubmissionFileName); + } else { + promise = $q.when([]); + } + + return promise.then(function(offlineFiles) { + var onlineFiles = offlineData.plugindata.files_filemanager.online || []; + offlineFiles = $mmFileUploaderHelper.markOfflineFiles(offlineFiles); + scope.files = onlineFiles.concat(offlineFiles); }); + } else { + // No offline data, get the online files. + scope.files = $mmaModAssign.getSubmissionPluginAttachments(scope.plugin); } }).finally(function() { $mmaModAssignSubmissionFileSession.setFiles(scope.assign.id, scope.files); diff --git a/www/addons/mod/assign/submission/file/handlers.js b/www/addons/mod/assign/submission/file/handlers.js index 644ba8203a3..a0eee0b82b9 100644 --- a/www/addons/mod/assign/submission/file/handlers.js +++ b/www/addons/mod/assign/submission/file/handlers.js @@ -29,9 +29,30 @@ angular.module('mm.addons.mod_assign') var self = {}; + /** + * Check if the plugin can be edited in offline for existing submissions. + * In general, this should return false if the plugin uses Moodle filters. The reason is that the app only prefetches + * filtered data, and the user should edit unfiltered data. + * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#canEditOffline + * @param {Object} assign Assignment. + * @param {Object} submission Submission. + * @param {Object} plugin Plugin. + * @return {Boolean} Whether the plugin can be edited in offline for existing submissions. + */ + self.canEditOffline = function(assign, submission, plugin) { + // This plugin doesn't use Moodle filters, it can be edited in offline. + return true; + }; + /** * Clear some temporary data because a submission was cancelled. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#clearTmpData * @param {Object} assign Assignment. * @param {Object} submission Submission to clear the data for. * @param {Object} plugin Plugin to clear the data for. @@ -51,6 +72,9 @@ angular.module('mm.addons.mod_assign') * Function meant to copy a submission. * Should add to pluginData the data to send to server based in the data in plugin (previous attempt). * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#copySubmissionData * @param {Object} assign Assignment. * @param {Object} plugin Plugin data of the previous submission (the one to get the data from). * @param {Object} pluginData Object where to add the plugin data. @@ -68,6 +92,9 @@ angular.module('mm.addons.mod_assign') /** * Delete offline data stored for a certain submission. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#deleteOfflineData * @param {Object} assign Assignment. * @param {Object} submission Submission affected. * @param {Object} plugin Plugin to delete the data for. @@ -85,6 +112,9 @@ angular.module('mm.addons.mod_assign') /** * Get the size of data (in bytes) this plugin will send to copy a previous attempt. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#getSizeForCopy * @param {Object} assign Assignment. * @param {Object} plugin Plugin data of the previous submission (the one to get the data from). * @return {Promise} Promise resolved with the size. @@ -112,6 +142,9 @@ angular.module('mm.addons.mod_assign') /** * Get the size of data (in bytes) this plugin will send to add or edit a submission. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#getSizeForEdit * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin to get the data for. @@ -164,9 +197,12 @@ angular.module('mm.addons.mod_assign') }; /** - * Whether or not the rule is enabled for the site. + * Whether or not the plugin is enabled for the site. * - * @return {Boolean} + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#isEnabled + * @return {Boolean} Whether the plugin is enabled. */ self.isEnabled = function() { return true; @@ -177,7 +213,10 @@ angular.module('mm.addons.mod_assign') * This should return true if the plugin has no submission component (allow_submissions=false), * otherwise the user won't be able to edit submissions at all. * - * @return {Boolean} + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#isEnabledForEdit + * @return {Boolean} Whether the plugin is enabled for edit. */ self.isEnabledForEdit = function() { return true; @@ -186,6 +225,9 @@ angular.module('mm.addons.mod_assign') /** * Get the name of the directive to render this plugin. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#getDirectiveName * @param {Object} plugin Plugin to get the directive for. * @param {Boolean} edit True if editing a submission, false if read only. * @return {String} Directive name. @@ -198,6 +240,9 @@ angular.module('mm.addons.mod_assign') * Get files used by this plugin. * The files returned by this function will be prefetched when the user prefetches the assign. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#getPluginFiles * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin. @@ -211,6 +256,9 @@ angular.module('mm.addons.mod_assign') /** * Check if the submission data has changed for this plugin. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#hasDataChanged * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin. @@ -254,6 +302,9 @@ angular.module('mm.addons.mod_assign') /** * Should prepare and add to pluginData the data to send to server based in the input data. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#prepareSubmissionData * @param {Object} assign Assignment. * @param {Object} submission Submission affected. * @param {Object} plugin Plugin to get the data for. @@ -286,6 +337,9 @@ angular.module('mm.addons.mod_assign') /** * Should prepare and add to pluginData the data to send to server to synchronize an offline submission. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionFileHandler#prepareSyncData * @param {Object} assign Assignment. * @param {Object} submission Submission affected. * @param {Object} plugin Plugin to get the data for. diff --git a/www/addons/mod/assign/submission/onlinetext/handlers.js b/www/addons/mod/assign/submission/onlinetext/handlers.js index d3b0b4c58bc..6b389da2faf 100644 --- a/www/addons/mod/assign/submission/onlinetext/handlers.js +++ b/www/addons/mod/assign/submission/onlinetext/handlers.js @@ -26,10 +26,31 @@ angular.module('mm.addons.mod_assign') var self = {}; + /** + * Check if the plugin can be edited in offline for existing submissions. + * In general, this should return false if the plugin uses Moodle filters. The reason is that the app only prefetches + * filtered data, and the user should edit unfiltered data. + * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#canEditOffline + * @param {Object} assign Assignment. + * @param {Object} submission Submission. + * @param {Object} plugin Plugin. + * @return {Boolean} Whether the plugin can be edited in offline for existing submissions. + */ + self.canEditOffline = function(assign, submission, plugin) { + // This plugin uses Moodle filters, it cannot be edited in offline. + return false; + }; + /** * Function meant to copy a submission. * Should add to pluginData the data to send to server based in the data in plugin (previous attempt). * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#copySubmissionData * @param {Object} assign Assignment. * @param {Object} plugin Plugin data of the previous submission (the one to get the data from). * @param {Object} pluginData Object where to add the plugin data. @@ -61,6 +82,9 @@ angular.module('mm.addons.mod_assign') * Get files used by this plugin. * The files returned by this function will be prefetched when the user prefetches the assign. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#getPluginFiles * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin. @@ -74,6 +98,9 @@ angular.module('mm.addons.mod_assign') /** * Get the size of data (in bytes) this plugin will send to copy a previous attempt. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#getSizeForCopy * @param {Object} assign Assignment. * @param {Object} plugin Plugin data of the previous submission (the one to get the data from). * @return {Promise} Promise resolved with the size. @@ -108,6 +135,9 @@ angular.module('mm.addons.mod_assign') /** * Get the size of data (in bytes) this plugin will send to add or edit a submission. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#getSizeForEdit * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin to get the data for. @@ -122,7 +152,10 @@ angular.module('mm.addons.mod_assign') /** * Whether or not the plugin is enabled for the site. * - * @return {Boolean} + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#isEnabled + * @return {Boolean} Whether the plugin is enabled. */ self.isEnabled = function() { return true; @@ -133,7 +166,10 @@ angular.module('mm.addons.mod_assign') * This should return true if the plugin has no submission component (allow_submissions=false), * otherwise the user won't be able to edit submissions at all. * - * @return {Boolean} + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#isEnabledForEdit + * @return {Boolean} Whether the plugin is enabled. */ self.isEnabledForEdit = function() { // There's a bug in Moodle 3.1.0 that doesn't allow submitting HTML, so we'll disable this plugin in that case. @@ -144,6 +180,9 @@ angular.module('mm.addons.mod_assign') /** * Get the name of the directive to render this plugin. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#getDirectiveName * @param {Object} plugin Plugin to get the directive for. * @param {Boolean} edit True if editing a submission, false if read only. * @return {String} Directive name. @@ -155,6 +194,9 @@ angular.module('mm.addons.mod_assign') /** * Should prepare and add to pluginData the data to send to server based in the input data. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#prepareSubmissionData * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin to get the data for. @@ -184,6 +226,9 @@ angular.module('mm.addons.mod_assign') /** * Check if the submission data has changed for this plugin. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#hasDataChanged * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin. @@ -229,6 +274,9 @@ angular.module('mm.addons.mod_assign') /** * Should prepare and add to pluginData the data to send to server to synchronize an offline submission. * + * @module mm.addons.mod_assign + * @ngdoc method + * @name $mmaModAssignSubmissionOnlinetextHandler#prepareSyncData * @param {Object} assign Assignment. * @param {Object} submission Submission to check data. * @param {Object} plugin Plugin to get the data for. diff --git a/www/core/directives/file.js b/www/core/directives/file.js index 41c83e2a6c7..b8617802087 100644 --- a/www/core/directives/file.js +++ b/www/core/directives/file.js @@ -82,12 +82,12 @@ angular.module('mm.core') scope.isDownloading = true; return $mmFilepool.downloadUrl(siteId, fileUrl, false, component, componentId, timeModified).then(function(localUrl) { - getState(scope, siteId, fileUrl, timeModified, alwaysDownload); // Update state. return localUrl; - }, function() { + }).catch(function() { + // Call getState to make sure we have the right state. return getState(scope, siteId, fileUrl, timeModified, alwaysDownload).then(function() { if (scope.isDownloaded) { - return localUrl; + return $mmFilepool.getInternalUrlByUrl(siteId, fileUrl); } else { return $q.reject(); } @@ -127,8 +127,10 @@ angular.module('mm.core') return $q.reject(); } + var isDownloading = scope.isDownloading; + scope.isDownloading = true; // This check could take a while, show spinner. return $mmFilepool.shouldDownloadBeforeOpen(fixedUrl, fileSize).then(function() { - if (scope.isDownloading) { + if (isDownloading) { // It's already downloading, stop. return; } @@ -140,7 +142,7 @@ angular.module('mm.core') downloadFile(scope, siteId, fileUrl, component, componentId, timeModified, alwaysDownload); } - if (scope.isDownloading || !scope.isDownloaded || isOnline) { + if (isDownloading|| !scope.isDownloaded || isOnline) { // Not downloaded or outdated and online, return the online URL. return fixedUrl; } else { @@ -201,12 +203,10 @@ angular.module('mm.core') if (canDownload) { getState(scope, siteId, fileUrl, timeModified, alwaysDownload); + // Update state when receiving events about this file. $mmFilepool.getFileEventNameByUrl(siteId, fileUrl).then(function(eventName) { - observer = $mmEvents.on(eventName, function(data) { + observer = $mmEvents.on(eventName, function() { getState(scope, siteId, fileUrl, timeModified, alwaysDownload); - if (data.action == 'download' && !data.success) { - $mmUtil.showErrorModal('mm.core.errordownloading', true); - } }); }); } @@ -229,7 +229,7 @@ angular.module('mm.core') // File needs to be opened now. If file needs to be downloaded, skip the queue. openFile(scope, siteId, fileUrl, fileSize, component, componentId, timeModified, alwaysDownload) .catch(function(error) { - $mmUtil.showErrorModal(error); + $mmUtil.showErrorModalDefault(error, 'mm.core.errordownloading', true); }); } else { // File doesn't need to be opened (it's a prefetch). Show confirm modal if file size is defined and it's big. @@ -238,7 +238,9 @@ angular.module('mm.core') // User confirmed, add the file to queue. $mmFilepool.invalidateFileByUrl(siteId, fileUrl).finally(function() { scope.isDownloading = true; - $mmFilepool.addToQueueByUrl(siteId, fileUrl, component, componentId, timeModified); + $mmFilepool.addToQueueByUrl(siteId, fileUrl, component, componentId, timeModified).catch(function() { + $mmUtil.showErrorModal('mm.core.errordownloading', true); + }); }); }); } diff --git a/www/core/lib/filepool.js b/www/core/lib/filepool.js index b7bdd898bf6..15ddbe0ab33 100644 --- a/www/core/lib/filepool.js +++ b/www/core/lib/filepool.js @@ -740,10 +740,12 @@ angular.module('mm.core') if (typeof fileObject === 'undefined') { // We do not have the file, download and add to pool. + self._notifyFileDownloading(siteId, fileId); return self._downloadForPoolByUrl(siteId, fileUrl, revision, timemodified, filePath); } else if (self._isFileOutdated(fileObject, revision, timemodified) && $mmApp.isOnline() && !ignoreStale) { // The file is outdated, force the download and update it. + self._notifyFileDownloading(siteId, fileId); return self._downloadForPoolByUrl(siteId, fileUrl, revision, timemodified, filePath, fileObject); } @@ -757,11 +759,13 @@ angular.module('mm.core') return response; }, function() { // The file was not found in the pool, weird. + self._notifyFileDownloading(siteId, fileId); return self._downloadForPoolByUrl(siteId, fileUrl, revision, timemodified, filePath, fileObject); }); }, function() { // The file is not in the pool just yet. + self._notifyFileDownloading(siteId, fileId); return self._downloadForPoolByUrl(siteId, fileUrl, revision, timemodified, filePath); }) .then(function(response) { @@ -804,8 +808,6 @@ angular.module('mm.core') addExtension = typeof filePath == "undefined", pathPromise = filePath ? filePath : self._getFilePath(siteId, fileId, extension); - self._notifyFileDownloading(siteId, fileId); - return $q.when(pathPromise).then(function(filePath) { if (poolFileObject && poolFileObject.fileId !== fileId) { $log.error('Invalid object to update passed'); @@ -1244,7 +1246,7 @@ angular.module('mm.core') * * @module mm.core * @ngdoc method - * @name $mmFilepool#getInternalUrlByUrl + * @name $mmFilepool#getDirectoryUrlByUrl * @param {String} siteId The site ID. * @param {String} fileUrl The file URL. * @return {Promise} Resolved with the URL. Rejected otherwise. @@ -1631,9 +1633,10 @@ angular.module('mm.core') * @param {String} siteId The site ID. * @param {String} fileUrl File URL. * @param {Number} [timemodified=0] The time this file was modified. + * @param {String} [filePath] Filepath to download the file to. If defined, no extension will be added. * @return {Promise} Promise resolved with the file state. */ - self.getFileStateByUrl = function(siteId, fileUrl, timemodified) { + self.getFileStateByUrl = function(siteId, fileUrl, timemodified, filePath) { var fileId, revision; @@ -1646,18 +1649,28 @@ angular.module('mm.core') // Restore old file if needed. return self._restoreOldFileIfNeeded(siteId, fileId, fileUrl); }).then(function() { - return self._hasFileInQueue(siteId, fileId).then(function() { return mmCoreDownloading; }, function() { - return self._hasFileInPool(siteId, fileId).then(function(fileObject) { - if (self._isFileOutdated(fileObject, revision, timemodified)) { - return mmCoreOutdated; - } else { - return mmCoreDownloaded; + // Check if the file is being downloaded right now. + var extension = $mmFS.guessExtensionFromUrl(fileUrl), + pathPromise = filePath ? filePath : self._getFilePath(siteId, fileId, extension); + + return $q.when(pathPromise).then(function(filePath) { + var downloadId = self.getFileDownloadId(fileUrl, filePath); + if (filePromises[siteId] && filePromises[siteId][downloadId]) { + return mmCoreDownloading; } - }, function() { - return mmCoreNotDownloaded; + + return self._hasFileInPool(siteId, fileId).then(function(fileObject) { + if (self._isFileOutdated(fileObject, revision, timemodified)) { + return mmCoreOutdated; + } else { + return mmCoreDownloaded; + } + }, function() { + return mmCoreNotDownloaded; + }); }); }); }); @@ -1731,6 +1744,26 @@ angular.module('mm.core') return $q.reject(); }; + /** + * Returns the local URL of a file. + * + * @module mm.core + * @ngdoc method + * @name $mmFilepool#getInternalUrlByUrl + * @param {String} siteId The site ID. + * @param {String} fileUrl The file URL. + * @return {Promise} Resolved with the URL. Rejected otherwise. + */ + self.getInternalUrlByUrl = function(siteId, fileUrl) { + if ($mmFS.isAvailable()) { + return self._fixPluginfileURL(siteId, fileUrl).then(function(fileUrl) { + var fileId = self._getFileIdByUrl(fileUrl); + return self._getInternalUrlById(siteId, fileId); + }); + } + return $q.reject(); + }; + /** * Get the path to a directory to store a package files. We use the old implementation of getFileId. *