forked from EVOgeek/Vmeda.Online
		
	
						commit
						3e6eeb88f8
					
				| @ -317,6 +317,10 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy { | |||||||
|             // Clear temporary data from plugins.
 |             // Clear temporary data from plugins.
 | ||||||
|             await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData); |             await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData); | ||||||
| 
 | 
 | ||||||
|  |             if (sent) { | ||||||
|  |                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'assign' }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             // Submission saved, trigger events.
 |             // Submission saved, trigger events.
 | ||||||
|             this.domUtils.triggerFormSubmittedEvent(this.formElement, sent, this.sitesProvider.getCurrentSiteId()); |             this.domUtils.triggerFormSubmittedEvent(this.formElement, sent, this.sitesProvider.getCurrentSiteId()); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -117,6 +117,7 @@ export class AddonModChatChatPage { | |||||||
|      * Runs when the page is about to leave and no longer be the active page. |      * Runs when the page is about to leave and no longer be the active page. | ||||||
|      */ |      */ | ||||||
|     ionViewWillLeave(): void { |     ionViewWillLeave(): void { | ||||||
|  |         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'chat' }); | ||||||
|         this.stopPolling(); |         this.stopPolling(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ | |||||||
| 
 | 
 | ||||||
| import { Component, Optional, Injector } from '@angular/core'; | import { Component, Optional, Injector } from '@angular/core'; | ||||||
| import { Content } from 'ionic-angular'; | import { Content } from 'ionic-angular'; | ||||||
|  | import { CoreEvents, CoreEventsProvider } from '@providers/events'; | ||||||
| import { CoreTimeUtilsProvider } from '@providers/utils/time'; | import { CoreTimeUtilsProvider } from '@providers/utils/time'; | ||||||
| import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; | import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; | ||||||
| import { AddonModChoiceProvider, AddonModChoiceChoice, AddonModChoiceOption, AddonModChoiceResult } from '../../providers/choice'; | import { AddonModChoiceProvider, AddonModChoiceChoice, AddonModChoiceOption, AddonModChoiceResult } from '../../providers/choice'; | ||||||
| @ -51,9 +52,14 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|     protected hasAnsweredOnline = false; |     protected hasAnsweredOnline = false; | ||||||
|     protected now: number; |     protected now: number; | ||||||
| 
 | 
 | ||||||
|     constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() content: Content, |     constructor( | ||||||
|             private choiceOffline: AddonModChoiceOfflineProvider, private choiceSync: AddonModChoiceSyncProvider, |             injector: Injector, | ||||||
|             private timeUtils: CoreTimeUtilsProvider) { |             protected choiceProvider: AddonModChoiceProvider, | ||||||
|  |             @Optional() content: Content, | ||||||
|  |             protected choiceOffline: AddonModChoiceOfflineProvider, | ||||||
|  |             protected choiceSync: AddonModChoiceSyncProvider, | ||||||
|  |             protected timeUtils: CoreTimeUtilsProvider, | ||||||
|  |             ) { | ||||||
|         super(injector, content); |         super(injector, content); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -359,6 +365,10 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|                 this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata); |                 this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata); | ||||||
|                 this.domUtils.scrollToTop(this.content); |                 this.domUtils.scrollToTop(this.content); | ||||||
| 
 | 
 | ||||||
|  |                 if (online) { | ||||||
|  |                     CoreEvents.instance.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: this.moduleName }); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|                 return this.dataUpdated(online); |                 return this.dataUpdated(online); | ||||||
|             }).catch((message) => { |             }).catch((message) => { | ||||||
|                 this.domUtils.showErrorModalDefault(message, 'addon.mod_choice.cannotsubmit', true); |                 this.domUtils.showErrorModalDefault(message, 'addon.mod_choice.cannotsubmit', true); | ||||||
|  | |||||||
| @ -217,6 +217,10 @@ export class AddonModDataEditPage { | |||||||
| 
 | 
 | ||||||
|                     this.domUtils.triggerFormSubmittedEvent(this.formElement, result.sent, this.siteId); |                     this.domUtils.triggerFormSubmittedEvent(this.formElement, result.sent, this.siteId); | ||||||
| 
 | 
 | ||||||
|  |                     if (result.sent) { | ||||||
|  |                         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'data' }); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     const promises = []; |                     const promises = []; | ||||||
| 
 | 
 | ||||||
|                     this.entryId = this.entryId || result.newentryid; |                     this.entryId = this.entryId || result.newentryid; | ||||||
|  | |||||||
| @ -280,6 +280,8 @@ export class AddonModFeedbackFormPage implements OnDestroy { | |||||||
|                     promises.push(this.feedbackProvider.invalidateFeedbackAccessInformationData(this.feedback.id)); |                     promises.push(this.feedbackProvider.invalidateFeedbackAccessInformationData(this.feedback.id)); | ||||||
|                     promises.push(this.feedbackProvider.invalidateResumePageData(this.feedback.id)); |                     promises.push(this.feedbackProvider.invalidateResumePageData(this.feedback.id)); | ||||||
| 
 | 
 | ||||||
|  |                     this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'feedback' }); | ||||||
|  | 
 | ||||||
|                     return Promise.all(promises).then(() => { |                     return Promise.all(promises).then(() => { | ||||||
|                         return this.fetchAccessData(); |                         return this.fetchAccessData(); | ||||||
|                     }); |                     }); | ||||||
|  | |||||||
| @ -473,6 +473,8 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { | |||||||
|             if (discussionIds) { |             if (discussionIds) { | ||||||
|                 // Data sent to server, delete stored files (if any).
 |                 // Data sent to server, delete stored files (if any).
 | ||||||
|                 this.forumHelper.deleteNewDiscussionStoredFiles(this.forumId, discTimecreated); |                 this.forumHelper.deleteNewDiscussionStoredFiles(this.forumId, discTimecreated); | ||||||
|  | 
 | ||||||
|  |                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'forum' }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (discussionIds && discussionIds.length < groupIds.length) { |             if (discussionIds && discussionIds.length < groupIds.length) { | ||||||
|  | |||||||
| @ -246,6 +246,7 @@ export class AddonModGlossaryEditPage implements OnInit { | |||||||
|             if (entryId) { |             if (entryId) { | ||||||
|                 // Data sent to server, delete stored files (if any).
 |                 // Data sent to server, delete stored files (if any).
 | ||||||
|                 this.glossaryHelper.deleteStoredFiles(this.glossary.id, this.entry.concept, timecreated); |                 this.glossaryHelper.deleteStoredFiles(this.glossary.id, this.entry.concept, timecreated); | ||||||
|  |                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'glossary' }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const data = { |             const data = { | ||||||
|  | |||||||
| @ -18,7 +18,6 @@ import { IonicPage, NavParams, Content, PopoverController, ModalController, Moda | |||||||
| import { TranslateService } from '@ngx-translate/core'; | import { TranslateService } from '@ngx-translate/core'; | ||||||
| import { CoreAppProvider } from '@providers/app'; | import { CoreAppProvider } from '@providers/app'; | ||||||
| import { CoreEventsProvider } from '@providers/events'; | import { CoreEventsProvider } from '@providers/events'; | ||||||
| import { CoreLoggerProvider } from '@providers/logger'; |  | ||||||
| import { CoreSitesProvider } from '@providers/sites'; | import { CoreSitesProvider } from '@providers/sites'; | ||||||
| import { CoreSyncProvider } from '@providers/sync'; | import { CoreSyncProvider } from '@providers/sync'; | ||||||
| import { CoreDomUtilsProvider } from '@providers/utils/dom'; | import { CoreDomUtilsProvider } from '@providers/utils/dom'; | ||||||
| @ -80,7 +79,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy { | |||||||
|     protected loadingMenu: boolean; // Whether the lesson menu is being loaded.
 |     protected loadingMenu: boolean; // Whether the lesson menu is being loaded.
 | ||||||
|     protected lessonPages: any[]; // Lesson pages (for the lesson menu).
 |     protected lessonPages: any[]; // Lesson pages (for the lesson menu).
 | ||||||
| 
 | 
 | ||||||
|     constructor(protected navParams: NavParams, logger: CoreLoggerProvider, protected translate: TranslateService, |     constructor(protected navParams: NavParams, protected translate: TranslateService, | ||||||
|             protected eventsProvider: CoreEventsProvider, protected sitesProvider: CoreSitesProvider, |             protected eventsProvider: CoreEventsProvider, protected sitesProvider: CoreSitesProvider, | ||||||
|             protected syncProvider: CoreSyncProvider, protected domUtils: CoreDomUtilsProvider, popoverCtrl: PopoverController, |             protected syncProvider: CoreSyncProvider, protected domUtils: CoreDomUtilsProvider, popoverCtrl: PopoverController, | ||||||
|             protected timeUtils: CoreTimeUtilsProvider, protected lessonProvider: AddonModLessonProvider, |             protected timeUtils: CoreTimeUtilsProvider, protected lessonProvider: AddonModLessonProvider, | ||||||
| @ -369,6 +368,8 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy { | |||||||
|             this.messages = this.messages.concat(data.messages); |             this.messages = this.messages.concat(data.messages); | ||||||
|             this.processData = undefined; |             this.processData = undefined; | ||||||
| 
 | 
 | ||||||
|  |             this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'lesson' }); | ||||||
|  | 
 | ||||||
|             // Format activity link if present.
 |             // Format activity link if present.
 | ||||||
|             if (this.eolData && this.eolData.activitylink) { |             if (this.eolData && this.eolData.activitylink) { | ||||||
|                 this.eolData.activitylink.value = this.lessonHelper.formatActivityLink(this.eolData.activitylink.value); |                 this.eolData.activitylink.value = this.lessonHelper.formatActivityLink(this.eolData.activitylink.value); | ||||||
|  | |||||||
| @ -376,6 +376,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy { | |||||||
|                     synced: !this.offline |                     synced: !this.offline | ||||||
|                 }, this.sitesProvider.getCurrentSiteId()); |                 }, this.sitesProvider.getCurrentSiteId()); | ||||||
| 
 | 
 | ||||||
|  |                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'quiz' }); | ||||||
|  | 
 | ||||||
|                 // Leave the player.
 |                 // Leave the player.
 | ||||||
|                 this.forceLeave = true; |                 this.forceLeave = true; | ||||||
|                 this.navCtrl.pop(); |                 this.navCtrl.pop(); | ||||||
|  | |||||||
| @ -310,6 +310,8 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { | |||||||
|      * Page will leave. |      * Page will leave. | ||||||
|      */ |      */ | ||||||
|     ionViewWillUnload(): void { |     ionViewWillUnload(): void { | ||||||
|  |         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'scorm' }); | ||||||
|  | 
 | ||||||
|         // Empty src when leaving the state so unload event is triggered in the iframe.
 |         // Empty src when leaving the state so unload event is triggered in the iframe.
 | ||||||
|         this.src = ''; |         this.src = ''; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ | |||||||
| import { Component, Optional, Injector } from '@angular/core'; | import { Component, Optional, Injector } from '@angular/core'; | ||||||
| import { Content } from 'ionic-angular'; | import { Content } from 'ionic-angular'; | ||||||
| import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; | import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; | ||||||
|  | import { CoreEvents, CoreEventsProvider } from '@providers/events'; | ||||||
| import { AddonModSurveyProvider, AddonModSurveySurvey } from '../../providers/survey'; | import { AddonModSurveyProvider, AddonModSurveySurvey } from '../../providers/survey'; | ||||||
| import { AddonModSurveyHelperProvider, AddonModSurveyQuestionFormatted } from '../../providers/helper'; | import { AddonModSurveyHelperProvider, AddonModSurveyQuestionFormatted } from '../../providers/helper'; | ||||||
| import { AddonModSurveyOfflineProvider } from '../../providers/offline'; | import { AddonModSurveyOfflineProvider } from '../../providers/offline'; | ||||||
| @ -38,9 +39,14 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|     protected userId: number; |     protected userId: number; | ||||||
|     protected syncEventName = AddonModSurveySyncProvider.AUTO_SYNCED; |     protected syncEventName = AddonModSurveySyncProvider.AUTO_SYNCED; | ||||||
| 
 | 
 | ||||||
|     constructor(injector: Injector, private surveyProvider: AddonModSurveyProvider, @Optional() content: Content, |     constructor( | ||||||
|             private surveyHelper: AddonModSurveyHelperProvider, private surveyOffline: AddonModSurveyOfflineProvider, |             injector: Injector, | ||||||
|             private surveySync: AddonModSurveySyncProvider) { |             protected surveyProvider: AddonModSurveyProvider, | ||||||
|  |             @Optional() content: Content, | ||||||
|  |             protected surveyHelper: AddonModSurveyHelperProvider, | ||||||
|  |             protected surveyOffline: AddonModSurveyOfflineProvider, | ||||||
|  |             protected surveySync: AddonModSurveySyncProvider, | ||||||
|  |             ) { | ||||||
|         super(injector, content); |         super(injector, content); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -185,6 +191,8 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then((online) => { |             return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then((online) => { | ||||||
|  |                 CoreEvents.instance.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: this.moduleName }); | ||||||
|  | 
 | ||||||
|                 if (online && this.isPrefetched()) { |                 if (online && this.isPrefetched()) { | ||||||
|                     // The survey is downloaded, update the data.
 |                     // The survey is downloaded, update the data.
 | ||||||
|                     return this.surveySync.prefetchAfterUpdate(this.module, this.courseId).then(() => { |                     return this.surveySync.prefetchAfterUpdate(this.module, this.courseId).then(() => { | ||||||
|  | |||||||
| @ -465,6 +465,8 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy { | |||||||
|                     this.domUtils.triggerFormSubmittedEvent(this.formElement, id > 0, this.sitesProvider.getCurrentSiteId()); |                     this.domUtils.triggerFormSubmittedEvent(this.formElement, id > 0, this.sitesProvider.getCurrentSiteId()); | ||||||
| 
 | 
 | ||||||
|                     if (id > 0) { |                     if (id > 0) { | ||||||
|  |                         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'wiki' }); | ||||||
|  | 
 | ||||||
|                         // Page was created, get its data and go to the page.
 |                         // Page was created, get its data and go to the page.
 | ||||||
|                         this.pageId = id; |                         this.pageId = id; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -388,6 +388,8 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy { | |||||||
|                 data['submissionId'] = newSubmissionId; |                 data['submissionId'] = newSubmissionId; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|  |             this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'workshop' }); | ||||||
|  | 
 | ||||||
|             const promise = newSubmissionId ? this.workshopProvider.invalidateSubmissionData(this.workshopId, newSubmissionId) : |             const promise = newSubmissionId ? this.workshopProvider.invalidateSubmissionData(this.workshopId, newSubmissionId) : | ||||||
|                 Promise.resolve(); |                 Promise.resolve(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -94,5 +94,12 @@ | |||||||
|     "statusbarlighttextremotetheme": true, |     "statusbarlighttextremotetheme": true, | ||||||
|     "enableanalytics": false, |     "enableanalytics": false, | ||||||
|     "forceColorScheme": "", |     "forceColorScheme": "", | ||||||
|     "webviewscheme": "moodleappfs" |     "webviewscheme": "moodleappfs", | ||||||
|  |     "appstores": { | ||||||
|  |         "android": "com.moodle.moodlemobile", | ||||||
|  |         "ios": "id633359593", | ||||||
|  |         "windows": "moodle-desktop/9p9bwvhdc8c8", | ||||||
|  |         "mac": "id1255924440", | ||||||
|  |         "linux": "https://download.moodle.org/desktop/download.php?platform=linux&arch=64" | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -277,7 +277,11 @@ export class CoreLoginSitePage { | |||||||
|             } |             } | ||||||
|         ]; |         ]; | ||||||
| 
 | 
 | ||||||
|         this.domUtils.showAlertWithButtons(this.translate.instant('core.cannotconnect'), message, buttons); |         this.domUtils.showAlertWithOptions({ | ||||||
|  |             title: this.translate.instant('core.cannotconnect'), | ||||||
|  |             message, | ||||||
|  |             buttons, | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -369,10 +373,11 @@ export class CoreLoginSitePage { | |||||||
|      */ |      */ | ||||||
|     showInstructionsAndScanQR(): void { |     showInstructionsAndScanQR(): void { | ||||||
|         // Show some instructions first.
 |         // Show some instructions first.
 | ||||||
|         this.domUtils.showAlertWithButtons( |         this.domUtils.showAlertWithOptions({ | ||||||
|             this.translate.instant('core.login.faqwhereisqrcode'), |             title: this.translate.instant('core.login.faqwhereisqrcode'), | ||||||
|             this.translate.instant('core.login.faqwhereisqrcodeanswer', {$image: CoreLoginHelperProvider.FAQ_QRCODE_IMAGE_HTML}), |             message: this.translate.instant('core.login.faqwhereisqrcodeanswer', | ||||||
|             [ |                 {$image: CoreLoginHelperProvider.FAQ_QRCODE_IMAGE_HTML}), | ||||||
|  |             buttons: [ | ||||||
|                 { |                 { | ||||||
|                     text: this.translate.instant('core.cancel'), |                     text: this.translate.instant('core.cancel'), | ||||||
|                     role: 'cancel' |                     role: 'cancel' | ||||||
| @ -383,8 +388,8 @@ export class CoreLoginSitePage { | |||||||
|                         this.scanQR(); |                         this.scanQR(); | ||||||
|                     } |                     } | ||||||
|                 }, |                 }, | ||||||
|             ] |             ], | ||||||
|         ); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; | |||||||
| import { Location } from '@angular/common'; | import { Location } from '@angular/common'; | ||||||
| import { Platform, AlertController, NavController, NavOptions } from 'ionic-angular'; | import { Platform, AlertController, NavController, NavOptions } from 'ionic-angular'; | ||||||
| import { TranslateService } from '@ngx-translate/core'; | import { TranslateService } from '@ngx-translate/core'; | ||||||
| import { CoreAppProvider } from '@providers/app'; | import { CoreAppProvider, CoreStoreConfig } from '@providers/app'; | ||||||
| import { CoreConfigProvider } from '@providers/config'; | import { CoreConfigProvider } from '@providers/config'; | ||||||
| import { CoreEventsProvider } from '@providers/events'; | import { CoreEventsProvider } from '@providers/events'; | ||||||
| import { CoreInitDelegate } from '@providers/init'; | import { CoreInitDelegate } from '@providers/init'; | ||||||
| @ -1180,13 +1180,7 @@ export class CoreLoginHelperProvider { | |||||||
|      * @param message The warning message. |      * @param message The warning message. | ||||||
|      */ |      */ | ||||||
|     protected showWorkplaceNoticeModal(message: string): void { |     protected showWorkplaceNoticeModal(message: string): void { | ||||||
|         let link; |         const link = this.appProvider.getAppStoreUrl({android: 'com.moodle.workplace', ios: 'id1470929705' }); | ||||||
| 
 |  | ||||||
|         if (this.platform.is('android')) { |  | ||||||
|             link = 'market://details?id=com.moodle.workplace'; |  | ||||||
|         } else if (this.platform.is('ios')) { |  | ||||||
|             link = 'itms-apps://itunes.apple.com/app/id1470929705'; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         this.showDownloadAppNoticeModal(message, link); |         this.showDownloadAppNoticeModal(message, link); | ||||||
|     } |     } | ||||||
| @ -1197,20 +1191,12 @@ export class CoreLoginHelperProvider { | |||||||
|      * @param message The warning message. |      * @param message The warning message. | ||||||
|      */ |      */ | ||||||
|     protected showMoodleAppNoticeModal(message: string): void { |     protected showMoodleAppNoticeModal(message: string): void { | ||||||
|         let link; |         const storesConfig: CoreStoreConfig = CoreConfigConstants.appstores; | ||||||
|  |         storesConfig.desktop = 'https://download.moodle.org/desktop/'; | ||||||
|  |         storesConfig.mobile = 'https://download.moodle.org/mobile/'; | ||||||
|  |         storesConfig.default = 'https://download.moodle.org/mobile/'; | ||||||
| 
 | 
 | ||||||
|         if (this.appProvider.isWindows()) { |         const link = this.appProvider.getAppStoreUrl(storesConfig); | ||||||
|             link = 'https://download.moodle.org/desktop/download.php?platform=windows'; |  | ||||||
|         } else if (this.appProvider.isLinux()) { |  | ||||||
|             link = 'https://download.moodle.org/desktop/download.php?platform=linux&arch=' + |  | ||||||
|                     (this.appProvider.is64Bits() ? '64' : '32'); |  | ||||||
|         } else if (this.appProvider.isMac()) { |  | ||||||
|             link = 'itms-apps://itunes.apple.com/app/id1255924440'; |  | ||||||
|         } else if (this.platform.is('android')) { |  | ||||||
|             link = 'market://details?id=com.moodle.moodlemobile'; |  | ||||||
|         } else if (this.platform.is('ios')) { |  | ||||||
|             link = 'itms-apps://itunes.apple.com/app/id633359593'; |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         this.showDownloadAppNoticeModal(message, link); |         this.showDownloadAppNoticeModal(message, link); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										14
									
								
								src/core/viewer/pages/textarea/textarea.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/core/viewer/pages/textarea/textarea.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | <ion-header> | ||||||
|  |     <ion-navbar> | ||||||
|  |         <ion-title>{{ title }}</ion-title> | ||||||
|  |     </ion-navbar> | ||||||
|  | </ion-header> | ||||||
|  | <ion-content> | ||||||
|  |     <div class="prompt-message"><core-format-text [text]="message"></core-format-text></div> | ||||||
|  |     <ion-textarea rows="1" core-auto-rows name="feedback" [attr.aria-multiline]="true" [(ngModel)]="text" [placeholder]="placeholder"></ion-textarea> | ||||||
|  |     <div class="prompt-button-group"> | ||||||
|  |         <button *ngFor="let button of buttons" ion-button="prompt-button" (click)="buttonClicked(button)" [ngClass]="button.cssClass"> | ||||||
|  |             {{ button.text }} | ||||||
|  |         </button> | ||||||
|  |     </div> | ||||||
|  | </ion-content> | ||||||
							
								
								
									
										36
									
								
								src/core/viewer/pages/textarea/textarea.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								src/core/viewer/pages/textarea/textarea.module.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | // (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 { NgModule } from '@angular/core'; | ||||||
|  | import { IonicPageModule } from 'ionic-angular'; | ||||||
|  | import { TranslateModule } from '@ngx-translate/core'; | ||||||
|  | import { CoreViewerTextAreaPage } from './textarea'; | ||||||
|  | import { CoreComponentsModule } from '@components/components.module'; | ||||||
|  | import { CoreDirectivesModule } from '@directives/directives.module'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Module to lazy load the page. | ||||||
|  |  */ | ||||||
|  | @NgModule({ | ||||||
|  |     declarations: [ | ||||||
|  |         CoreViewerTextAreaPage | ||||||
|  |     ], | ||||||
|  |     imports: [ | ||||||
|  |         CoreComponentsModule, | ||||||
|  |         CoreDirectivesModule, | ||||||
|  |         IonicPageModule.forChild(CoreViewerTextAreaPage), | ||||||
|  |         TranslateModule.forChild() | ||||||
|  |     ] | ||||||
|  | }) | ||||||
|  | export class CoreViewerTextAreaPageModule {} | ||||||
							
								
								
									
										187
									
								
								src/core/viewer/pages/textarea/textarea.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/core/viewer/pages/textarea/textarea.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | |||||||
|  | $core-modal-promt-min-width: 320px; | ||||||
|  | 
 | ||||||
|  | ion-app.app-root ion-modal.core-modal-prompt { | ||||||
|  |     /* Some styles have been copied from ionic alert component. */ | ||||||
|  |     @include position(0, 0, 0, 0); | ||||||
|  |     position: absolute; | ||||||
|  |     z-index: $z-index-overlay; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: center; | ||||||
|  |     contain: strict; | ||||||
|  | 
 | ||||||
|  |     ion-backdrop { | ||||||
|  |         visibility: visible; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .header { | ||||||
|  |         &::after { | ||||||
|  |             background: none; | ||||||
|  |         } | ||||||
|  |         .toolbar-background { | ||||||
|  |             display: none; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .prompt-button-group { | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: row; | ||||||
|  | 
 | ||||||
|  |         .prompt-button { | ||||||
|  |             @include margin(0); | ||||||
|  | 
 | ||||||
|  |             z-index: 0; | ||||||
|  |             display: block; | ||||||
|  | 
 | ||||||
|  |             font-size: $alert-button-font-size; | ||||||
|  |             line-height: $alert-button-line-height; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ion-textarea { | ||||||
|  |         @include placeholder($alert-input-placeholder-color); | ||||||
|  |         @include padding($alert-md-message-padding-top, $alert-md-message-padding-end, $alert-md-message-padding-bottom, $alert-md-message-padding-start); | ||||||
|  |         border: 0; | ||||||
|  |         background: inherit; | ||||||
|  | 
 | ||||||
|  |         textarea { | ||||||
|  |             margin: 0; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .prompt-message { | ||||||
|  |         @include deprecated-variable(padding, $alert-md-message-padding) { | ||||||
|  |             @include padding($alert-md-message-padding-top, $alert-md-message-padding-end, $alert-md-message-padding-bottom, $alert-md-message-padding-start); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .modal-wrapper { | ||||||
|  |         z-index: $z-index-overlay-wrapper; | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         min-width: $core-modal-promt-min-width; | ||||||
|  |         max-height: $alert-max-height; | ||||||
|  |         opacity: 0; | ||||||
|  |         contain: content; | ||||||
|  |         height: auto; | ||||||
|  | 
 | ||||||
|  |         page-core-viewer-textarea, | ||||||
|  |         ion-content, | ||||||
|  |         .fixed-content, | ||||||
|  |         .scroll-content { | ||||||
|  |             position: relative; | ||||||
|  |             background: $white; | ||||||
|  |             overflow: hidden; | ||||||
|  |         } | ||||||
|  |         .fixed-content { | ||||||
|  |             display: none; | ||||||
|  |         } | ||||||
|  |         .scroll-content { | ||||||
|  |             padding: 0 !important; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .content-md .prompt-button-group { | ||||||
|  |         flex-wrap: $alert-md-button-group-flex-wrap; | ||||||
|  |         justify-content: $alert-md-button-group-justify-content; | ||||||
|  | 
 | ||||||
|  |         @include deprecated-variable(padding, $alert-md-button-group-padding) { | ||||||
|  |             @include padding($alert-md-button-group-padding-top, $alert-md-button-group-padding-end, $alert-md-button-group-padding-bottom, $alert-md-button-group-padding-start); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .prompt-button { | ||||||
|  |             @include text-align($alert-md-button-text-align); | ||||||
|  |             @include border-radius($alert-md-button-border-radius); | ||||||
|  | 
 | ||||||
|  |             // necessary for ripple to work properly | ||||||
|  |             position: relative; | ||||||
|  |             overflow: hidden; | ||||||
|  | 
 | ||||||
|  |             font-weight: $alert-md-button-font-weight; | ||||||
|  |             text-transform: $alert-md-button-text-transform; | ||||||
|  |             color: $alert-md-button-text-color; | ||||||
|  |             background-color: $alert-md-button-background-color; | ||||||
|  | 
 | ||||||
|  |             @include deprecated-variable(margin, $alert-md-button-margin) { | ||||||
|  |                 @include margin($alert-md-button-margin-top, $alert-md-button-margin-end, $alert-md-button-margin-bottom, $alert-md-button-margin-start); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             @include deprecated-variable(padding, $alert-md-button-padding) { | ||||||
|  |                 @include padding($alert-md-button-padding-top, $alert-md-button-padding-end, $alert-md-button-padding-bottom, $alert-md-button-padding-start); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .prompt-button.activated { | ||||||
|  |             background-color: $alert-md-button-background-color-activated; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .prompt-button .button-inner { | ||||||
|  |             justify-content: $alert-md-button-group-justify-content; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .content-ios .prompt-button-group { | ||||||
|  |         @include margin-horizontal(null, -$alert-ios-button-border-width); | ||||||
|  | 
 | ||||||
|  |         flex-wrap: $alert-ios-button-group-flex-wrap; | ||||||
|  |         .prompt-button { | ||||||
|  |             @include margin($alert-ios-button-margin); | ||||||
|  |             @include border-radius($alert-ios-button-border-radius); | ||||||
|  | 
 | ||||||
|  |             overflow: hidden; | ||||||
|  | 
 | ||||||
|  |             flex: $alert-ios-button-flex; | ||||||
|  | 
 | ||||||
|  |             min-width: $alert-ios-button-min-width; | ||||||
|  |             height: $alert-ios-button-min-height; | ||||||
|  | 
 | ||||||
|  |             border-top: $alert-ios-button-border-width $alert-ios-button-border-style $alert-ios-button-border-color; | ||||||
|  |             border-right: $alert-ios-button-border-width $alert-ios-button-border-style $alert-ios-button-border-color; | ||||||
|  |             font-size: $alert-ios-button-font-size; | ||||||
|  |             color: $alert-ios-button-text-color; | ||||||
|  |             background-color: $alert-ios-button-background-color; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .prompt-button:last-child { | ||||||
|  |             border-right: 0; | ||||||
|  |             font-weight: $alert-ios-button-main-font-weight; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         .prompt-button.activated { | ||||||
|  |             background-color: $alert-ios-button-background-color-activated; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ion-app.app-root-md ion-modal.core-modal-prompt { | ||||||
|  |     .modal-wrapper { | ||||||
|  |         @include border-radius($alert-md-border-radius); | ||||||
|  |         max-width: $alert-md-max-width; | ||||||
|  |         background-color: $alert-md-background-color; | ||||||
|  |         box-shadow: $alert-md-box-shadow; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .toolbar-content .toolbar-title { | ||||||
|  |         color: $alert-md-message-text-color; | ||||||
|  |         white-space: normal; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | ion-app.app-root-ios ion-modal.core-modal-prompt { | ||||||
|  |     .modal-wrapper { | ||||||
|  |         @include border-radius($alert-ios-border-radius); | ||||||
|  |         overflow: hidden; | ||||||
|  |         max-width: $alert-ios-max-width; | ||||||
|  |         background-color: $alert-ios-background; | ||||||
|  |         box-shadow: $alert-ios-box-shadow; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     .toolbar-content .toolbar-title { | ||||||
|  |         color: $alert-ios-message-text-color; | ||||||
|  |         white-space: normal; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     ion-title { | ||||||
|  |         padding: 0; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										71
									
								
								src/core/viewer/pages/textarea/textarea.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/core/viewer/pages/textarea/textarea.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | // (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 { Component } from '@angular/core'; | ||||||
|  | import { IonicPage, ViewController, NavParams, AlertButton } from 'ionic-angular'; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Page to render a textarea prompt. | ||||||
|  |  */ | ||||||
|  | @IonicPage({ segment: 'core-viewer-textarea' }) | ||||||
|  | @Component({ | ||||||
|  |     selector: 'page-core-viewer-textarea', | ||||||
|  |     templateUrl: 'textarea.html', | ||||||
|  | }) | ||||||
|  | export class CoreViewerTextAreaPage { | ||||||
|  |     title: string; | ||||||
|  |     message: string; | ||||||
|  |     placeholder: string; | ||||||
|  |     buttons: AlertButton[]; | ||||||
|  |     text = ''; | ||||||
|  | 
 | ||||||
|  |     constructor( | ||||||
|  |             protected viewCtrl: ViewController, | ||||||
|  |             params: NavParams, | ||||||
|  |             ) { | ||||||
|  |         this.title = params.get('title'); | ||||||
|  |         this.message = params.get('message'); | ||||||
|  |         this.placeholder = params.get('placeholder') || ''; | ||||||
|  | 
 | ||||||
|  |         const buttons = params.get('buttons'); | ||||||
|  | 
 | ||||||
|  |         this.buttons = buttons.map((button) => { | ||||||
|  |             if (typeof button === 'string') { | ||||||
|  |                 return { text: button }; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return button; | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Button clicked. | ||||||
|  |      * | ||||||
|  |      * @param button: Clicked button. | ||||||
|  |      */ | ||||||
|  |     buttonClicked(button: AlertButton): void { | ||||||
|  |         let shouldDismiss = true; | ||||||
|  |         if (button.handler) { | ||||||
|  |             // A handler has been provided, execute it pass the handler the values from the inputs
 | ||||||
|  |             if (button.handler(this.text) === false) { | ||||||
|  |                 // If the return value of the handler is false then do not dismiss
 | ||||||
|  |                 shouldDismiss = false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (shouldDismiss) { | ||||||
|  |             this.viewCtrl.dismiss(button.role); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -50,6 +50,51 @@ export interface CoreRedirectData { | |||||||
|     timemodified?: number; |     timemodified?: number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Store config data. | ||||||
|  |  */ | ||||||
|  | export interface CoreStoreConfig { | ||||||
|  |     /** | ||||||
|  |      * ID of the Apple store where the desktop Mac app is uploaded. | ||||||
|  |      */ | ||||||
|  |     mac?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * ID of the Windows store where the desktop Windows app is uploaded. | ||||||
|  |      */ | ||||||
|  |     windows?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Url with the desktop linux download link. | ||||||
|  |      */ | ||||||
|  |     linux?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fallback URL when the desktop options is not set. | ||||||
|  |      */ | ||||||
|  |     desktop?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * ID of the Apple store where the mobile iOS app is uploaded. | ||||||
|  |      */ | ||||||
|  |     ios?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * ID of the Google play store where the android app is uploaded. | ||||||
|  |      */ | ||||||
|  |     android?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fallback URL when the mobile options is not set. | ||||||
|  |      */ | ||||||
|  |     mobile?: string; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fallback URL when the other fallbacks options are not set. | ||||||
|  |      */ | ||||||
|  |     default?: string; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * App DB schema and migration function. |  * App DB schema and migration function. | ||||||
|  */ |  */ | ||||||
| @ -255,6 +300,44 @@ export class CoreAppProvider { | |||||||
|         return this.appCtrl.getRootNavs()[0]; |         return this.appCtrl.getRootNavs()[0]; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Get app store URL. | ||||||
|  |      * | ||||||
|  |      * @param  storesConfig Config params to send the user to the right place. | ||||||
|  |      * @return Store URL. | ||||||
|  |      */ | ||||||
|  |      getAppStoreUrl(storesConfig: CoreStoreConfig): string { | ||||||
|  |         if (this.isMac() && storesConfig.mac) { | ||||||
|  |             return 'itms-apps://itunes.apple.com/app/' + storesConfig.mac; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isWindows() && storesConfig.windows) { | ||||||
|  |             return 'https://www.microsoft.com/p/' + storesConfig.windows; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isLinux() && storesConfig.linux) { | ||||||
|  |             return storesConfig.linux; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isDesktop() && storesConfig.desktop) { | ||||||
|  |             return storesConfig.desktop; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isIOS() && storesConfig.ios) { | ||||||
|  |             return 'itms-apps://itunes.apple.com/app/' + storesConfig.ios; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isAndroid() && storesConfig.android) { | ||||||
|  |             return 'market://details?id=' + storesConfig.android; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.isMobile() && storesConfig.mobile) { | ||||||
|  |             return storesConfig.mobile; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return storesConfig.default || null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Returns whether the user agent is controlled by automation. I.e. Behat testing. |      * Returns whether the user agent is controlled by automation. I.e. Behat testing. | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -67,6 +67,7 @@ export class CoreEventsProvider { | |||||||
|     static WS_CACHE_INVALIDATED = 'ws_cache_invalidated'; |     static WS_CACHE_INVALIDATED = 'ws_cache_invalidated'; | ||||||
|     static SITE_STORAGE_DELETED = 'site_storage_deleted'; |     static SITE_STORAGE_DELETED = 'site_storage_deleted'; | ||||||
|     static FORM_ACTION = 'form_action'; |     static FORM_ACTION = 'form_action'; | ||||||
|  |     static ACTIVITY_DATA_SENT = 'activity_data_sent'; | ||||||
| 
 | 
 | ||||||
|     protected logger; |     protected logger; | ||||||
|     protected observables: { [s: string]: Subject<any> } = {}; |     protected observables: { [s: string]: Subject<any> } = {}; | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
| import { Injectable, Injector } from '@angular/core'; | import { Injectable, Injector } from '@angular/core'; | ||||||
| import { HttpClient } from '@angular/common/http'; | import { HttpClient } from '@angular/common/http'; | ||||||
| import { TranslateService } from '@ngx-translate/core'; | import { TranslateService } from '@ngx-translate/core'; | ||||||
| import { CoreAppProvider, CoreAppSchema } from './app'; | import { CoreAppProvider, CoreAppSchema, CoreStoreConfig } from './app'; | ||||||
| import { CoreEventsProvider } from './events'; | import { CoreEventsProvider } from './events'; | ||||||
| import { CoreLoggerProvider } from './logger'; | import { CoreLoggerProvider } from './logger'; | ||||||
| import { CoreSitesFactoryProvider } from './sites-factory'; | import { CoreSitesFactoryProvider } from './sites-factory'; | ||||||
| @ -1001,19 +1001,15 @@ export class CoreSitesProvider { | |||||||
|                 appVersion = this.convertVersionName(CoreConfigConstants.versionname); |                 appVersion = this.convertVersionName(CoreConfigConstants.versionname); | ||||||
| 
 | 
 | ||||||
|             if (requiredVersion > appVersion) { |             if (requiredVersion > appVersion) { | ||||||
|                 let downloadUrl = ''; |                 const storesConfig: CoreStoreConfig = { | ||||||
|  |                     android: config.tool_mobile_androidappid || false, | ||||||
|  |                     ios: config.tool_mobile_iosappid || false, | ||||||
|  |                     desktop: config.tool_mobile_setuplink || 'https://download.moodle.org/desktop/', | ||||||
|  |                     mobile: config.tool_mobile_setuplink || 'https://download.moodle.org/mobile/', | ||||||
|  |                     default: config.tool_mobile_setuplink, | ||||||
|  |                 }; | ||||||
| 
 | 
 | ||||||
|                 if (this.appProvider.isAndroid() && config.tool_mobile_androidappid) { |                 const downloadUrl = this.appProvider.getAppStoreUrl(storesConfig); | ||||||
|                     downloadUrl = 'market://details?id=' + config.tool_mobile_androidappid; |  | ||||||
|                 } else if (this.appProvider.isIOS() && config.tool_mobile_iosappid) { |  | ||||||
|                     downloadUrl = 'itms-apps://itunes.apple.com/app/id' + config.tool_mobile_iosappid; |  | ||||||
|                 } else if (config.tool_mobile_setuplink) { |  | ||||||
|                     downloadUrl = config.tool_mobile_setuplink; |  | ||||||
|                 } else if (this.appProvider.isMobile()) { |  | ||||||
|                     downloadUrl = 'https://download.moodle.org/mobile/'; |  | ||||||
|                 } else { |  | ||||||
|                     downloadUrl = 'https://download.moodle.org/desktop/'; |  | ||||||
|                 } |  | ||||||
| 
 | 
 | ||||||
|                 siteId = siteId || this.getCurrentSiteId(); |                 siteId = siteId || this.getCurrentSiteId(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ | |||||||
| import { Injectable, SimpleChange, ElementRef } from '@angular/core'; | import { Injectable, SimpleChange, ElementRef } from '@angular/core'; | ||||||
| import { | import { | ||||||
|     LoadingController, Loading, ToastController, Toast, AlertController, Alert, Platform, Content, PopoverController, |     LoadingController, Loading, ToastController, Toast, AlertController, Alert, Platform, Content, PopoverController, | ||||||
|     ModalController, AlertButton |     ModalController, AlertButton, AlertOptions | ||||||
| } from 'ionic-angular'; | } from 'ionic-angular'; | ||||||
| import { DomSanitizer } from '@angular/platform-browser'; | import { DomSanitizer } from '@angular/platform-browser'; | ||||||
| import { TranslateService } from '@ngx-translate/core'; | import { TranslateService } from '@ngx-translate/core'; | ||||||
| @ -1139,41 +1139,36 @@ export class CoreDomUtilsProvider { | |||||||
|      * @return Promise resolved with the alert modal. |      * @return Promise resolved with the alert modal. | ||||||
|      */ |      */ | ||||||
|     async showAlert(title: string, message: string, buttonText?: string, autocloseTime?: number): Promise<CoreAlert> { |     async showAlert(title: string, message: string, buttonText?: string, autocloseTime?: number): Promise<CoreAlert> { | ||||||
|         const buttons = [buttonText || this.translate.instant('core.ok')]; |         return this.showAlertWithOptions({ | ||||||
| 
 |             title: title, | ||||||
|         return this.showAlertWithButtons(title, message, buttons, autocloseTime); |             message, | ||||||
|  |             buttons: [buttonText || this.translate.instant('core.ok')] | ||||||
|  |         }, autocloseTime); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Show an alert modal with some buttons. |      * General show an alert modal. | ||||||
|      * |      * | ||||||
|      * @param title Title to show. |      * @param options Alert options to pass to the alert. | ||||||
|      * @param message Message to show. |  | ||||||
|      * @param buttons Buttons objects or texts. |  | ||||||
|      * @param autocloseTime Number of milliseconds to wait to close the modal. If not defined, modal won't be closed. |      * @param autocloseTime Number of milliseconds to wait to close the modal. If not defined, modal won't be closed. | ||||||
|      * @return Promise resolved with the alert modal. |      * @return Promise resolved with the alert modal. | ||||||
|      */ |      */ | ||||||
|     async showAlertWithButtons(title: string, message: string, buttons: (string | AlertButton)[], autocloseTime?: number): |     async showAlertWithOptions(options: AlertOptions = {}, autocloseTime?: number): Promise<CoreAlert> { | ||||||
|             Promise<CoreAlert> { |         const hasHTMLTags = this.textUtils.hasHTMLTags(options.message || ''); | ||||||
|         const hasHTMLTags = this.textUtils.hasHTMLTags(message); |  | ||||||
| 
 | 
 | ||||||
|         if (hasHTMLTags) { |         if (hasHTMLTags) { | ||||||
|             // Format the text.
 |             // Format the text.
 | ||||||
|             message = await this.textUtils.formatText(message); |             options.message = await this.textUtils.formatText(options.message); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const alertId = <string> Md5.hashAsciiStr((title || '') + '#' + (message || '')); |         const alertId = <string> Md5.hashAsciiStr((options.title || '') + '#' + (options.message || '')); | ||||||
| 
 | 
 | ||||||
|         if (this.displayedAlerts[alertId]) { |         if (this.displayedAlerts[alertId]) { | ||||||
|             // There's already an alert with the same message and title. Return it.
 |             // There's already an alert with the same message and title. Return it.
 | ||||||
|             return this.displayedAlerts[alertId]; |             return this.displayedAlerts[alertId]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const alert: CoreAlert = <any> this.alertCtrl.create({ |         const alert: CoreAlert = <any> this.alertCtrl.create(options); | ||||||
|             title: title, |  | ||||||
|             message: message, |  | ||||||
|             buttons: buttons, |  | ||||||
|         }); |  | ||||||
| 
 | 
 | ||||||
|         alert.present().then(() => { |         alert.present().then(() => { | ||||||
|             if (hasHTMLTags) { |             if (hasHTMLTags) { | ||||||
| @ -1202,8 +1197,18 @@ export class CoreDomUtilsProvider { | |||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
|         if (autocloseTime > 0) { |         if (autocloseTime > 0) { | ||||||
|             setTimeout(() => { |             setTimeout(async () => { | ||||||
|                 alert.dismiss(); |                 await alert.dismiss(); | ||||||
|  | 
 | ||||||
|  |                 if (options.buttons) { | ||||||
|  |                     // Execute dismiss function if any.
 | ||||||
|  |                     const cancelButton = <AlertButton> options.buttons.find((button) => { | ||||||
|  |                         return typeof button != 'string' && typeof button.role != 'undefined' && | ||||||
|  |                             typeof button.handler != 'undefined' && button.role == 'cancel'; | ||||||
|  |                     }); | ||||||
|  |                     cancelButton && cancelButton.handler(null); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|             }, autocloseTime); |             }, autocloseTime); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -1250,26 +1255,12 @@ export class CoreDomUtilsProvider { | |||||||
|      * @param options More options. See https://ionicframework.com/docs/v3/api/components/alert/AlertController/
 |      * @param options More options. See https://ionicframework.com/docs/v3/api/components/alert/AlertController/
 | ||||||
|      * @return Promise resolved if the user confirms and rejected with a canceled error if he cancels. |      * @return 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<any> { |     showConfirm(message: string, title?: string, okText?: string, cancelText?: string, options: AlertOptions = {}): Promise<any> { | ||||||
|         return new Promise<void>((resolve, reject): void => { |         return new Promise<void>((resolve, reject): void => { | ||||||
|             const hasHTMLTags = this.textUtils.hasHTMLTags(message); |  | ||||||
|             let promise; |  | ||||||
| 
 | 
 | ||||||
|             if (hasHTMLTags) { |  | ||||||
|                 // Format the text.
 |  | ||||||
|                 promise = this.textUtils.formatText(message); |  | ||||||
|             } else { |  | ||||||
|                 promise = Promise.resolve(message); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             promise.then((message) => { |  | ||||||
|                 options = options || {}; |  | ||||||
| 
 |  | ||||||
|                 options.message = message; |  | ||||||
|             options.title = title; |             options.title = title; | ||||||
|                 if (!title) { |             options.message = message; | ||||||
|                     options.cssClass = 'core-nohead'; | 
 | ||||||
|                 } |  | ||||||
|             options.buttons = [ |             options.buttons = [ | ||||||
|                 { |                 { | ||||||
|                     text: cancelText || this.translate.instant('core.cancel'), |                     text: cancelText || this.translate.instant('core.cancel'), | ||||||
| @ -1286,16 +1277,11 @@ export class CoreDomUtilsProvider { | |||||||
|                 } |                 } | ||||||
|             ]; |             ]; | ||||||
| 
 | 
 | ||||||
|                 const alert = this.alertCtrl.create(options); |             if (!title) { | ||||||
| 
 |                 options.cssClass = 'core-nohead'; | ||||||
|                 alert.present().then(() => { |  | ||||||
|                     if (hasHTMLTags) { |  | ||||||
|                         // Treat all anchors so they don't override the app.
 |  | ||||||
|                         const alertMessageEl: HTMLElement = alert.pageRef().nativeElement.querySelector('.alert-message'); |  | ||||||
|                         this.treatAnchors(alertMessageEl); |  | ||||||
|             } |             } | ||||||
|                 }); | 
 | ||||||
|             }); |             this.showAlertWithOptions(options, 0); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -1414,28 +1400,21 @@ export class CoreDomUtilsProvider { | |||||||
|      * @param title Modal title. |      * @param title Modal title. | ||||||
|      * @param placeholder Placeholder of the input element. By default, "Password". |      * @param placeholder Placeholder of the input element. By default, "Password". | ||||||
|      * @param type Type of the input element. By default, password. |      * @param type Type of the input element. By default, password. | ||||||
|  |      * @param options More options to pass to the alert. | ||||||
|      * @return Promise resolved with the input data if the user clicks OK, rejected if cancels. |      * @return Promise resolved with the input data if the user clicks OK, rejected if cancels. | ||||||
|      */ |      */ | ||||||
|     showPrompt(message: string, title?: string, placeholder?: string, type: string = 'password'): Promise<any> { |     showPrompt(message: string, title?: string, placeholder?: string, type: string = 'password'): Promise<any> { | ||||||
|         return new Promise((resolve, reject): void => { |         return new Promise((resolve, reject): any => { | ||||||
|             const hasHTMLTags = this.textUtils.hasHTMLTags(message); |             placeholder = typeof placeholder == 'undefined' || placeholder == null ? | ||||||
|             let promise; |                 this.translate.instant('core.login.password') : placeholder; | ||||||
| 
 | 
 | ||||||
|             if (hasHTMLTags) { |             const options: AlertOptions = { | ||||||
|                 // Format the text.
 |                 title, | ||||||
|                 promise = this.textUtils.formatText(message); |                 message, | ||||||
|             } else { |  | ||||||
|                 promise = Promise.resolve(message); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             promise.then((message) => { |  | ||||||
|                 const alert = this.alertCtrl.create({ |  | ||||||
|                     message: message, |  | ||||||
|                     title: title, |  | ||||||
|                 inputs: [ |                 inputs: [ | ||||||
|                     { |                     { | ||||||
|                         name: 'promptinput', |                         name: 'promptinput', | ||||||
|                             placeholder: placeholder || this.translate.instant('core.login.password'), |                         placeholder: placeholder, | ||||||
|                         type: type |                         type: type | ||||||
|                     } |                     } | ||||||
|                 ], |                 ], | ||||||
| @ -1453,18 +1432,33 @@ export class CoreDomUtilsProvider { | |||||||
|                             resolve(data.promptinput); |                             resolve(data.promptinput); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|                     ] |                 ], | ||||||
|                 }); |             }; | ||||||
| 
 | 
 | ||||||
|                 alert.present().then(() => { |             this.showAlertWithOptions(options); | ||||||
|                     if (hasHTMLTags) { |         }); | ||||||
|                         // Treat all anchors so they don't override the app.
 |  | ||||||
|                         const alertMessageEl: HTMLElement = alert.pageRef().nativeElement.querySelector('.alert-message'); |  | ||||||
|                         this.treatAnchors(alertMessageEl); |  | ||||||
|     } |     } | ||||||
|                 }); | 
 | ||||||
|             }); |     /** | ||||||
|         }); |      * Show a prompt modal to input a textarea. | ||||||
|  |      * | ||||||
|  |      * @param title Modal title. | ||||||
|  |      * @param message Modal message. | ||||||
|  |      * @param buttons Buttons to pass to the modal. | ||||||
|  |      * @param placeholder Placeholder of the input element if any. | ||||||
|  |      * @return Promise resolved when modal presented. | ||||||
|  |      */ | ||||||
|  |     showTextareaPrompt(title: string, message: string, buttons: (string | AlertButton)[], placeholder?: string): Promise<any> { | ||||||
|  |         const params = { | ||||||
|  |             title: title, | ||||||
|  |             message: message, | ||||||
|  |             placeholder: placeholder, | ||||||
|  |             buttons: buttons, | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         const modal = this.modalCtrl.create('CoreViewerTextAreaPage', params, { cssClass: 'core-modal-prompt' }); | ||||||
|  | 
 | ||||||
|  |         return modal.present(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user