MOBILE-2348 core: Return a 'canceled' error in showConfirm
This commit is contained in:
		
							parent
							
								
									ad1e564600
								
							
						
					
					
						commit
						01848965d8
					
				| @ -518,18 +518,18 @@ export class AddonMessagesDiscussionPage implements OnDestroy { | ||||
|         this.domUtils.showConfirm(this.translate.instant(langKey)).then(() => { | ||||
|             const modal = this.domUtils.showModalLoading('core.deleting', true); | ||||
| 
 | ||||
|             this.messagesProvider.deleteMessage(message).then(() => { | ||||
|             return this.messagesProvider.deleteMessage(message).then(() => { | ||||
|                  // Remove message from the list without having to wait for re-fetch.
 | ||||
|                 this.messages.splice(index, 1); | ||||
|                 this.removeMessage(message.hash); | ||||
|                 this.notifyNewMessage(); | ||||
| 
 | ||||
|                 this.fetchData(); // Re-fetch messages to update cached data.
 | ||||
|             }).catch((error) => { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'addon.messages.errordeletemessage', true); | ||||
|             }).finally(() => { | ||||
|                 modal.dismiss(); | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             this.domUtils.showErrorModalDefault(error, 'addon.messages.errordeletemessage', true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -100,8 +100,6 @@ export class AddonMessagesAddContactUserHandler implements CoreUserProfileHandle | ||||
| 
 | ||||
|                         return this.domUtils.showConfirm(template, title, title).then(() => { | ||||
|                             return this.messagesProvider.removeContact(user.id); | ||||
|                         }, () => { | ||||
|                             // Ignore on cancel.
 | ||||
|                         }); | ||||
|                     } else { | ||||
|                         return this.messagesProvider.addContact(user.id); | ||||
|  | ||||
| @ -103,8 +103,6 @@ export class AddonMessagesBlockContactUserHandler implements CoreUserProfileHand | ||||
| 
 | ||||
|                         return this.domUtils.showConfirm(template, title, title).then(() => { | ||||
|                             return this.messagesProvider.blockContact(user.id); | ||||
|                         }, () => { | ||||
|                             // Ignore on cancel.
 | ||||
|                         }); | ||||
|                     } | ||||
|                 }).catch((error) => { | ||||
|  | ||||
| @ -172,7 +172,7 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy { | ||||
|             answers[button.name] = button.value; | ||||
| 
 | ||||
|             // Behaviour checks are always in online.
 | ||||
|             this.quizProvider.processAttempt(this.quiz, this.attempt, answers, this.preflightData).then(() => { | ||||
|             return this.quizProvider.processAttempt(this.quiz, this.attempt, answers, this.preflightData).then(() => { | ||||
|                 // Reload the current page.
 | ||||
|                 const scrollElement = this.content.getScrollElement(), | ||||
|                     scrollTop = scrollElement.scrollTop || 0, | ||||
| @ -185,11 +185,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy { | ||||
|                     this.loaded = true; | ||||
|                     this.content.scrollTo(scrollLeft, scrollTop); | ||||
|                 }); | ||||
|             }).catch((error) => { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'Error performing action.'); | ||||
|             }).finally(() => { | ||||
|                 modal.dismiss(); | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             this.domUtils.showErrorModalDefault(error, 'Error performing action.'); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -354,11 +354,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy { | ||||
|                 // Leave the player.
 | ||||
|                 this.forceLeave = true; | ||||
|                 this.navCtrl.pop(); | ||||
|             }).catch((error) => { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'addon.mod_quiz.errorsaveattempt', true); | ||||
|             }).finally(() => { | ||||
|                 modal.dismiss(); | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             this.domUtils.showErrorModalDefault(error, 'addon.mod_quiz.errorsaveattempt', true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -560,13 +560,9 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy { | ||||
|                     // Attempt is overdue or finished in offline, we can only load the summary.
 | ||||
|                     return this.loadSummary(); | ||||
|                 } | ||||
|             }).catch((error) => { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'addon.mod_quiz.errorgetquestions', true); | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             if (error) { | ||||
|                 this.domUtils.showErrorModal(error); | ||||
|             } | ||||
|             this.domUtils.showErrorModalDefault(error, 'addon.mod_quiz.errorgetquestions', true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -139,7 +139,7 @@ export class AddonModQuizHelperProvider { | ||||
|                 if (typeof data != 'undefined') { | ||||
|                     resolve(data); | ||||
|                 } else { | ||||
|                     reject(null); | ||||
|                     reject(this.domUtils.createCanceledError()); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
| @ -188,15 +188,15 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then(() => { | ||||
|             return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then(() => { | ||||
|                 this.content.scrollToTop(); | ||||
| 
 | ||||
|                 return this.refreshContent(false); | ||||
|             }).catch((message) => { | ||||
|                 this.domUtils.showErrorModalDefault(message, 'addon.mod_survey.cannotsubmitsurvey', true); | ||||
|             }).finally(() => { | ||||
|                 modal.dismiss(); | ||||
|             }); | ||||
|         }).catch((message) => { | ||||
|             this.domUtils.showErrorModalDefault(message, 'addon.mod_survey.cannotsubmitsurvey', true); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -158,14 +158,17 @@ export class CoreFileComponent implements OnInit, OnDestroy { | ||||
|             promise = this.fileSize ? this.domUtils.confirmDownloadSize({ size: this.fileSize, total: true }) : Promise.resolve(); | ||||
|             promise.then(() => { | ||||
|                 // User confirmed, add the file to queue.
 | ||||
|                 this.filepoolProvider.invalidateFileByUrl(this.siteId, this.fileUrl).finally(() => { | ||||
|                 return this.filepoolProvider.invalidateFileByUrl(this.siteId, this.fileUrl).finally(() => { | ||||
|                     this.isDownloading = true; | ||||
| 
 | ||||
|                     this.filepoolProvider.addToQueueByUrl(this.siteId, this.fileUrl, this.component, | ||||
|                         this.componentId, this.timemodified, undefined, undefined, 0, this.file).catch((error) => { | ||||
|                             this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true); | ||||
|                             this.calculateState(); | ||||
|                         }); | ||||
|                 }); | ||||
|             }).catch(() => { | ||||
|                 // Ignore error.
 | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -171,15 +171,14 @@ export class CoreLocalFileComponent implements OnInit { | ||||
|         // Ask confirmation.
 | ||||
|         this.domUtils.showConfirm(this.translate.instant('core.confirmdeletefile')).then(() => { | ||||
|             const modal = this.domUtils.showModalLoading(); | ||||
|             this.fileProvider.removeFile(this.relativePath).then(() => { | ||||
| 
 | ||||
|             return this.fileProvider.removeFile(this.relativePath).then(() => { | ||||
|                 this.onDelete.emit(); | ||||
|             }).catch(() => { | ||||
|                 this.domUtils.showErrorModal('core.errordeletefile', true); | ||||
|             }).finally(() => { | ||||
|                 modal.dismiss(); | ||||
|             }); | ||||
|         }).catch(() => { | ||||
|             // User cancelled.
 | ||||
|             this.domUtils.showErrorModal('core.errordeletefile', true); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -233,6 +233,8 @@ export class CoreContentLinksHelperProvider { | ||||
|                         } else { | ||||
|                             this.goToChooseSite(url); | ||||
|                         } | ||||
|                     }).catch(() => { | ||||
|                         // User canceled.
 | ||||
|                     }); | ||||
|                 } | ||||
| 
 | ||||
|  | ||||
| @ -283,18 +283,18 @@ export class CoreCourseSectionPage implements OnDestroy { | ||||
|      */ | ||||
|     prefetchCourse(): void { | ||||
|         this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course, this.sections, this.courseHandlers) | ||||
|             .then((downloaded) => { | ||||
|                 if (downloaded && this.downloadEnabled) { | ||||
|                     // Recalculate the status.
 | ||||
|                     this.courseHelper.calculateSectionsStatus(this.sections, this.course.id).catch(() => { | ||||
|                         // Ignore errors (shouldn't happen).
 | ||||
|                     }); | ||||
|                 } | ||||
|             }).catch((error) => { | ||||
|                 if (!this.isDestroyed) { | ||||
|                     this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                 } | ||||
|             }); | ||||
|                 .then(() => { | ||||
|             if (this.downloadEnabled) { | ||||
|                 // Recalculate the status.
 | ||||
|                 this.courseHelper.calculateSectionsStatus(this.sections, this.course.id).catch(() => { | ||||
|                     // Ignore errors (shouldn't happen).
 | ||||
|                 }); | ||||
|             } | ||||
|         }).catch((error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -249,8 +249,7 @@ export class CoreCourseHelperProvider { | ||||
|      * @param {any} course Course to prefetch. | ||||
|      * @param {any[]} [sections] List of course sections. | ||||
|      * @param {CoreCourseOptionsHandlerToDisplay[]} courseHandlers List of course handlers. | ||||
|      * @return {Promise<boolean>} Promise resolved with true when the download finishes, resolved with false if user doesn't | ||||
|      *                            confirm, rejected if an error occurs. | ||||
|      * @return {Promise<boolean>} Promise resolved when the download finishes, rejected if an error occurs or the user cancels. | ||||
|      */ | ||||
|     confirmAndPrefetchCourse(iconData: any, course: any, sections?: any[], courseHandlers?: CoreCourseOptionsHandlerToDisplay[]) | ||||
|             : Promise<boolean> { | ||||
| @ -288,11 +287,8 @@ export class CoreCourseHelperProvider { | ||||
|             }, (error): any => { | ||||
|                 // User cancelled or there was an error calculating the size.
 | ||||
|                 iconData.prefetchCourseIcon = initialIcon; | ||||
|                 if (error) { | ||||
|                     return Promise.reject(error); | ||||
|                 } | ||||
| 
 | ||||
|                 return false; | ||||
|                 return Promise.reject(error); | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| @ -302,9 +298,9 @@ export class CoreCourseHelperProvider { | ||||
|      * | ||||
|      * @param {any[]} courses List of courses to download. | ||||
|      * @param {Function} [onProgress] Function to call everytime a course is downloaded. | ||||
|      * @return {Promise<boolean>} Resolved with true when downloaded, resolved with false if user cancels, rejected if error. | ||||
|      * @return {Promise<boolean>} Resolved when downloaded, rejected if error or canceled. | ||||
|      */ | ||||
|     confirmAndPrefetchCourses(courses: any[], onProgress?: (data: CoreCourseCoursesProgress) => void): Promise<boolean> { | ||||
|     confirmAndPrefetchCourses(courses: any[], onProgress?: (data: CoreCourseCoursesProgress) => void): Promise<any> { | ||||
|         const siteId = this.sitesProvider.getCurrentSiteId(); | ||||
| 
 | ||||
|         // Confirm the download without checking size because it could take a while.
 | ||||
| @ -347,12 +343,7 @@ export class CoreCourseHelperProvider { | ||||
|                 onProgress({ count: 0, total: total, success: true }); | ||||
|             } | ||||
| 
 | ||||
|             return this.utils.allPromises(promises).then(() => { | ||||
|                 return true; | ||||
|             }); | ||||
|         }, () => { | ||||
|             // User cancelled.
 | ||||
|             return false; | ||||
|             return this.utils.allPromises(promises); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -426,23 +417,18 @@ export class CoreCourseHelperProvider { | ||||
|      */ | ||||
|     contextMenuPrefetch(instance: any, module: any, courseId: number): Promise<any> { | ||||
|         const initialIcon = instance.prefetchStatusIcon; | ||||
|         let cancelled = false; | ||||
| 
 | ||||
|         instance.prefetchStatusIcon = 'spinner'; // Show spinner since this operation might take a while.
 | ||||
| 
 | ||||
|         // We need to call getDownloadSize, the package might have been updated.
 | ||||
|         return this.prefetchDelegate.getModuleDownloadSize(module, courseId, true).then((size) => { | ||||
|             return this.domUtils.confirmDownloadSize(size).catch(() => { | ||||
|                 // User hasn't confirmed, stop.
 | ||||
|                 cancelled = true; | ||||
| 
 | ||||
|                 return Promise.reject(null); | ||||
|             }).then(() => { | ||||
|             return this.domUtils.confirmDownloadSize(size).then(() => { | ||||
|                 return this.prefetchDelegate.prefetchModule(module, courseId, true); | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             instance.prefetchStatusIcon = initialIcon; | ||||
|             if (!instance.isDestroyed && !cancelled) { | ||||
| 
 | ||||
|             if (!instance.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true); | ||||
|             } | ||||
|         }); | ||||
| @ -979,36 +965,37 @@ export class CoreCourseHelperProvider { | ||||
| 
 | ||||
|         // First of all, mark the course as being downloaded.
 | ||||
|         this.courseDwnPromises[siteId][course.id] = this.courseProvider.setCourseStatus(course.id, CoreConstants.DOWNLOADING, | ||||
|             siteId).then(() => { | ||||
|                 const promises = []; | ||||
|                 let allSectionsSection = sections[0]; | ||||
|                 siteId).then(() => { | ||||
| 
 | ||||
|                 // Prefetch all the sections. If the first section is "All sections", use it. Otherwise, use a fake "All sections".
 | ||||
|                 if (sections[0].id != CoreCourseProvider.ALL_SECTIONS_ID) { | ||||
|                     allSectionsSection = { id: CoreCourseProvider.ALL_SECTIONS_ID }; | ||||
|             const promises = []; | ||||
|             let allSectionsSection = sections[0]; | ||||
| 
 | ||||
|             // Prefetch all the sections. If the first section is "All sections", use it. Otherwise, use a fake "All sections".
 | ||||
|             if (sections[0].id != CoreCourseProvider.ALL_SECTIONS_ID) { | ||||
|                 allSectionsSection = { id: CoreCourseProvider.ALL_SECTIONS_ID }; | ||||
|             } | ||||
|             promises.push(this.prefetchSection(allSectionsSection, course.id, sections)); | ||||
| 
 | ||||
|             // Prefetch course options.
 | ||||
|             courseHandlers.forEach((handler) => { | ||||
|                 if (handler.prefetch) { | ||||
|                     promises.push(handler.prefetch(course)); | ||||
|                 } | ||||
|                 promises.push(this.prefetchSection(allSectionsSection, course.id, sections)); | ||||
| 
 | ||||
|                 // Prefetch course options.
 | ||||
|                 courseHandlers.forEach((handler) => { | ||||
|                     if (handler.prefetch) { | ||||
|                         promises.push(handler.prefetch(course)); | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|                 return this.utils.allPromises(promises); | ||||
|             }).then(() => { | ||||
|                 // Download success, mark the course as downloaded.
 | ||||
|                 return this.courseProvider.setCourseStatus(course.id, CoreConstants.DOWNLOADED, siteId); | ||||
|             }).catch((error) => { | ||||
|                 // Error, restore previous status.
 | ||||
|                 return this.courseProvider.setCoursePreviousStatus(course.id, siteId).then(() => { | ||||
|                     return Promise.reject(error); | ||||
|                 }); | ||||
|             }).finally(() => { | ||||
|                 delete this.courseDwnPromises[siteId][course.id]; | ||||
|             }); | ||||
| 
 | ||||
|             return this.utils.allPromises(promises); | ||||
|         }).then(() => { | ||||
|             // Download success, mark the course as downloaded.
 | ||||
|             return this.courseProvider.setCourseStatus(course.id, CoreConstants.DOWNLOADED, siteId); | ||||
|         }).catch((error) => { | ||||
|             // Error, restore previous status.
 | ||||
|             return this.courseProvider.setCoursePreviousStatus(course.id, siteId).then(() => { | ||||
|                 return Promise.reject(error); | ||||
|             }); | ||||
|         }).finally(() => { | ||||
|             delete this.courseDwnPromises[siteId][course.id]; | ||||
|         }); | ||||
| 
 | ||||
|         return this.courseDwnPromises[siteId][course.id]; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -160,9 +160,9 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { | ||||
| 
 | ||||
|         return this.courseHelper.confirmAndPrefetchCourses(this.courses, (progress) => { | ||||
|             this.prefetchCoursesData.badge = progress.count + ' / ' + progress.total; | ||||
|         }).then((downloaded) => { | ||||
|             this.prefetchCoursesData.icon = downloaded ? 'ion-android-refresh' : initialIcon; | ||||
|         }, (error) => { | ||||
|         }).then(() => { | ||||
|             this.prefetchCoursesData.icon = 'ion-android-refresh'; | ||||
|         }).catch((error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                 this.prefetchCoursesData.icon = initialIcon; | ||||
|  | ||||
| @ -362,9 +362,9 @@ export class CoreCoursesMyOverviewPage implements OnDestroy { | ||||
| 
 | ||||
|         return this.courseHelper.confirmAndPrefetchCourses(this.courses[selected], (progress) => { | ||||
|             selectedData.badge = progress.count + ' / ' + progress.total; | ||||
|         }).then((downloaded) => { | ||||
|             selectedData.icon = downloaded ? 'refresh' : initialIcon; | ||||
|         }, (error) => { | ||||
|         }).then(() => { | ||||
|             selectedData.icon = 'refresh'; | ||||
|         }).catch((error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                 selectedData.icon = initialIcon; | ||||
|  | ||||
| @ -235,7 +235,7 @@ export class CoreLoginHelperProvider { | ||||
| 
 | ||||
|         promise.then(() => { | ||||
|             this.openBrowserForSSOLogin(siteUrl, typeOfLogin, service, launchUrl); | ||||
|         }, () => { | ||||
|         }).catch(() => { | ||||
|             // User cancelled, ignore.
 | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @ -139,6 +139,15 @@ export class CoreDomUtilsProvider { | ||||
|         return Promise.resolve(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Create a "cancelled" error. These errors won't display an error message in showErrorModal functions. | ||||
|      * | ||||
|      * @return {any} The error object. | ||||
|      */ | ||||
|     createCanceledError(): any { | ||||
|         return {coreCanceled: true}; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Extract the downloadable URLs from an HTML code. | ||||
|      * | ||||
| @ -771,7 +780,7 @@ export class CoreDomUtilsProvider { | ||||
|      * @param {string} [okText] Text of the OK button. | ||||
|      * @param {string} [cancelText] Text of the Cancel button. | ||||
|      * @param {any} [options] More options. See https://ionicframework.com/docs/api/components/alert/AlertController/
 | ||||
|      * @return {Promise<void>} Promise resolved if the user confirms and rejected if he cancels. | ||||
|      * @return {Promise<void>} Promise resolved if the user confirms and rejected with a canceled error if he cancels. | ||||
|      */ | ||||
|     showConfirm(message: string, title?: string, okText?: string, cancelText?: string, options?: any): Promise<void> { | ||||
|         return new Promise<void>((resolve, reject): void => { | ||||
| @ -787,7 +796,7 @@ export class CoreDomUtilsProvider { | ||||
|                     text: cancelText || this.translate.instant('core.cancel'), | ||||
|                     role: 'cancel', | ||||
|                     handler: (): void => { | ||||
|                         reject(); | ||||
|                         reject(this.createCanceledError()); | ||||
|                     } | ||||
|                 }, | ||||
|                 { | ||||
| @ -813,7 +822,10 @@ export class CoreDomUtilsProvider { | ||||
|     showErrorModal(error: any, needsTranslate?: boolean, autocloseTime?: number): Alert { | ||||
|         if (typeof error == 'object') { | ||||
|             // We received an object instead of a string. Search for common properties.
 | ||||
|             if (typeof error.content != 'undefined') { | ||||
|             if (error.coreCanceled) { | ||||
|                 // It's a canceled error, don't display an error.
 | ||||
|                 return; | ||||
|             } else if (typeof error.content != 'undefined') { | ||||
|                 error = error.content; | ||||
|             } else if (typeof error.body != 'undefined') { | ||||
|                 error = error.body; | ||||
| @ -833,6 +845,11 @@ export class CoreDomUtilsProvider { | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (error == CoreConstants.DONT_SHOW_ERROR) { | ||||
|             // The error shouldn't be shown, stop.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const message = this.textUtils.decodeHTML(needsTranslate ? this.translate.instant(error) : error); | ||||
| 
 | ||||
|         return this.showAlert(this.getErrorTitle(message), message, undefined, autocloseTime); | ||||
| @ -848,14 +865,18 @@ export class CoreDomUtilsProvider { | ||||
|      * @return {Alert} The alert modal. | ||||
|      */ | ||||
|     showErrorModalDefault(error: any, defaultError: any, needsTranslate?: boolean, autocloseTime?: number): Alert { | ||||
|         if (error != CoreConstants.DONT_SHOW_ERROR) { | ||||
|             if (error && typeof error != 'string') { | ||||
|                 error = error.message || error.error; | ||||
|             } | ||||
|             error = typeof error == 'string' ? error : defaultError; | ||||
| 
 | ||||
|             return this.showErrorModal(error, needsTranslate, autocloseTime); | ||||
|         if (error && error.coreCanceled) { | ||||
|             // It's a canceled error, don't display an error.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (error && typeof error != 'string') { | ||||
|             error = error.message || error.error || error.content || error.body; | ||||
|         } | ||||
| 
 | ||||
|         error = typeof error == 'string' ? error : defaultError; | ||||
| 
 | ||||
|         return this.showErrorModal(error, needsTranslate, autocloseTime); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user