MOBILE-2995 qr: Add copy to clipboard button in QR text modal
This commit is contained in:
		
							parent
							
								
									d79f48e3fb
								
							
						
					
					
						commit
						ec19082f7b
					
				| @ -1387,6 +1387,7 @@ | ||||
|   "core.contentlinks.errorredirectothersite": "local_moodlemobileapp", | ||||
|   "core.continue": "moodle", | ||||
|   "core.copiedtoclipboard": "local_moodlemobileapp", | ||||
|   "core.copytoclipboard": "local_moodlemobileapp", | ||||
|   "core.course": "moodle", | ||||
|   "core.course.activitydisabled": "local_moodlemobileapp", | ||||
|   "core.course.activitynotyetviewableremoteaddon": "local_moodlemobileapp", | ||||
| @ -1754,6 +1755,7 @@ | ||||
|   "core.login.mustconfirm": "moodle", | ||||
|   "core.login.newaccount": "moodle", | ||||
|   "core.login.notloggedin": "local_moodlemobileapp", | ||||
|   "core.login.or": "local_moodlemobileapp", | ||||
|   "core.login.password": "moodle", | ||||
|   "core.login.passwordforgotten": "moodle", | ||||
|   "core.login.passwordforgotteninstructions2": "moodle", | ||||
| @ -1860,6 +1862,7 @@ | ||||
|   "core.online": "message", | ||||
|   "core.openfullimage": "local_moodlemobileapp", | ||||
|   "core.openinbrowser": "local_moodlemobileapp", | ||||
|   "core.openmodinbrowser": "local_moodlemobileapp", | ||||
|   "core.othergroups": "group", | ||||
|   "core.pagea": "moodle", | ||||
|   "core.parentlanguage": "langconfig", | ||||
|  | ||||
| @ -133,8 +133,15 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo | ||||
|         ev && ev.stopPropagation(); | ||||
| 
 | ||||
|         if (this.assign && (this.description || this.assign.introattachments)) { | ||||
|             this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, | ||||
|                     this.module.id, this.assign.introattachments, true, 'module', this.module.id, this.courseId); | ||||
|             this.textUtils.viewText(this.translate.instant('core.description'), this.description, { | ||||
|                 component: this.component, | ||||
|                 componentId: this.module.id, | ||||
|                 files: this.assign.introattachments, | ||||
|                 filter: true, | ||||
|                 contextLevel: 'module', | ||||
|                 instanceId: this.module.id, | ||||
|                 courseId: this.courseId, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -678,8 +678,10 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy { | ||||
|      */ | ||||
|     showAdvancedGrade(): void { | ||||
|         if (this.feedback && this.feedback.advancedgrade) { | ||||
|             this.textUtils.expandText(this.translate.instant('core.grades.grade'), this.feedback.gradefordisplay, | ||||
|                     AddonModAssignProvider.COMPONENT, this.moduleId); | ||||
|             this.textUtils.viewText(this.translate.instant('core.grades.grade'), this.feedback.gradefordisplay, { | ||||
|                 component: AddonModAssignProvider.COMPONENT, | ||||
|                 componentId: this.moduleId, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -65,8 +65,14 @@ export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedb | ||||
| 
 | ||||
|                     if (this.text) { | ||||
|                         // Open a new state with the text.
 | ||||
|                         this.textUtils.expandText(this.plugin.name, this.text, this.component, this.assign.cmid, undefined, true, | ||||
|                                 'module', this.assign.cmid, this.assign.course); | ||||
|                         this.textUtils.viewText(this.plugin.name, this.text, { | ||||
|                             component: this.component, | ||||
|                             componentId: this.assign.cmid, | ||||
|                             filter: true, | ||||
|                             contextLevel: 'module', | ||||
|                             instanceId: this.assign.cmid, | ||||
|                             courseId: this.assign.course, | ||||
|                         }); | ||||
|                     } | ||||
|                 }); | ||||
|             } else if (this.edit) { | ||||
|  | ||||
| @ -83,8 +83,14 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS | ||||
| 
 | ||||
|                     if (text) { | ||||
|                         // Open a new state with the interpolated contents.
 | ||||
|                         this.textUtils.expandText(this.plugin.name, text, this.component, this.assign.cmid, undefined, true, | ||||
|                                 'module', this.assign.cmid, this.assign.course); | ||||
|                         this.textUtils.viewText(this.plugin.name, text, { | ||||
|                             component: this.component, | ||||
|                             componentId: this.assign.cmid, | ||||
|                             filter: true, | ||||
|                             contextLevel: 'module', | ||||
|                             instanceId: this.assign.cmid, | ||||
|                             courseId: this.assign.course, | ||||
|                         }); | ||||
|                     } | ||||
|                 }); | ||||
|             } else { | ||||
|  | ||||
| @ -1387,6 +1387,7 @@ | ||||
|     "core.contentlinks.errorredirectothersite": "The redirect URL cannot point to a different site.", | ||||
|     "core.continue": "Continue", | ||||
|     "core.copiedtoclipboard": "Text copied to clipboard", | ||||
|     "core.copytoclipboard": "Copy to clipboard", | ||||
|     "core.course": "Course", | ||||
|     "core.course.activitydisabled": "Your organisation has disabled this activity in the mobile app.", | ||||
|     "core.course.activitynotyetviewableremoteaddon": "Your organisation installed a plugin that is not yet supported.", | ||||
|  | ||||
| @ -47,7 +47,13 @@ export class CoreNavigationBarComponent { | ||||
|     } | ||||
| 
 | ||||
|     showInfo(): void { | ||||
|         this.textUtils.expandText(this.title, this.info, this.component, this.componentId, [], true, this.contextLevel, | ||||
|                 this.contextInstanceId, this.courseId); | ||||
|         this.textUtils.viewText(this.title, this.info, { | ||||
|             component: this.component, | ||||
|             componentId: this.componentId, | ||||
|             filter: true, | ||||
|             contextLevel: this.contextLevel, | ||||
|             instanceId: this.contextInstanceId, | ||||
|             courseId: this.courseId, | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -265,8 +265,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, | ||||
|      * Expand the description. | ||||
|      */ | ||||
|     expandDescription(): void { | ||||
|         this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id, | ||||
|                 [], true, 'module', this.module.id, this.courseId); | ||||
|         this.textUtils.viewText(this.translate.instant('core.description'), this.description, { | ||||
|             component: this.component, | ||||
|             componentId: this.module.id, | ||||
|             filter: true, | ||||
|             contextLevel: 'module', | ||||
|             instanceId: this.module.id, | ||||
|             courseId: this.courseId, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -38,7 +38,11 @@ export class CoreCourseUnsupportedModulePage { | ||||
|      * Expand the description. | ||||
|      */ | ||||
|     expandDescription(): void { | ||||
|         this.textUtils.expandText(this.translate.instant('core.description'), this.module.description, undefined, undefined, | ||||
|                 [], true, 'module', this.module.id, this.courseId); | ||||
|         this.textUtils.viewText(this.translate.instant('core.description'), this.module.description, { | ||||
|             filter: true, | ||||
|             contextLevel: 'module', | ||||
|             instanceId: this.module.id, | ||||
|             courseId: this.courseId, | ||||
|         }); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -317,7 +317,7 @@ export class CoreLoginEmailSignupPage { | ||||
|      * Show authentication instructions. | ||||
|      */ | ||||
|     protected showAuthInstructions(): void { | ||||
|         this.textUtils.expandText(this.translate.instant('core.login.instructions'), this.authInstructions); | ||||
|         this.textUtils.viewText(this.translate.instant('core.login.instructions'), this.authInstructions); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -192,7 +192,9 @@ export class CoreMainMenuMorePage implements OnDestroy { | ||||
|                     }); | ||||
|                 } else { | ||||
|                     // It's not a URL, open it in a modal so the user can see it and copy it.
 | ||||
|                     this.textUtils.expandText(this.translate.instant('core.qrscanner'), text); | ||||
|                     this.textUtils.viewText(this.translate.instant('core.qrscanner'), text, { | ||||
|                         displayCopyButton: true, | ||||
|                     }); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|  | ||||
| @ -709,8 +709,14 @@ export class CoreQuestionHelperProvider { | ||||
|             if (span) { | ||||
|                 // There's a hidden feedback, show it when the icon is clicked.
 | ||||
|                 icon.addEventListener('click', (event) => { | ||||
|                     this.textUtils.expandText(title, span.innerHTML, component, componentId, [], true, contextLevel, | ||||
|                             contextInstanceId, courseId); | ||||
|                     this.textUtils.viewText(title, span.innerHTML, { | ||||
|                         component: component, | ||||
|                         componentId: componentId, | ||||
|                         filter: true, | ||||
|                         contextLevel: contextLevel, | ||||
|                         instanceId: contextInstanceId, | ||||
|                         courseId: courseId, | ||||
|                     }); | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
| @ -146,8 +146,14 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C | ||||
|      * Expand the description. | ||||
|      */ | ||||
|     expandDescription(): void { | ||||
|         this.textUtils.expandText(this.translate.instant('core.description'), this.description, this.component, this.module.id, | ||||
|                 [], true, 'module', this.module.id, this.courseId); | ||||
|         this.textUtils.viewText(this.translate.instant('core.description'), this.description, { | ||||
|             component: this.component, | ||||
|             componentId: this.module.id, | ||||
|             filter: true, | ||||
|             contextLevel: 'module', | ||||
|             instanceId: this.module.id, | ||||
|             courseId: this.courseId, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -16,3 +16,9 @@ | ||||
|         <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="componentId"></core-file> | ||||
|     </ion-card> | ||||
| </ion-content> | ||||
| <ion-footer color="light" *ngIf="displayCopyButton"> | ||||
|     <button ion-button block color="light" icon-start (click)="copyText()"> | ||||
|         <ion-icon name="copy" aria-hidden="true"></ion-icon> | ||||
|         {{ 'core.copytoclipboard' | translate }} | ||||
|     </button> | ||||
| </ion-footer> | ||||
|  | ||||
							
								
								
									
										5
									
								
								src/core/viewer/pages/text/text.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/core/viewer/pages/text/text.scss
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| ion-app.app-root page-core-viewer-text { | ||||
|     ion-footer { | ||||
|         padding: 6px; | ||||
|     } | ||||
| } | ||||
| @ -15,6 +15,7 @@ | ||||
| import { Component } from '@angular/core'; | ||||
| import { IonicPage, ViewController, NavParams } from 'ionic-angular'; | ||||
| import { CoreTextUtilsProvider } from '@providers/utils/text'; | ||||
| import { CoreUtils } from '@providers/utils/utils'; | ||||
| 
 | ||||
| /** | ||||
|  * Page to render a certain text. If opened as a modal, it will have a button to close the modal. | ||||
| @ -34,6 +35,7 @@ export class CoreViewerTextPage { | ||||
|     contextLevel: string; // The context level.
 | ||||
|     instanceId: number; // The instance ID related to the context.
 | ||||
|     courseId: number; // Course ID the text belongs to. It can be used to improve performance with filters.
 | ||||
|     displayCopyButton: boolean; // Whether to display a button to copy the contents.
 | ||||
| 
 | ||||
|     constructor(private viewCtrl: ViewController, params: NavParams, textUtils: CoreTextUtilsProvider) { | ||||
|         this.title = params.get('title'); | ||||
| @ -45,6 +47,7 @@ export class CoreViewerTextPage { | ||||
|         this.contextLevel = params.get('contextLevel'); | ||||
|         this.instanceId = params.get('instanceId'); | ||||
|         this.courseId = params.get('courseId'); | ||||
|         this.displayCopyButton = !!params.get('displayCopyButton'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -53,4 +56,11 @@ export class CoreViewerTextPage { | ||||
|     closeModal(): void { | ||||
|         this.viewCtrl.dismiss(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Copy the text to clipboard. | ||||
|      */ | ||||
|     copyText(): void { | ||||
|         CoreUtils.instance.copyToClipboard(this.content); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -307,8 +307,14 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|             // Open a new state with the contents.
 | ||||
|             const filter = typeof this.filter != 'undefined' ? this.utils.isTrueOrOne(this.filter) : undefined; | ||||
| 
 | ||||
|             this.textUtils.expandText(this.fullTitle || this.translate.instant('core.description'), this.text, | ||||
|                 this.component, this.componentId, undefined, filter, this.contextLevel, this.contextInstanceId, this.courseId); | ||||
|             this.textUtils.viewText(this.fullTitle || this.translate.instant('core.description'), this.text, { | ||||
|                 component: this.component, | ||||
|                 componentId: this.componentId, | ||||
|                 filter: filter, | ||||
|                 contextLevel: this.contextLevel, | ||||
|                 instanceId: this.contextInstanceId, | ||||
|                 courseId: this.courseId, | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -51,6 +51,7 @@ | ||||
|     "contenteditingsynced": "The content you are editing has been synced.", | ||||
|     "continue": "Continue", | ||||
|     "copiedtoclipboard": "Text copied to clipboard", | ||||
|     "copytoclipboard": "Copy to clipboard", | ||||
|     "course": "Course", | ||||
|     "coursedetails": "Course details", | ||||
|     "coursenogroups": "You are not a member of any group of this course.", | ||||
|  | ||||
| @ -441,28 +441,20 @@ export class CoreTextUtilsProvider { | ||||
|      * @param contextLevel The context level. | ||||
|      * @param instanceId The instance ID related to the context. | ||||
|      * @param courseId Course ID the text belongs to. It can be used to improve performance with filters. | ||||
|      * @deprecated since 3.8.3. Please use viewText instead. | ||||
|      */ | ||||
|     expandText(title: string, text: string, component?: string, componentId?: string | number, files?: any[], | ||||
|             filter?: boolean, contextLevel?: string, instanceId?: number, courseId?: number): void { | ||||
|         if (text.length > 0) { | ||||
|             const params: any = { | ||||
|                 title: title, | ||||
|                 content: text, | ||||
|                 component: component, | ||||
|                 componentId: componentId, | ||||
|                 files: files, | ||||
|                 filter: filter, | ||||
|                 contextLevel: contextLevel, | ||||
|                 instanceId: instanceId, | ||||
|                 courseId: courseId | ||||
|             }; | ||||
| 
 | ||||
|             // Open a modal with the contents.
 | ||||
|             params.isModal = true; | ||||
| 
 | ||||
|             const modal = this.modalCtrl.create('CoreViewerTextPage', params); | ||||
|             modal.present(); | ||||
|         } | ||||
|         return this.viewText(title, text, { | ||||
|             component, | ||||
|             componentId, | ||||
|             files, | ||||
|             filter, | ||||
|             contextLevel, | ||||
|             instanceId, | ||||
|             courseId, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -1133,6 +1125,50 @@ export class CoreTextUtilsProvider { | ||||
| 
 | ||||
|         return _unserialize((data + ''), 0)[2]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Shows a text on a new page. | ||||
|      * | ||||
|      * @param title Title of the new state. | ||||
|      * @param text Content of the text to be expanded. | ||||
|      * @param component Component to link the embedded files to. | ||||
|      * @param componentId An ID to use in conjunction with the component. | ||||
|      * @param files List of files to display along with the text. | ||||
|      * @param filter Whether the text should be filtered. | ||||
|      * @param contextLevel The context level. | ||||
|      * @param instanceId The instance ID related to the context. | ||||
|      * @param courseId Course ID the text belongs to. It can be used to improve performance with filters. | ||||
|      */ | ||||
|     viewText(title: string, text: string, options?: CoreTextUtilsViewTextOptions): void { | ||||
|         if (text.length > 0) { | ||||
|             options = options || {}; | ||||
| 
 | ||||
|             const params: any = { | ||||
|                 title: title, | ||||
|                 content: text, | ||||
|                 isModal: true, | ||||
|             }; | ||||
| 
 | ||||
|             Object.assign(params, options); | ||||
| 
 | ||||
|             const modal = this.modalCtrl.create('CoreViewerTextPage', params); | ||||
|             modal.present(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Options for viewText. | ||||
|  */ | ||||
| export type CoreTextUtilsViewTextOptions = { | ||||
|     component?: string; // Component to link the embedded files to.
 | ||||
|     componentId?: string | number; // An ID to use in conjunction with the component.
 | ||||
|     files?: any[]; // List of files to display along with the text.
 | ||||
|     filter?: boolean; // Whether the text should be filtered.
 | ||||
|     contextLevel?: string; // The context level.
 | ||||
|     instanceId?: number; // The instance ID related to the context.
 | ||||
|     courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters.
 | ||||
|     displayCopyButton?: boolean; // Whether to display a button to copy the text.
 | ||||
| }; | ||||
| 
 | ||||
| export class CoreTextUtils extends makeSingleton(CoreTextUtilsProvider) {} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user