From ec19082f7bb8f0a9956e71a7de4d9e3bce6fb9fd Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 29 Apr 2020 13:52:07 +0200 Subject: [PATCH] MOBILE-2995 qr: Add copy to clipboard button in QR text modal --- scripts/langindex.json | 3 + .../mod/assign/components/index/index.ts | 11 ++- .../components/submission/submission.ts | 6 +- .../feedback/comments/component/comments.ts | 10 ++- .../onlinetext/component/onlinetext.ts | 10 ++- src/assets/lang/en.json | 1 + .../navigation-bar/navigation-bar.ts | 10 ++- .../course/classes/main-resource-component.ts | 10 ++- .../unsupported-module/unsupported-module.ts | 8 ++- .../login/pages/email-signup/email-signup.ts | 2 +- src/core/mainmenu/pages/more/more.ts | 4 +- src/core/question/providers/helper.ts | 10 ++- .../components/module-index/module-index.ts | 10 ++- src/core/viewer/pages/text/text.html | 6 ++ src/core/viewer/pages/text/text.scss | 5 ++ src/core/viewer/pages/text/text.ts | 10 +++ src/directives/format-text.ts | 10 ++- src/lang/en.json | 1 + src/providers/utils/text.ts | 72 ++++++++++++++----- 19 files changed, 159 insertions(+), 40 deletions(-) create mode 100644 src/core/viewer/pages/text/text.scss diff --git a/scripts/langindex.json b/scripts/langindex.json index 19eabe1cf..bb5317983 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -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", diff --git a/src/addon/mod/assign/components/index/index.ts b/src/addon/mod/assign/components/index/index.ts index b392abef3..8d8fb9985 100644 --- a/src/addon/mod/assign/components/index/index.ts +++ b/src/addon/mod/assign/components/index/index.ts @@ -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, + }); } } diff --git a/src/addon/mod/assign/components/submission/submission.ts b/src/addon/mod/assign/components/submission/submission.ts index 9c231cabf..6bc9c7282 100644 --- a/src/addon/mod/assign/components/submission/submission.ts +++ b/src/addon/mod/assign/components/submission/submission.ts @@ -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, + }); } } diff --git a/src/addon/mod/assign/feedback/comments/component/comments.ts b/src/addon/mod/assign/feedback/comments/component/comments.ts index 27eb0baa1..1207e8f33 100644 --- a/src/addon/mod/assign/feedback/comments/component/comments.ts +++ b/src/addon/mod/assign/feedback/comments/component/comments.ts @@ -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) { diff --git a/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts b/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts index a788de667..ccfb0d3cd 100644 --- a/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts +++ b/src/addon/mod/assign/submission/onlinetext/component/onlinetext.ts @@ -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 { diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 7e4902eba..7fd738ba5 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -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.", diff --git a/src/components/navigation-bar/navigation-bar.ts b/src/components/navigation-bar/navigation-bar.ts index c19aad5ac..5eb878cb2 100644 --- a/src/components/navigation-bar/navigation-bar.ts +++ b/src/components/navigation-bar/navigation-bar.ts @@ -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, + }); } } diff --git a/src/core/course/classes/main-resource-component.ts b/src/core/course/classes/main-resource-component.ts index b84b2964e..0a333639b 100644 --- a/src/core/course/classes/main-resource-component.ts +++ b/src/core/course/classes/main-resource-component.ts @@ -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, + }); } /** diff --git a/src/core/course/pages/unsupported-module/unsupported-module.ts b/src/core/course/pages/unsupported-module/unsupported-module.ts index a28a2dde6..e63edc461 100644 --- a/src/core/course/pages/unsupported-module/unsupported-module.ts +++ b/src/core/course/pages/unsupported-module/unsupported-module.ts @@ -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, + }); } } diff --git a/src/core/login/pages/email-signup/email-signup.ts b/src/core/login/pages/email-signup/email-signup.ts index 62121f94b..fc0eb808d 100644 --- a/src/core/login/pages/email-signup/email-signup.ts +++ b/src/core/login/pages/email-signup/email-signup.ts @@ -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); } /** diff --git a/src/core/mainmenu/pages/more/more.ts b/src/core/mainmenu/pages/more/more.ts index f583edc2d..cca0add21 100644 --- a/src/core/mainmenu/pages/more/more.ts +++ b/src/core/mainmenu/pages/more/more.ts @@ -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, + }); } } }); diff --git a/src/core/question/providers/helper.ts b/src/core/question/providers/helper.ts index 7623ea747..378c1a2cb 100644 --- a/src/core/question/providers/helper.ts +++ b/src/core/question/providers/helper.ts @@ -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, + }); }); } }); diff --git a/src/core/siteplugins/components/module-index/module-index.ts b/src/core/siteplugins/components/module-index/module-index.ts index 586bd5203..94f1dcc75 100644 --- a/src/core/siteplugins/components/module-index/module-index.ts +++ b/src/core/siteplugins/components/module-index/module-index.ts @@ -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, + }); } /** diff --git a/src/core/viewer/pages/text/text.html b/src/core/viewer/pages/text/text.html index 410063705..108d28929 100644 --- a/src/core/viewer/pages/text/text.html +++ b/src/core/viewer/pages/text/text.html @@ -16,3 +16,9 @@ + + + diff --git a/src/core/viewer/pages/text/text.scss b/src/core/viewer/pages/text/text.scss new file mode 100644 index 000000000..4377e35e3 --- /dev/null +++ b/src/core/viewer/pages/text/text.scss @@ -0,0 +1,5 @@ +ion-app.app-root page-core-viewer-text { + ion-footer { + padding: 6px; + } +} diff --git a/src/core/viewer/pages/text/text.ts b/src/core/viewer/pages/text/text.ts index 6c8c1b6f8..935978391 100644 --- a/src/core/viewer/pages/text/text.ts +++ b/src/core/viewer/pages/text/text.ts @@ -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); + } } diff --git a/src/directives/format-text.ts b/src/directives/format-text.ts index fdec21043..f5c9f8f4b 100644 --- a/src/directives/format-text.ts +++ b/src/directives/format-text.ts @@ -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, + }); } } diff --git a/src/lang/en.json b/src/lang/en.json index cc4d99e42..8d279f23c 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -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.", diff --git a/src/providers/utils/text.ts b/src/providers/utils/text.ts index 3cac7f846..5ba186d9b 100644 --- a/src/providers/utils/text.ts +++ b/src/providers/utils/text.ts @@ -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) {}