diff --git a/src/addons/mod/assign/components/index/addon-mod-assign-index.html b/src/addons/mod/assign/components/index/addon-mod-assign-index.html index 8ae559539..1f7633bd4 100644 --- a/src/addons/mod/assign/components/index/addon-mod-assign-index.html +++ b/src/addons/mod/assign/components/index/addon-mod-assign-index.html @@ -6,7 +6,7 @@ - + - - + diff --git a/src/addons/mod/assign/pages/edit/edit.ts b/src/addons/mod/assign/pages/edit/edit.ts index 01ddb7499..6e0f06b8d 100644 --- a/src/addons/mod/assign/pages/edit/edit.ts +++ b/src/addons/mod/assign/pages/edit/edit.ts @@ -36,6 +36,7 @@ import { import { AddonModAssignHelper } from '../../services/assign-helper'; import { AddonModAssignOffline } from '../../services/assign-offline'; import { AddonModAssignSync } from '../../services/assign-sync'; +import { CoreUtils } from '@services/utils/utils'; /** * Page that allows adding or editing an assigment submission. @@ -255,7 +256,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy, CanLeave { this.hasOffline, ); } catch (error) { - if (this.allowOffline && !this.saveOffline) { + if (this.allowOffline && !this.saveOffline && !CoreUtils.isWebServiceError(error)) { // Cannot submit in online, prepare for offline usage. this.saveOffline = true; diff --git a/src/addons/mod/assign/pages/index/index.html b/src/addons/mod/assign/pages/index/index.html index 0d424c637..71f69b398 100644 --- a/src/addons/mod/assign/pages/index/index.html +++ b/src/addons/mod/assign/pages/index/index.html @@ -16,7 +16,7 @@ - + diff --git a/src/addons/mod/assign/services/assign-helper.ts b/src/addons/mod/assign/services/assign-helper.ts index cb062c240..c3f948527 100644 --- a/src/addons/mod/assign/services/assign-helper.ts +++ b/src/addons/mod/assign/services/assign-helper.ts @@ -15,7 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader'; import { CoreSites, CoreSitesCommonWSOptions } from '@services/sites'; -import { FileEntry } from '@ionic-native/file/ngx'; +import { FileEntry, DirectoryEntry } from '@ionic-native/file/ngx'; import { AddonModAssignProvider, AddonModAssignAssign, diff --git a/src/addons/mod/assign/submission/file/services/handler.ts b/src/addons/mod/assign/submission/file/services/handler.ts index f1b52ea2f..7c684ea89 100644 --- a/src/addons/mod/assign/submission/file/services/handler.ts +++ b/src/addons/mod/assign/submission/file/services/handler.ts @@ -187,7 +187,8 @@ export class AddonModAssignSubmissionFileHandlerService implements AddonModAssig plugin: AddonModAssignPlugin, ): Promise { // Check if there's any change. - if (this.hasDataChanged(assign, submission, plugin)) { + const hasChanged = await this.hasDataChanged(assign, submission, plugin); + if (hasChanged) { const files = CoreFileSession.getFiles(AddonModAssignProvider.COMPONENT, assign.id); return CoreFileHelper.getTotalFilesSize(files); diff --git a/src/addons/mod/bigbluebuttonbn/components/index/index.html b/src/addons/mod/bigbluebuttonbn/components/index/index.html index 39f7bd548..911bc6123 100644 --- a/src/addons/mod/bigbluebuttonbn/components/index/index.html +++ b/src/addons/mod/bigbluebuttonbn/components/index/index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/bigbluebuttonbn/components/index/index.ts b/src/addons/mod/bigbluebuttonbn/components/index/index.ts index 8d85abf94..5f1e648cb 100644 --- a/src/addons/mod/bigbluebuttonbn/components/index/index.ts +++ b/src/addons/mod/bigbluebuttonbn/components/index/index.ts @@ -115,14 +115,14 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo return; } - this.loaded = false; + this.showLoading = true; try { await AddonModBBB.invalidateAllGroupsMeetingInfo(this.bbb.id); await this.fetchMeetingInfo(); } finally { - this.loaded = true; + this.showLoading = false; } } @@ -148,14 +148,14 @@ export class AddonModBBBIndexComponent extends CoreCourseModuleMainActivityCompo * @return Promise resolved when done. */ async groupChanged(): Promise { - this.loaded = false; + this.showLoading = true; try { await this.fetchMeetingInfo(); } catch (error) { CoreDomUtils.showErrorModal(error); } finally { - this.loaded = true; + this.showLoading = false; } } diff --git a/src/addons/mod/bigbluebuttonbn/pages/index/index.html b/src/addons/mod/bigbluebuttonbn/pages/index/index.html index 5d8e5197e..f6e0e524e 100644 --- a/src/addons/mod/bigbluebuttonbn/pages/index/index.html +++ b/src/addons/mod/bigbluebuttonbn/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/book/components/index/addon-mod-book-index.html b/src/addons/mod/book/components/index/addon-mod-book-index.html index f8d3545b6..410dd43cc 100644 --- a/src/addons/mod/book/components/index/addon-mod-book-index.html +++ b/src/addons/mod/book/components/index/addon-mod-book-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/book/pages/index/index.html b/src/addons/mod/book/pages/index/index.html index b09bfab96..fb3db333b 100644 --- a/src/addons/mod/book/pages/index/index.html +++ b/src/addons/mod/book/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/chat/components/index/addon-mod-chat-index.html b/src/addons/mod/chat/components/index/addon-mod-chat-index.html index 47f13bd8c..7296cddb5 100644 --- a/src/addons/mod/chat/components/index/addon-mod-chat-index.html +++ b/src/addons/mod/chat/components/index/addon-mod-chat-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/chat/pages/index/index.html b/src/addons/mod/chat/pages/index/index.html index ed096fe29..bc5f254eb 100644 --- a/src/addons/mod/chat/pages/index/index.html +++ b/src/addons/mod/chat/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/choice/components/index/addon-mod-choice-index.html b/src/addons/mod/choice/components/index/addon-mod-choice-index.html index e29970de6..1eebfa01c 100644 --- a/src/addons/mod/choice/components/index/addon-mod-choice-index.html +++ b/src/addons/mod/choice/components/index/addon-mod-choice-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/choice/pages/index/index.html b/src/addons/mod/choice/pages/index/index.html index 7c56322d2..b5a04c2a6 100644 --- a/src/addons/mod/choice/pages/index/index.html +++ b/src/addons/mod/choice/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/data/components/index/addon-mod-data-index.html b/src/addons/mod/data/components/index/addon-mod-data-index.html index 3a8aa7713..6f15f5132 100644 --- a/src/addons/mod/data/components/index/addon-mod-data-index.html +++ b/src/addons/mod/data/components/index/addon-mod-data-index.html @@ -18,7 +18,7 @@ - + - + diff --git a/src/addons/mod/data/components/index/index.ts b/src/addons/mod/data/components/index/index.ts index 9bdb523fe..2c367fa48 100644 --- a/src/addons/mod/data/components/index/index.ts +++ b/src/addons/mod/data/components/index/index.ts @@ -133,7 +133,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp // Refresh entries on change. this.entryChangedObserver = CoreEvents.on(AddonModDataProvider.ENTRY_CHANGED, (eventData) => { if (this.database?.id == eventData.dataId) { - this.loaded = false; + this.showLoading = true; return this.loadContent(true); } @@ -191,7 +191,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp */ protected isRefreshSyncNeeded(syncEventData: AddonModDataAutoSyncData): boolean { if (this.database && syncEventData.dataId == this.database.id && syncEventData.entryId === undefined) { - this.loaded = false; + this.showLoading = true; // Refresh the data. this.content?.scrollToTop(); @@ -404,7 +404,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp * @return Resolved when done. */ async searchEntries(page: number): Promise { - this.loaded = false; + this.showLoading = true; this.search.page = page; try { @@ -414,7 +414,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'core.course.errorgetmodule', true); } finally { - this.loaded = true; + this.showLoading = false; } } diff --git a/src/addons/mod/data/pages/edit/edit.ts b/src/addons/mod/data/pages/edit/edit.ts index dc307eaa2..e6878e177 100644 --- a/src/addons/mod/data/pages/edit/edit.ts +++ b/src/addons/mod/data/pages/edit/edit.ts @@ -266,9 +266,10 @@ export class AddonModDataEditPage implements OnInit { this.offline, ); } catch (error) { - if (this.offline) { + if (this.offline || CoreUtils.isWebServiceError(error)) { throw error; } + // Cannot submit in online, prepare for offline usage. this.offline = true; diff --git a/src/addons/mod/data/pages/index/index.html b/src/addons/mod/data/pages/index/index.html index 46e4a1dd9..ff9ed701e 100644 --- a/src/addons/mod/data/pages/index/index.html +++ b/src/addons/mod/data/pages/index/index.html @@ -16,7 +16,7 @@ - + diff --git a/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html b/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html index e336d35e1..3abdff768 100644 --- a/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html +++ b/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/feedback/components/index/index.ts b/src/addons/mod/feedback/components/index/index.ts index 255b0e6ce..e31b5f529 100644 --- a/src/addons/mod/feedback/components/index/index.ts +++ b/src/addons/mod/feedback/components/index/index.ts @@ -97,7 +97,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity this.tabsLoaded.analysis = false; this.tabsLoaded.overview = false; - this.loaded = false; + this.showLoading = true; // Prefetch data if needed. if (!data.offline && this.isPrefetched()) { diff --git a/src/addons/mod/feedback/pages/index/index.html b/src/addons/mod/feedback/pages/index/index.html index fa031ccc7..6996000e4 100644 --- a/src/addons/mod/feedback/pages/index/index.html +++ b/src/addons/mod/feedback/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/folder/components/index/addon-mod-folder-index.html b/src/addons/mod/folder/components/index/addon-mod-folder-index.html index b01b72741..82cb66284 100644 --- a/src/addons/mod/folder/components/index/addon-mod-folder-index.html +++ b/src/addons/mod/folder/components/index/addon-mod-folder-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/folder/components/index/index.ts b/src/addons/mod/folder/components/index/index.ts index 562a2824e..fcfa675c7 100644 --- a/src/addons/mod/folder/components/index/index.ts +++ b/src/addons/mod/folder/components/index/index.ts @@ -55,7 +55,7 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo this.description = this.folderInstance ? this.folderInstance.intro : this.module.description; this.contents = this.subfolder; - this.loaded = true; + this.showLoading = false; return; } @@ -70,7 +70,7 @@ export class AddonModFolderIndexComponent extends CoreCourseModuleMainResourceCo // Ignore errors. } } finally { - this.loaded = true; + this.showLoading = false; } } diff --git a/src/addons/mod/folder/pages/index/index.html b/src/addons/mod/folder/pages/index/index.html index 442b976ec..b83a186f5 100644 --- a/src/addons/mod/folder/pages/index/index.html +++ b/src/addons/mod/folder/pages/index/index.html @@ -16,7 +16,7 @@ - diff --git a/src/addons/mod/forum/components/index/index.html b/src/addons/mod/forum/components/index/index.html index 35776441c..61ff3501f 100644 --- a/src/addons/mod/forum/components/index/index.html +++ b/src/addons/mod/forum/components/index/index.html @@ -7,11 +7,11 @@ - + - + @@ -114,7 +114,7 @@ - diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 2a2cf19ed..cfd60670f 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -364,7 +364,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges ); } catch (error) { // Cannot upload them in online, save them in offline. - if (!this.forum.id || isEditOnline) { + if (!this.forum.id || isEditOnline || CoreUtils.isWebServiceError(error)) { // Cannot store them in offline. Reject. throw error; } diff --git a/src/addons/mod/forum/services/forum-helper.ts b/src/addons/mod/forum/services/forum-helper.ts index 0519efe28..47c2bd0cc 100644 --- a/src/addons/mod/forum/services/forum-helper.ts +++ b/src/addons/mod/forum/services/forum-helper.ts @@ -106,6 +106,10 @@ export class AddonModForumHelperProvider { try { await Promise.all(promises); } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. saveOffline = true; diff --git a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html index 524abb9b1..c973a95a3 100644 --- a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html +++ b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html @@ -16,7 +16,7 @@ - + @@ -24,7 +24,7 @@ [autoFocus]="true" [lengthCheck]="2" (onClear)="toggleSearch()" searchArea="AddonModGlossary-{{module.id}}"> - + @@ -72,7 +72,7 @@ - diff --git a/src/addons/mod/glossary/components/index/index.ts b/src/addons/mod/glossary/components/index/index.ts index cbcc5aa89..4e483a919 100644 --- a/src/addons/mod/glossary/components/index/index.ts +++ b/src/addons/mod/glossary/components/index/index.ts @@ -393,7 +393,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity this.loadingMessage = Translate.instant('core.loading'); this.content?.scrollToTop(); this.switchMode(mode); - this.loaded = false; + this.showLoading = true; this.loadContent(); } @@ -411,7 +411,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity */ search(query: string): void { this.loadingMessage = Translate.instant('core.searching'); - this.loaded = false; + this.showLoading = true; this.entries?.getSource().search(query); this.loadContent(); diff --git a/src/addons/mod/glossary/pages/edit/edit.ts b/src/addons/mod/glossary/pages/edit/edit.ts index 2edc0d440..127a5ea4a 100644 --- a/src/addons/mod/glossary/pages/edit/edit.ts +++ b/src/addons/mod/glossary/pages/edit/edit.ts @@ -25,6 +25,7 @@ import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; +import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreForms } from '@singletons/form'; @@ -392,7 +393,11 @@ export class AddonModGlossaryEditPage implements OnInit, OnDestroy, CanLeave { saveOffline: false, attachmentsResult, }; - } catch { + } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. const attachmentsResult = await AddonModGlossaryHelper.storeFiles( this.glossary.id, diff --git a/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html b/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html index 039f30ce2..deed6960a 100644 --- a/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html +++ b/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html @@ -16,7 +16,7 @@ - + - + diff --git a/src/addons/mod/h5pactivity/pages/index/index.html b/src/addons/mod/h5pactivity/pages/index/index.html index 6ac751048..8c2890fee 100644 --- a/src/addons/mod/h5pactivity/pages/index/index.html +++ b/src/addons/mod/h5pactivity/pages/index/index.html @@ -16,7 +16,7 @@ - + diff --git a/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html b/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html index d795fb3fe..a3ce89920 100644 --- a/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html +++ b/src/addons/mod/imscp/components/index/addon-mod-imscp-index.html @@ -1,6 +1,6 @@ - + @@ -10,7 +10,7 @@ - + @@ -26,9 +26,10 @@
- +
- + diff --git a/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html index 29a420944..d79ecd5a1 100644 --- a/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html +++ b/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html @@ -6,8 +6,8 @@ - - + + @@ -279,5 +279,6 @@ - + diff --git a/src/addons/mod/lesson/components/index/index.ts b/src/addons/mod/lesson/components/index/index.ts index 1a9e8b614..415bf0555 100644 --- a/src/addons/mod/lesson/components/index/index.ts +++ b/src/addons/mod/lesson/components/index/index.ts @@ -618,7 +618,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo return; } - this.loaded = false; + this.showLoading = true; try { await this.validatePassword( password); @@ -635,7 +635,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo } catch (error) { CoreDomUtils.showErrorModal(error); } finally { - this.loaded = true; + this.showLoading = false; CoreForms.triggerFormSubmittedEvent(this.formElement, true, this.siteId); } diff --git a/src/addons/mod/lesson/pages/index/index.html b/src/addons/mod/lesson/pages/index/index.html index a6b75a913..fec01e323 100644 --- a/src/addons/mod/lesson/pages/index/index.html +++ b/src/addons/mod/lesson/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/lti/components/index/addon-mod-lti-index.html b/src/addons/mod/lti/components/index/addon-mod-lti-index.html index dc3b6068d..1452e0c18 100644 --- a/src/addons/mod/lti/components/index/addon-mod-lti-index.html +++ b/src/addons/mod/lti/components/index/addon-mod-lti-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/lti/pages/index/index.html b/src/addons/mod/lti/pages/index/index.html index 9b7017a3f..38ce5fc89 100644 --- a/src/addons/mod/lti/pages/index/index.html +++ b/src/addons/mod/lti/pages/index/index.html @@ -16,7 +16,7 @@ - + diff --git a/src/addons/mod/page/components/index/addon-mod-page-index.html b/src/addons/mod/page/components/index/addon-mod-page-index.html index 1cfc5f303..83536200d 100644 --- a/src/addons/mod/page/components/index/addon-mod-page-index.html +++ b/src/addons/mod/page/components/index/addon-mod-page-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/page/pages/index/index.html b/src/addons/mod/page/pages/index/index.html index cab819bed..fc6dc2f86 100644 --- a/src/addons/mod/page/pages/index/index.html +++ b/src/addons/mod/page/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html index 6323f3cb5..59961b31c 100644 --- a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html +++ b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/quiz/components/index/index.ts b/src/addons/mod/quiz/components/index/index.ts index 1f03d876e..d827022de 100644 --- a/src/addons/mod/quiz/components/index/index.ts +++ b/src/addons/mod/quiz/components/index/index.ts @@ -455,13 +455,13 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp } // Refresh data. - this.loaded = false; + this.showLoading = true; this.content?.scrollToTop(); await promise; await CoreUtils.ignoreErrors(this.refreshContent(true)); - this.loaded = true; + this.showLoading = false; } /** @@ -547,8 +547,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp if (status == CoreConstants.DOWNLOADED && previousStatus == CoreConstants.DOWNLOADING) { // Quiz downloaded now, maybe a new attempt was created. Load content again. - this.loaded = false; - this.loadContent(); + this.showLoadingAndFetch(); } } diff --git a/src/addons/mod/quiz/pages/index/index.html b/src/addons/mod/quiz/pages/index/index.html index 9a58a95ff..233973f4f 100644 --- a/src/addons/mod/quiz/pages/index/index.html +++ b/src/addons/mod/quiz/pages/index/index.html @@ -16,7 +16,7 @@ - + diff --git a/src/addons/mod/resource/components/index/addon-mod-resource-index.html b/src/addons/mod/resource/components/index/addon-mod-resource-index.html index 89fbf28f7..1efbca3f9 100644 --- a/src/addons/mod/resource/components/index/addon-mod-resource-index.html +++ b/src/addons/mod/resource/components/index/addon-mod-resource-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/resource/pages/index/index.html b/src/addons/mod/resource/pages/index/index.html index ac1c3727e..4bfe3e2a6 100644 --- a/src/addons/mod/resource/pages/index/index.html +++ b/src/addons/mod/resource/pages/index/index.html @@ -16,7 +16,7 @@ - diff --git a/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html b/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html index 275c81125..96329ba19 100644 --- a/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html +++ b/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html @@ -6,7 +6,7 @@ - + - + @@ -217,5 +217,6 @@ - + diff --git a/src/addons/mod/scorm/pages/index/index.html b/src/addons/mod/scorm/pages/index/index.html index fc1e6f57f..00e1aa739 100644 --- a/src/addons/mod/scorm/pages/index/index.html +++ b/src/addons/mod/scorm/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/survey/components/index/addon-mod-survey-index.html b/src/addons/mod/survey/components/index/addon-mod-survey-index.html index acafdf331..8c99699fc 100644 --- a/src/addons/mod/survey/components/index/addon-mod-survey-index.html +++ b/src/addons/mod/survey/components/index/addon-mod-survey-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/survey/pages/index/index.html b/src/addons/mod/survey/pages/index/index.html index 808d88eb1..02673c75d 100644 --- a/src/addons/mod/survey/pages/index/index.html +++ b/src/addons/mod/survey/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/url/components/index/addon-mod-url-index.html b/src/addons/mod/url/components/index/addon-mod-url-index.html index ccf09a1a2..0153bcdf7 100644 --- a/src/addons/mod/url/components/index/addon-mod-url-index.html +++ b/src/addons/mod/url/components/index/addon-mod-url-index.html @@ -6,7 +6,7 @@ - + - + diff --git a/src/addons/mod/url/pages/index/index.html b/src/addons/mod/url/pages/index/index.html index 45dc4198c..f940549ef 100644 --- a/src/addons/mod/url/pages/index/index.html +++ b/src/addons/mod/url/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html b/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html index 462d5a1b4..342e83895 100644 --- a/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html +++ b/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html @@ -7,7 +7,7 @@ - @@ -27,7 +27,7 @@ - + - + diff --git a/src/addons/mod/wiki/pages/index/index.html b/src/addons/mod/wiki/pages/index/index.html index a33c7c251..0c013169c 100644 --- a/src/addons/mod/wiki/pages/index/index.html +++ b/src/addons/mod/wiki/pages/index/index.html @@ -16,7 +16,7 @@ - + diff --git a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts index f46b85d90..26d9b61c1 100644 --- a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts +++ b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts @@ -304,7 +304,11 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe files, saveOffline, ); - } catch { + } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. saveOffline = true; allowOffline = true; diff --git a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html index 9fc19b652..ebb5b73a3 100644 --- a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html +++ b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html @@ -6,7 +6,7 @@ - + @@ -233,5 +233,6 @@ - + diff --git a/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts index aa215a1ce..23b7e7e5e 100644 --- a/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts +++ b/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts @@ -25,6 +25,7 @@ import { CoreSites } from '@services/sites'; import { CoreSync } from '@services/sync'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; +import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { CoreForms } from '@singletons/form'; @@ -349,7 +350,11 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy, Ca inputData.attachmentfiles, false, ); - } catch { + } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. saveOffline = true; allowOffline = true; diff --git a/src/addons/mod/workshop/pages/index/index.html b/src/addons/mod/workshop/pages/index/index.html index 9b639898c..c9fdc573a 100644 --- a/src/addons/mod/workshop/pages/index/index.html +++ b/src/addons/mod/workshop/pages/index/index.html @@ -15,7 +15,7 @@ - + diff --git a/src/core/classes/errors/errors.ts b/src/core/classes/errors/errors.ts index 94b34a72f..517d91910 100644 --- a/src/core/classes/errors/errors.ts +++ b/src/core/classes/errors/errors.ts @@ -24,6 +24,7 @@ import { CoreCaptureError } from './captureerror'; import { CoreNetworkError } from './network-error'; import { CoreSiteError } from './siteerror'; import { CoreErrorWithTitle } from './errorwithtitle'; +import { CoreHttpError } from './httperror'; export const CORE_ERRORS_CLASSES: Type[] = [ CoreAjaxError, @@ -36,4 +37,5 @@ export const CORE_ERRORS_CLASSES: Type[] = [ CoreSiteError, CoreWSError, CoreErrorWithTitle, + CoreHttpError, ]; diff --git a/src/core/classes/errors/httperror.ts b/src/core/classes/errors/httperror.ts new file mode 100644 index 000000000..598cc4455 --- /dev/null +++ b/src/core/classes/errors/httperror.ts @@ -0,0 +1,30 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreError } from '@classes/errors/error'; + +/** + * HTTP error. + */ +export class CoreHttpError extends CoreError { + + status: number; // HTTP status. 0 if cannot connect or similar errors. + + constructor(message: string, status?: number) { + super(message); + + this.status = status ?? 0; + } + +} diff --git a/src/core/features/course/classes/main-activity-component.ts b/src/core/features/course/classes/main-activity-component.ts index d0214e996..e41b66bfb 100644 --- a/src/core/features/course/classes/main-activity-component.ts +++ b/src/core/features/course/classes/main-activity-component.ts @@ -116,7 +116,7 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR * @return Resolved when done. */ protected async showLoadingAndFetch(sync: boolean = false, showErrors: boolean = false): Promise { - this.loaded = false; + this.showLoading = true; this.content?.scrollToTop(); await this.loadContent(false, sync, showErrors); @@ -130,7 +130,7 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR * @return Resolved when done. */ protected showLoadingAndRefresh(sync: boolean = false, showErrors: boolean = false): Promise { - this.loaded = false; + this.showLoading = true; this.content?.scrollToTop(); return this.refreshContent(sync, showErrors); @@ -177,7 +177,7 @@ export class CoreCourseModuleMainActivityComponent extends CoreCourseModuleMainR CoreDomUtils.showErrorModalDefault(error, this.fetchContentDefaultError, true); } finally { - this.loaded = true; + this.showLoading = false; } } diff --git a/src/core/features/course/classes/main-resource-component.ts b/src/core/features/course/classes/main-resource-component.ts index 6536145e0..2a0eed662 100644 --- a/src/core/features/course/classes/main-resource-component.ts +++ b/src/core/features/course/classes/main-resource-component.ts @@ -52,7 +52,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, @Input() courseId!: number; // Course ID the component belongs to. @Output() dataRetrieved = new EventEmitter(); // Called to notify changes the index page from the main component. - loaded = false; // If the component has been loaded. + showLoading = true; // Whether to show loading. component?: string; // Component name. componentId?: number; // Component ID. hasOffline = false; // Resources don't have any data to sync. @@ -199,7 +199,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, CoreDomUtils.showErrorModalDefault(error, this.fetchContentDefaultError, true); } finally { - this.loaded = true; + this.showLoading = false; } } @@ -416,12 +416,12 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, }); if (data) { - if (this.loaded && (data.action == 'refresh' || data.action == 'sync')) { - this.loaded = false; + if (!this.showLoading && (data.action == 'refresh' || data.action == 'sync')) { + this.showLoading = true; try { await this.doRefresh(undefined, data.action == 'sync'); } finally { - this.loaded = true; + this.showLoading = false; } } } diff --git a/src/core/services/utils/text.ts b/src/core/services/utils/text.ts index 4c6d5f307..9a091db74 100644 --- a/src/core/services/utils/text.ts +++ b/src/core/services/utils/text.ts @@ -530,6 +530,18 @@ export class CoreTextUtilsProvider { return error.message || error.error || error.content || error.body; } + /** + * Given some HTML code, return the HTML code inside tags. If there are no body tags, return the whole HTML. + * + * @param html HTML text. + * @return Body HTML. + */ + getHTMLBodyContent(html: string): string { + const matches = html.match(/([\s\S]*)<\/body>/im); + + return matches?.[1] ?? html; + } + /** * Get the pluginfile URL to replace @@PLUGINFILE@@ wildcards. * diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index 4808ccca5..e211d3350 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -858,12 +858,17 @@ export class CoreUtilsProvider { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any isWebServiceError(error: any): boolean { - return error && (error.warningcode !== undefined || (error.errorcode !== undefined && - error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' && + return error && ( + error.warningcode !== undefined || + ( + error.errorcode !== undefined && error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' && error.errorcode != 'forcepasswordchangenotice' && error.errorcode != 'usernotfullysetup' && error.errorcode != 'sitepolicynotagreed' && error.errorcode != 'sitemaintenance' && error.errorcode != 'wsaccessusersuspended' && error.errorcode != 'wsaccessuserdeleted' && - !this.isExpiredTokenError(error))); + !this.isExpiredTokenError(error) + ) || + error.status && error.status >= 400 // CoreHttpError, assume status 400 and above are like WebService errors. + ); } /** diff --git a/src/core/services/ws.ts b/src/core/services/ws.ts index d1ab15a5e..866ed0724 100644 --- a/src/core/services/ws.ts +++ b/src/core/services/ws.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { HttpResponse, HttpParams } from '@angular/common/http'; import { FileEntry } from '@ionic-native/file/ngx'; -import { FileUploadOptions } from '@ionic-native/file-transfer/ngx'; +import { FileUploadOptions, FileUploadResult } from '@ionic-native/file-transfer/ngx'; import { Md5 } from 'ts-md5/dist/md5'; import { Observable } from 'rxjs'; import { timeout } from 'rxjs/operators'; @@ -25,7 +25,7 @@ import { CoreNativeToAngularHttpResponse } from '@classes/native-to-angular-http import { CoreApp } from '@services/app'; import { CoreFile, CoreFileFormat } from '@services/file'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; -import { CoreTextUtils } from '@services/utils/text'; +import { CoreTextErrorObject, CoreTextUtils } from '@services/utils/text'; import { CoreUtils, PromiseDefer } from '@services/utils/utils'; import { CoreConstants } from '@/core/constants'; import { CoreError } from '@classes/errors/error'; @@ -38,6 +38,7 @@ import { CoreAjaxError } from '@classes/errors/ajaxerror'; import { CoreAjaxWSError } from '@classes/errors/ajaxwserror'; import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreSite } from '@classes/site'; +import { CoreHttpError } from '@classes/errors/httperror'; /** * This service allows performing WS calls and download/upload files. @@ -693,6 +694,8 @@ export class CoreWSProvider { return retryPromise; } else if (error.status === -2) { throw new CoreError(this.getCertificateErrorMessage(error.error)); + } else if (error.status > 0) { + throw this.createHttpError(error, error.status); } throw new CoreError(Translate.instant('core.serverconnection')); @@ -885,51 +888,69 @@ export class CoreWSProvider { options.headers = {}; options['Connection'] = 'close'; + let success: FileUploadResult; + try { - const success = await transfer.upload(filePath, uploadUrl, options, true); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const data = CoreTextUtils.parseJSON( - success.response, - null, - this.logger.error.bind(this.logger, 'Error parsing response from upload', success.response), - ); - - if (data === null) { - throw new CoreError(Translate.instant('core.errorinvalidresponse')); - } - - if (!data) { - throw new CoreError(Translate.instant('core.serverconnection')); - } else if (typeof data != 'object') { - this.logger.warn('Upload file: Response of type "' + typeof data + '" received, expecting "object"'); - - throw new CoreError(Translate.instant('core.errorinvalidresponse')); - } - - if (data.exception !== undefined) { - throw new CoreWSError(data); - } else if (data.error !== undefined) { - throw new CoreWSError({ - errorcode: data.errortype, - message: data.error, - }); - } else if (data[0] && data[0].error !== undefined) { - throw new CoreWSError({ - errorcode: data[0].errortype, - message: data[0].error, - }); - } - - // We uploaded only 1 file, so we only return the first file returned. - this.logger.debug('Successfully uploaded file', filePath); - - return data[0]; + success = await transfer.upload(filePath, uploadUrl, options, true); } catch (error) { this.logger.error('Error while uploading file', filePath, error); + throw this.createHttpError(error, error.http_status ?? 0); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const data = CoreTextUtils.parseJSON( + success.response, + null, + this.logger.error.bind(this.logger, 'Error parsing response from upload', success.response), + ); + + if (data === null) { throw new CoreError(Translate.instant('core.errorinvalidresponse')); } + + if (!data) { + throw new CoreError(Translate.instant('core.serverconnection')); + } else if (typeof data != 'object') { + this.logger.warn('Upload file: Response of type "' + typeof data + '" received, expecting "object"'); + + throw new CoreError(Translate.instant('core.errorinvalidresponse')); + } + + if (data.exception !== undefined) { + throw new CoreWSError(data); + } else if (data.error !== undefined) { + throw new CoreWSError({ + errorcode: data.errortype, + message: data.error, + }); + } else if (data[0] && data[0].error !== undefined) { + throw new CoreWSError({ + errorcode: data[0].errortype, + message: data[0].error, + }); + } + + // We uploaded only 1 file, so we only return the first file returned. + this.logger.debug('Successfully uploaded file', filePath); + + return data[0]; + } + + /** + * Create a CoreHttpError based on a certain error. + * + * @param error Original error. + * @param status Status code (if any). + * @return CoreHttpError. + */ + protected createHttpError(error: CoreTextErrorObject, status: number): CoreHttpError { + const message = CoreTextUtils.buildSeveralParagraphsMessage([ + Translate.instant('core.cannotconnecttrouble'), + CoreTextUtils.getHTMLBodyContent(CoreTextUtils.getErrorMessageFromError(error) || ''), + ]); + + return new CoreHttpError(message, status); } /** diff --git a/upgrade.txt b/upgrade.txt index ebb311bcb..e01fe0058 100644 --- a/upgrade.txt +++ b/upgrade.txt @@ -22,6 +22,7 @@ information provided here is intended especially for developers. - The parameters of the following functions in CoreCourseHelper have changed: navigateToModuleByInstance, navigateToModule, openModule. - fillContextMenu, expandDescription, gotoBlog, prefetch and removeFiles functions have been removed from CoreCourseModuleMainResourceComponent. - contextMenuPrefetch and fillContextMenu have been removed from CoreCourseHelper. +-The variable "loaded" in CoreCourseModuleMainResourceComponent has been changed to "showLoading" to reflect its purpose better.