forked from EVOgeek/Vmeda.Online
		
	
						commit
						3e6eeb88f8
					
				| @ -317,6 +317,10 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy { | ||||
|             // Clear temporary data from plugins.
 | ||||
|             await this.assignHelper.clearSubmissionPluginTmpData(this.assign, this.userSubmission, inputData); | ||||
| 
 | ||||
|             if (sent) { | ||||
|                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'assign' }); | ||||
|             } | ||||
| 
 | ||||
|             // Submission saved, trigger events.
 | ||||
|             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. | ||||
|      */ | ||||
|     ionViewWillLeave(): void { | ||||
|         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'chat' }); | ||||
|         this.stopPolling(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| 
 | ||||
| import { Component, Optional, Injector } from '@angular/core'; | ||||
| import { Content } from 'ionic-angular'; | ||||
| import { CoreEvents, CoreEventsProvider } from '@providers/events'; | ||||
| import { CoreTimeUtilsProvider } from '@providers/utils/time'; | ||||
| import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; | ||||
| import { AddonModChoiceProvider, AddonModChoiceChoice, AddonModChoiceOption, AddonModChoiceResult } from '../../providers/choice'; | ||||
| @ -51,9 +52,14 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo | ||||
|     protected hasAnsweredOnline = false; | ||||
|     protected now: number; | ||||
| 
 | ||||
|     constructor(injector: Injector, private choiceProvider: AddonModChoiceProvider, @Optional() content: Content, | ||||
|             private choiceOffline: AddonModChoiceOfflineProvider, private choiceSync: AddonModChoiceSyncProvider, | ||||
|             private timeUtils: CoreTimeUtilsProvider) { | ||||
|     constructor( | ||||
|             injector: Injector, | ||||
|             protected choiceProvider: AddonModChoiceProvider, | ||||
|             @Optional() content: Content, | ||||
|             protected choiceOffline: AddonModChoiceOfflineProvider, | ||||
|             protected choiceSync: AddonModChoiceSyncProvider, | ||||
|             protected timeUtils: CoreTimeUtilsProvider, | ||||
|             ) { | ||||
|         super(injector, content); | ||||
|     } | ||||
| 
 | ||||
| @ -359,6 +365,10 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo | ||||
|                 this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata); | ||||
|                 this.domUtils.scrollToTop(this.content); | ||||
| 
 | ||||
|                 if (online) { | ||||
|                     CoreEvents.instance.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: this.moduleName }); | ||||
|                 } | ||||
| 
 | ||||
|                 return this.dataUpdated(online); | ||||
|             }).catch((message) => { | ||||
|                 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); | ||||
| 
 | ||||
|                     if (result.sent) { | ||||
|                         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'data' }); | ||||
|                     } | ||||
| 
 | ||||
|                     const promises = []; | ||||
| 
 | ||||
|                     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.invalidateResumePageData(this.feedback.id)); | ||||
| 
 | ||||
|                     this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'feedback' }); | ||||
| 
 | ||||
|                     return Promise.all(promises).then(() => { | ||||
|                         return this.fetchAccessData(); | ||||
|                     }); | ||||
|  | ||||
| @ -473,6 +473,8 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { | ||||
|             if (discussionIds) { | ||||
|                 // Data sent to server, delete stored files (if any).
 | ||||
|                 this.forumHelper.deleteNewDiscussionStoredFiles(this.forumId, discTimecreated); | ||||
| 
 | ||||
|                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'forum' }); | ||||
|             } | ||||
| 
 | ||||
|             if (discussionIds && discussionIds.length < groupIds.length) { | ||||
|  | ||||
| @ -246,6 +246,7 @@ export class AddonModGlossaryEditPage implements OnInit { | ||||
|             if (entryId) { | ||||
|                 // Data sent to server, delete stored files (if any).
 | ||||
|                 this.glossaryHelper.deleteStoredFiles(this.glossary.id, this.entry.concept, timecreated); | ||||
|                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'glossary' }); | ||||
|             } | ||||
| 
 | ||||
|             const data = { | ||||
|  | ||||
| @ -18,7 +18,6 @@ import { IonicPage, NavParams, Content, PopoverController, ModalController, Moda | ||||
| import { TranslateService } from '@ngx-translate/core'; | ||||
| import { CoreAppProvider } from '@providers/app'; | ||||
| import { CoreEventsProvider } from '@providers/events'; | ||||
| import { CoreLoggerProvider } from '@providers/logger'; | ||||
| import { CoreSitesProvider } from '@providers/sites'; | ||||
| import { CoreSyncProvider } from '@providers/sync'; | ||||
| 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 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 syncProvider: CoreSyncProvider, protected domUtils: CoreDomUtilsProvider, popoverCtrl: PopoverController, | ||||
|             protected timeUtils: CoreTimeUtilsProvider, protected lessonProvider: AddonModLessonProvider, | ||||
| @ -369,6 +368,8 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy { | ||||
|             this.messages = this.messages.concat(data.messages); | ||||
|             this.processData = undefined; | ||||
| 
 | ||||
|             this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'lesson' }); | ||||
| 
 | ||||
|             // Format activity link if present.
 | ||||
|             if (this.eolData && this.eolData.activitylink) { | ||||
|                 this.eolData.activitylink.value = this.lessonHelper.formatActivityLink(this.eolData.activitylink.value); | ||||
|  | ||||
| @ -376,6 +376,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy { | ||||
|                     synced: !this.offline | ||||
|                 }, this.sitesProvider.getCurrentSiteId()); | ||||
| 
 | ||||
|                 this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'quiz' }); | ||||
| 
 | ||||
|                 // Leave the player.
 | ||||
|                 this.forceLeave = true; | ||||
|                 this.navCtrl.pop(); | ||||
|  | ||||
| @ -310,6 +310,8 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { | ||||
|      * Page will leave. | ||||
|      */ | ||||
|     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.
 | ||||
|         this.src = ''; | ||||
|     } | ||||
|  | ||||
| @ -15,6 +15,7 @@ | ||||
| import { Component, Optional, Injector } from '@angular/core'; | ||||
| import { Content } from 'ionic-angular'; | ||||
| import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component'; | ||||
| import { CoreEvents, CoreEventsProvider } from '@providers/events'; | ||||
| import { AddonModSurveyProvider, AddonModSurveySurvey } from '../../providers/survey'; | ||||
| import { AddonModSurveyHelperProvider, AddonModSurveyQuestionFormatted } from '../../providers/helper'; | ||||
| import { AddonModSurveyOfflineProvider } from '../../providers/offline'; | ||||
| @ -38,9 +39,14 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo | ||||
|     protected userId: number; | ||||
|     protected syncEventName = AddonModSurveySyncProvider.AUTO_SYNCED; | ||||
| 
 | ||||
|     constructor(injector: Injector, private surveyProvider: AddonModSurveyProvider, @Optional() content: Content, | ||||
|             private surveyHelper: AddonModSurveyHelperProvider, private surveyOffline: AddonModSurveyOfflineProvider, | ||||
|             private surveySync: AddonModSurveySyncProvider) { | ||||
|     constructor( | ||||
|             injector: Injector, | ||||
|             protected surveyProvider: AddonModSurveyProvider, | ||||
|             @Optional() content: Content, | ||||
|             protected surveyHelper: AddonModSurveyHelperProvider, | ||||
|             protected surveyOffline: AddonModSurveyOfflineProvider, | ||||
|             protected surveySync: AddonModSurveySyncProvider, | ||||
|             ) { | ||||
|         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) => { | ||||
|                 CoreEvents.instance.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: this.moduleName }); | ||||
| 
 | ||||
|                 if (online && this.isPrefetched()) { | ||||
|                     // The survey is downloaded, update the data.
 | ||||
|                     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()); | ||||
| 
 | ||||
|                     if (id > 0) { | ||||
|                         this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'wiki' }); | ||||
| 
 | ||||
|                         // Page was created, get its data and go to the page.
 | ||||
|                         this.pageId = id; | ||||
| 
 | ||||
|  | ||||
| @ -388,6 +388,8 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy { | ||||
|                 data['submissionId'] = newSubmissionId; | ||||
|             } | ||||
| 
 | ||||
|             this.eventsProvider.trigger(CoreEventsProvider.ACTIVITY_DATA_SENT, { module: 'workshop' }); | ||||
| 
 | ||||
|             const promise = newSubmissionId ? this.workshopProvider.invalidateSubmissionData(this.workshopId, newSubmissionId) : | ||||
|                 Promise.resolve(); | ||||
| 
 | ||||
|  | ||||
| @ -94,5 +94,12 @@ | ||||
|     "statusbarlighttextremotetheme": true, | ||||
|     "enableanalytics": false, | ||||
|     "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 { | ||||
|         // Show some instructions first.
 | ||||
|         this.domUtils.showAlertWithButtons( | ||||
|             this.translate.instant('core.login.faqwhereisqrcode'), | ||||
|             this.translate.instant('core.login.faqwhereisqrcodeanswer', {$image: CoreLoginHelperProvider.FAQ_QRCODE_IMAGE_HTML}), | ||||
|             [ | ||||
|         this.domUtils.showAlertWithOptions({ | ||||
|             title: this.translate.instant('core.login.faqwhereisqrcode'), | ||||
|             message: this.translate.instant('core.login.faqwhereisqrcodeanswer', | ||||
|                 {$image: CoreLoginHelperProvider.FAQ_QRCODE_IMAGE_HTML}), | ||||
|             buttons: [ | ||||
|                 { | ||||
|                     text: this.translate.instant('core.cancel'), | ||||
|                     role: 'cancel' | ||||
| @ -383,8 +388,8 @@ export class CoreLoginSitePage { | ||||
|                         this.scanQR(); | ||||
|                     } | ||||
|                 }, | ||||
|             ] | ||||
|         ); | ||||
|             ], | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; | ||||
| import { Location } from '@angular/common'; | ||||
| import { Platform, AlertController, NavController, NavOptions } from 'ionic-angular'; | ||||
| import { TranslateService } from '@ngx-translate/core'; | ||||
| import { CoreAppProvider } from '@providers/app'; | ||||
| import { CoreAppProvider, CoreStoreConfig } from '@providers/app'; | ||||
| import { CoreConfigProvider } from '@providers/config'; | ||||
| import { CoreEventsProvider } from '@providers/events'; | ||||
| import { CoreInitDelegate } from '@providers/init'; | ||||
| @ -1180,13 +1180,7 @@ export class CoreLoginHelperProvider { | ||||
|      * @param message The warning message. | ||||
|      */ | ||||
|     protected showWorkplaceNoticeModal(message: string): void { | ||||
|         let link; | ||||
| 
 | ||||
|         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'; | ||||
|         } | ||||
|         const link = this.appProvider.getAppStoreUrl({android: 'com.moodle.workplace', ios: 'id1470929705' }); | ||||
| 
 | ||||
|         this.showDownloadAppNoticeModal(message, link); | ||||
|     } | ||||
| @ -1197,20 +1191,12 @@ export class CoreLoginHelperProvider { | ||||
|      * @param message The warning message. | ||||
|      */ | ||||
|     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()) { | ||||
|             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'; | ||||
|         } | ||||
|         const link = this.appProvider.getAppStoreUrl(storesConfig); | ||||
| 
 | ||||
|         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; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * 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. | ||||
|  */ | ||||
| @ -255,6 +300,44 @@ export class CoreAppProvider { | ||||
|         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. | ||||
|      * | ||||
|  | ||||
| @ -67,6 +67,7 @@ export class CoreEventsProvider { | ||||
|     static WS_CACHE_INVALIDATED = 'ws_cache_invalidated'; | ||||
|     static SITE_STORAGE_DELETED = 'site_storage_deleted'; | ||||
|     static FORM_ACTION = 'form_action'; | ||||
|     static ACTIVITY_DATA_SENT = 'activity_data_sent'; | ||||
| 
 | ||||
|     protected logger; | ||||
|     protected observables: { [s: string]: Subject<any> } = {}; | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| import { Injectable, Injector } from '@angular/core'; | ||||
| import { HttpClient } from '@angular/common/http'; | ||||
| import { TranslateService } from '@ngx-translate/core'; | ||||
| import { CoreAppProvider, CoreAppSchema } from './app'; | ||||
| import { CoreAppProvider, CoreAppSchema, CoreStoreConfig } from './app'; | ||||
| import { CoreEventsProvider } from './events'; | ||||
| import { CoreLoggerProvider } from './logger'; | ||||
| import { CoreSitesFactoryProvider } from './sites-factory'; | ||||
| @ -1001,19 +1001,15 @@ export class CoreSitesProvider { | ||||
|                 appVersion = this.convertVersionName(CoreConfigConstants.versionname); | ||||
| 
 | ||||
|             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) { | ||||
|                     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/'; | ||||
|                 } | ||||
|                 const downloadUrl = this.appProvider.getAppStoreUrl(storesConfig); | ||||
| 
 | ||||
|                 siteId = siteId || this.getCurrentSiteId(); | ||||
| 
 | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
| import { Injectable, SimpleChange, ElementRef } from '@angular/core'; | ||||
| import { | ||||
|     LoadingController, Loading, ToastController, Toast, AlertController, Alert, Platform, Content, PopoverController, | ||||
|     ModalController, AlertButton | ||||
|     ModalController, AlertButton, AlertOptions | ||||
| } from 'ionic-angular'; | ||||
| import { DomSanitizer } from '@angular/platform-browser'; | ||||
| import { TranslateService } from '@ngx-translate/core'; | ||||
| @ -1139,41 +1139,36 @@ export class CoreDomUtilsProvider { | ||||
|      * @return Promise resolved with the alert modal. | ||||
|      */ | ||||
|     async showAlert(title: string, message: string, buttonText?: string, autocloseTime?: number): Promise<CoreAlert> { | ||||
|         const buttons = [buttonText || this.translate.instant('core.ok')]; | ||||
| 
 | ||||
|         return this.showAlertWithButtons(title, message, buttons, autocloseTime); | ||||
|         return this.showAlertWithOptions({ | ||||
|             title: title, | ||||
|             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 message Message to show. | ||||
|      * @param buttons Buttons objects or texts. | ||||
|      * @param options Alert options to pass to the alert. | ||||
|      * @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. | ||||
|      */ | ||||
|     async showAlertWithButtons(title: string, message: string, buttons: (string | AlertButton)[], autocloseTime?: number): | ||||
|             Promise<CoreAlert> { | ||||
|         const hasHTMLTags = this.textUtils.hasHTMLTags(message); | ||||
|     async showAlertWithOptions(options: AlertOptions = {}, autocloseTime?: number): Promise<CoreAlert> { | ||||
|         const hasHTMLTags = this.textUtils.hasHTMLTags(options.message || ''); | ||||
| 
 | ||||
|         if (hasHTMLTags) { | ||||
|             // 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]) { | ||||
|             // There's already an alert with the same message and title. Return it.
 | ||||
|             return this.displayedAlerts[alertId]; | ||||
|         } | ||||
| 
 | ||||
|         const alert: CoreAlert = <any> this.alertCtrl.create({ | ||||
|             title: title, | ||||
|             message: message, | ||||
|             buttons: buttons, | ||||
|         }); | ||||
|         const alert: CoreAlert = <any> this.alertCtrl.create(options); | ||||
| 
 | ||||
|         alert.present().then(() => { | ||||
|             if (hasHTMLTags) { | ||||
| @ -1202,8 +1197,18 @@ export class CoreDomUtilsProvider { | ||||
|         }); | ||||
| 
 | ||||
|         if (autocloseTime > 0) { | ||||
|             setTimeout(() => { | ||||
|                 alert.dismiss(); | ||||
|             setTimeout(async () => { | ||||
|                 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); | ||||
|         } | ||||
| 
 | ||||
| @ -1250,26 +1255,12 @@ export class CoreDomUtilsProvider { | ||||
|      * @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. | ||||
|      */ | ||||
|     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 => { | ||||
|             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; | ||||
|                 if (!title) { | ||||
|                     options.cssClass = 'core-nohead'; | ||||
|                 } | ||||
|             options.message = message; | ||||
| 
 | ||||
|             options.buttons = [ | ||||
|                 { | ||||
|                     text: cancelText || this.translate.instant('core.cancel'), | ||||
| @ -1286,16 +1277,11 @@ export class CoreDomUtilsProvider { | ||||
|                 } | ||||
|             ]; | ||||
| 
 | ||||
|                 const alert = this.alertCtrl.create(options); | ||||
| 
 | ||||
|                 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); | ||||
|             if (!title) { | ||||
|                 options.cssClass = 'core-nohead'; | ||||
|             } | ||||
|                 }); | ||||
|             }); | ||||
| 
 | ||||
|             this.showAlertWithOptions(options, 0); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -1414,28 +1400,21 @@ export class CoreDomUtilsProvider { | ||||
|      * @param title Modal title. | ||||
|      * @param placeholder Placeholder 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. | ||||
|      */ | ||||
|     showPrompt(message: string, title?: string, placeholder?: string, type: string = 'password'): Promise<any> { | ||||
|         return new Promise((resolve, reject): void => { | ||||
|             const hasHTMLTags = this.textUtils.hasHTMLTags(message); | ||||
|             let promise; | ||||
|         return new Promise((resolve, reject): any => { | ||||
|             placeholder = typeof placeholder == 'undefined' || placeholder == null ? | ||||
|                 this.translate.instant('core.login.password') : placeholder; | ||||
| 
 | ||||
|             if (hasHTMLTags) { | ||||
|                 // Format the text.
 | ||||
|                 promise = this.textUtils.formatText(message); | ||||
|             } else { | ||||
|                 promise = Promise.resolve(message); | ||||
|             } | ||||
| 
 | ||||
|             promise.then((message) => { | ||||
|                 const alert = this.alertCtrl.create({ | ||||
|                     message: message, | ||||
|                     title: title, | ||||
|             const options: AlertOptions = { | ||||
|                 title, | ||||
|                 message, | ||||
|                 inputs: [ | ||||
|                     { | ||||
|                         name: 'promptinput', | ||||
|                             placeholder: placeholder || this.translate.instant('core.login.password'), | ||||
|                         placeholder: placeholder, | ||||
|                         type: type | ||||
|                     } | ||||
|                 ], | ||||
| @ -1453,18 +1432,33 @@ export class CoreDomUtilsProvider { | ||||
|                             resolve(data.promptinput); | ||||
|                         } | ||||
|                     } | ||||
|                     ] | ||||
|                 }); | ||||
|                 ], | ||||
|             }; | ||||
| 
 | ||||
|                 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); | ||||
|         }); | ||||
|     } | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
| 
 | ||||
|     /** | ||||
|      * 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