From 56e51e9e60fcb9bb92708720bba30ab602af383b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 17 Nov 2021 11:46:37 +0100 Subject: [PATCH 1/9] MOBILE-3810 ionic: Prevent modal from opening twice --- src/core/services/utils/dom.ts | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index bc52b22fe..c23675e5c 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -71,6 +71,7 @@ export class CoreDomUtilsProvider { protected instances: WeakMap = new WeakMap(); // Store component/directive instances indexed by element. protected debugDisplay = false; // Whether to display debug messages. Store it in a variable to make it synchronous. protected displayedAlerts: Record = {}; // To prevent duplicated alerts. + protected displayedModals: Record = {}; // To prevent duplicated modals. protected activeLoadingModals: CoreIonLoadingElement[] = []; protected logger: CoreLogger; @@ -1690,26 +1691,37 @@ export class CoreDomUtilsProvider { async openModal( options: OpenModalOptions, ): Promise { - const { waitForDismissCompleted, closeOnNavigate, ...modalOptions } = options; const listenCloseEvents = closeOnNavigate ?? true; // Default to true. - const modal = await ModalController.create(modalOptions); + // TODO: Improve this if we need two modals with same component open at the same time. + const modalId = Md5.hashAsciiStr(options.component?.toString() || ''); + + const modal = this.displayedModals[modalId] + ? this.displayedModals[modalId] + : await ModalController.create(modalOptions); let navSubscription: Subscription | undefined; - if (listenCloseEvents) { - // Listen navigation events to close modals. - navSubscription = Router.events - .pipe(filter(event => event instanceof NavigationStart)) - .subscribe(async () => { - modal.dismiss(); - }); - } - await modal.present(); + if (!this.displayedModals[modalId]) { + // Store the modal and remove it when dismissed. + this.displayedModals[modalId] = modal; + + if (listenCloseEvents) { + // Listen navigation events to close modals. + navSubscription = Router.events + .pipe(filter(event => event instanceof NavigationStart)) + .subscribe(async () => { + modal.dismiss(); + }); + } + + await modal.present(); + } const result = waitForDismissCompleted ? await modal.onDidDismiss() : await modal.onWillDismiss(); navSubscription?.unsubscribe(); + delete this.displayedModals[modalId]; if (result?.data) { return result?.data; From 8a3ae5e081c0651ebf48d6b0f2fb6e6646aefa3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 16 Nov 2021 14:10:43 +0100 Subject: [PATCH 2/9] MOBILE-3810 module: Fix getIconSrc on course module handler --- .../mod/resource/services/handlers/module.ts | 28 ++++++++++++++++++- src/core/components/mod-icon/mod-icon.ts | 4 +-- .../course/services/module-delegate.ts | 8 ++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/addons/mod/resource/services/handlers/module.ts b/src/addons/mod/resource/services/handlers/module.ts index 69a3d2ce8..275ea61f7 100644 --- a/src/addons/mod/resource/services/handlers/module.ts +++ b/src/addons/mod/resource/services/handlers/module.ts @@ -15,7 +15,7 @@ import { CoreConstants } from '@/core/constants'; import { Injectable, Type } from '@angular/core'; import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; -import { CoreCourse } from '@features/course/services/course'; +import { CoreCourse, CoreCourseWSModule } from '@features/course/services/course'; import { CoreCourseModule } from '@features/course/services/course-helper'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; import { CoreCourseModulePrefetchDelegate } from '@features/course/services/module-prefetch-delegate'; @@ -226,6 +226,32 @@ export class AddonModResourceModuleHandlerService extends CoreModuleHandlerBase }; } + /** + * @inheritdoc + */ + async getIconSrc(module?: CoreCourseWSModule): Promise { + if (!module) { + return; + } + let mimetypeIcon = ''; + + if ('contentsinfo' in module && module.contentsinfo) { + // No need to use the list of files. + const mimetype = module.contentsinfo.mimetypes[0]; + if (mimetype) { + mimetypeIcon = CoreMimetypeUtils.getMimetypeIcon(mimetype); + } + + } else if (module.contents && module.contents[0]) { + const files = module.contents; + const file = files[0]; + + mimetypeIcon = CoreMimetypeUtils.getFileIcon(file.filename || ''); + } + + return await CoreCourse.getModuleIconSrc(module.modname, module.modicon, mimetypeIcon); + } + /** * @inheritdoc */ diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index eba805215..c9c6b70ac 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -15,7 +15,7 @@ import { Component, Input, OnChanges, OnInit, SimpleChange } from '@angular/core'; import { CoreCourse } from '@features/course/services/course'; -const assetsPath = 'assets/img/mod/'; +const assetsPath = 'assets/img/'; const fallbackModName = 'external-tool'; /** @@ -51,7 +51,7 @@ export class CoreModIconComponent implements OnInit, OnChanges { * @inheritdoc */ ngOnChanges(changes: { [name: string]: SimpleChange }): void { - if (changes && changes.modicon && changes.modicon.previousValue) { + if (changes && changes.modicon && changes.modicon.previousValue !== undefined) { this.setIcon(); } } diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index f967c89a5..e5f918d1f 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -80,9 +80,10 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { /** * Get the icon src for the module. * + * @param module: Module to get the icon from. * @return The icon src. */ - getIconSrc?(module: CoreCourseWSModule): Promise | string | undefined; + getIconSrc?(module?: CoreCourseWSModule): Promise | string | undefined; /** * Check if this type of module supports a certain feature. @@ -343,10 +344,11 @@ export class CoreCourseModuleDelegateService extends CoreDelegate { - const icon = await this.executeFunctionOnEnabled>(modname, 'getIconSrc'); + async getModuleIconSrc(modname: string, modicon?: string, module?: CoreCourseWSModule): Promise { + const icon = await this.executeFunctionOnEnabled>(modname, 'getIconSrc', [module]); return icon || await CoreCourse.getModuleIconSrc(modname, modicon) || ''; } From dace9898d04967d4871bde0220a44bcb3f83971f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 16 Nov 2021 12:58:46 +0100 Subject: [PATCH 3/9] MOBILE-3810 module: Add basic info to core-course-module-info --- .../index/addon-mod-assign-index.html | 67 +++++++--------- .../index/addon-mod-book-index.html | 25 +++--- .../index/addon-mod-chat-index.html | 16 ++-- .../index/addon-mod-choice-index.html | 31 ++++---- .../index/addon-mod-data-index.html | 27 +++---- .../index/addon-mod-feedback-index.html | 39 ++++------ .../index/addon-mod-folder-index.html | 17 ++-- .../mod/forum/components/index/index.html | 77 ++++++++----------- .../index/addon-mod-glossary-index.html | 30 ++++---- .../index/addon-mod-h5pactivity-index.html | 24 +++--- .../index/addon-mod-imscp-index.html | 11 ++- .../index/addon-mod-lesson-index.html | 26 +++---- .../components/index/addon-mod-lti-index.html | 17 ++-- .../index/addon-mod-page-index.html | 16 ++-- .../index/addon-mod-quiz-index.html | 62 +++++++-------- .../index/addon-mod-resource-index.html | 18 ++--- .../index/addon-mod-scorm-index.html | 26 +++---- .../index/addon-mod-survey-index.html | 45 +++++------ .../components/index/addon-mod-url-index.html | 16 ++-- .../index/addon-mod-wiki-index.html | 33 ++++---- src/addons/mod/wiki/pages/index/index.ts | 4 +- .../index/addon-mod-workshop-index.html | 40 ++++++---- .../course/classes/main-resource-component.ts | 4 +- .../module-description/module-description.ts | 4 +- .../module-info/core-course-module-info.html | 53 +++++++++---- .../module-info/course-module-info.scss | 6 +- .../components/module-info/module-info.ts | 35 ++++++++- .../core-course-unsupported-module.html | 5 +- 28 files changed, 365 insertions(+), 409 deletions(-) diff --git a/src/addons/mod/assign/components/index/addon-mod-assign-index.html b/src/addons/mod/assign/components/index/addon-mod-assign-index.html index ef0cd7d5d..1efbaa292 100644 --- a/src/addons/mod/assign/components/index/addon-mod-assign-index.html +++ b/src/addons/mod/assign/components/index/addon-mod-assign-index.html @@ -1,15 +1,14 @@ - + + [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" iconAction="fas-arrow-right"> - + @@ -31,26 +30,15 @@ - + + + + + - - - - - - - - - - - - - @@ -90,8 +78,7 @@ - + {{ 'addon.mod_assign.numberofteams' | translate }} {{ 'addon.mod_assign.numberofparticipants' | translate }} @@ -109,48 +96,48 @@ - {{ 'addon.mod_assign.numberofdraftsubmissions' | translate }} + + {{ 'addon.mod_assign.numberofdraftsubmissions' | translate }} + {{ summary.submissiondraftscount }} {{ 'addon.mod_assign.numberofdraftsubmissionscountdescription' | translate: - {count: summary.submissiondraftscount} }} + {count: summary.submissiondraftscount} }} - {{ 'addon.mod_assign.numberofsubmittedassignments' | translate }} + + {{ 'addon.mod_assign.numberofsubmittedassignments' | translate }} + {{ summary.submissionssubmittedcount }} {{ 'addon.mod_assign.numberofsubmittedassignmentscountdescription' | translate: - {count: summary.submissionssubmittedcount} }} + {count: summary.submissionssubmittedcount} }} - {{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }} + + {{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }} + {{ summary.submissionsneedgradingcount }} {{ 'addon.mod_assign.numberofsubmissionsneedgradingcountdescription' | translate: - {count: summary.submissionsneedgradingcount} }} + {count: summary.submissionsneedgradingcount} }} diff --git a/src/addons/mod/book/components/index/addon-mod-book-index.html b/src/addons/mod/book/components/index/addon-mod-book-index.html index 7be6e735b..f6f090647 100644 --- a/src/addons/mod/book/components/index/addon-mod-book-index.html +++ b/src/addons/mod/book/components/index/addon-mod-book-index.html @@ -4,12 +4,12 @@ - + - + - + - - @@ -39,9 +36,8 @@ - + - + diff --git a/src/addons/mod/chat/components/index/addon-mod-chat-index.html b/src/addons/mod/chat/components/index/addon-mod-chat-index.html index 8f1069746..93265acea 100644 --- a/src/addons/mod/chat/components/index/addon-mod-chat-index.html +++ b/src/addons/mod/chat/components/index/addon-mod-chat-index.html @@ -1,14 +1,14 @@ - + - + @@ -27,14 +27,10 @@ - + - - - diff --git a/src/addons/mod/choice/components/index/addon-mod-choice-index.html b/src/addons/mod/choice/components/index/addon-mod-choice-index.html index 60a41827e..f0e2aa0f5 100644 --- a/src/addons/mod/choice/components/index/addon-mod-choice-index.html +++ b/src/addons/mod/choice/components/index/addon-mod-choice-index.html @@ -1,14 +1,14 @@ - + - + @@ -29,14 +29,10 @@ - + - - - @@ -54,8 +50,7 @@ {{ 'addon.mod_choice.yourselection' | translate }} - + {{ 'addon.mod_choice.expired' | translate:{$a: closeTimeReadable} }} @@ -145,10 +140,12 @@
{{ 'addon.mod_choice.yourselection' | translate }} - +
{{ 'addon.mod_choice.expired' | translate:{$a: closeTimeReadable} }}
{{user.fullname}}
{{ 'addon.mod_choice.noresultsviewable' | translate }}
{{item.num}}. + contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId">
- +
{{ 'addon.mod_feedback.average' | translate }}: {{item.average | number : '1.2-2'}} diff --git a/src/addons/mod/folder/components/index/addon-mod-folder-index.html b/src/addons/mod/folder/components/index/addon-mod-folder-index.html index 4763418b3..e44e8a1b7 100644 --- a/src/addons/mod/folder/components/index/addon-mod-folder-index.html +++ b/src/addons/mod/folder/components/index/addon-mod-folder-index.html @@ -1,14 +1,14 @@ - + - + @@ -26,14 +26,11 @@ - + + {{subfolder.filename}} - - - 0)"> diff --git a/src/addons/mod/forum/components/index/index.html b/src/addons/mod/forum/components/index/index.html index 3703497a6..642a96d2f 100644 --- a/src/addons/mod/forum/components/index/index.html +++ b/src/addons/mod/forum/components/index/index.html @@ -1,38 +1,30 @@ - + - + - - - + - + - @@ -46,15 +38,16 @@ - + + + + {{descriptionNote}} + + - - - @@ -72,23 +65,17 @@ - + - - @@ -98,15 +85,12 @@ [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"> - +
{{ rule }}
{{ 'addon.mod_quiz.outof' | translate: { $a: { grade: bestGrade.gradetopass, maxgrade: quiz.gradeFormatted - } } }}
{{ 'addon.mod_quiz.comment' | translate }}
-
+ + +
{{ 'addon.mod_quiz.overallfeedback' | translate }}
{{ message }}
{{ 'addon.mod_quiz.noquestions' | translate }}
{{ currentOrganization.title }}
- + - 0 && !incomplete && attemptsLeft > 0"> + 0 && !incomplete && attemptsLeft > 0"> {{ 'addon.mod_scorm.newattempt' | translate }} diff --git a/src/addons/mod/survey/components/index/addon-mod-survey-index.html b/src/addons/mod/survey/components/index/addon-mod-survey-index.html index 5bf012e3e..16ebaa871 100644 --- a/src/addons/mod/survey/components/index/addon-mod-survey-index.html +++ b/src/addons/mod/survey/components/index/addon-mod-survey-index.html @@ -1,21 +1,21 @@ - + - + + [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" + [closeOnClick]="false"> @@ -30,15 +30,11 @@ - + - - - {{ 'addon.mod_survey.surveycompletednograph' | translate }} @@ -63,7 +59,7 @@ - + {{ question.text }} {{ 'addon.mod_survey.responses' | translate }} @@ -73,15 +69,16 @@ - {{ question.intro }} + + {{ question.intro }} + - + @@ -93,19 +90,17 @@ + *ngFor="let option of question.optionsArray; let value=index;"> + [attr.aria-labelledby]="'addon-mod_survey-'+question.id" interface="action-sheet" [name]="question.name" + [interfaceOptions]="{header: question.text}"> {{ 'core.choose' | translate }} - + {{option}} @@ -126,8 +121,8 @@ + [attr.aria-labelledby]="'addon-mod_survey-'+question.id" interface="action-sheet" [name]="question.name" + [interfaceOptions]="{header: question.text}"> {{option}} diff --git a/src/addons/mod/url/components/index/addon-mod-url-index.html b/src/addons/mod/url/components/index/addon-mod-url-index.html index 722bdfafd..491e186eb 100644 --- a/src/addons/mod/url/components/index/addon-mod-url-index.html +++ b/src/addons/mod/url/components/index/addon-mod-url-index.html @@ -1,12 +1,12 @@ - + - + @@ -16,14 +16,10 @@ - + - - - diff --git a/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html b/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html index 07a1a2638..5eecab5a1 100644 --- a/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html +++ b/src/addons/mod/wiki/components/index/addon-mod-wiki-index.html @@ -1,8 +1,8 @@ - 1" (click)="showSubwikiPicker($event)" - [attr.aria-label]="'addon.mod_wiki.subwiki' | translate" aria-haspopup="true"> + 1" (click)="showSubwikiPicker($event)" [attr.aria-label]="'addon.mod_wiki.subwiki' | translate" + aria-haspopup="true"> @@ -13,18 +13,17 @@ - + - + + [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> - + @@ -49,15 +48,12 @@ - + + {{pageTitle}} - - - - + @@ -82,8 +78,7 @@ - + diff --git a/src/addons/mod/wiki/pages/index/index.ts b/src/addons/mod/wiki/pages/index/index.ts index 3b6058055..e98a10c9f 100644 --- a/src/addons/mod/wiki/pages/index/index.ts +++ b/src/addons/mod/wiki/pages/index/index.ts @@ -52,9 +52,7 @@ export class AddonModWikiIndexPage extends CoreCourseModuleMainActivityPage - + - + @@ -22,15 +22,15 @@ - + + - + @@ -87,9 +87,8 @@ {{ 'addon.mod_workshop.conclusion' | translate }} - + @@ -97,7 +96,9 @@ - {{ 'addon.mod_workshop.yourgrades' | translate }} + + {{ 'addon.mod_workshop.yourgrades' | translate }} + @@ -120,8 +121,7 @@ {{ 'addon.mod_workshop.areainstructauthors' | translate }} + [text]="workshop!.instructauthors" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> @@ -166,7 +166,9 @@ = PHASE_CLOSED"> - {{ 'addon.mod_workshop.publishedsubmissions' | translate }} + + {{ 'addon.mod_workshop.publishedsubmissions' | translate }} + - {{ 'addon.mod_workshop.assignedassessments' | translate }} + + {{ 'addon.mod_workshop.assignedassessments' | translate }} + - {{ 'addon.mod_workshop.assignedassessmentsnone' | translate }} + + {{ 'addon.mod_workshop.assignedassessmentsnone' | translate }} + - + diff --git a/src/core/features/course/classes/main-resource-component.ts b/src/core/features/course/classes/main-resource-component.ts index e01d48d86..722907a73 100644 --- a/src/core/features/course/classes/main-resource-component.ts +++ b/src/core/features/course/classes/main-resource-component.ts @@ -70,7 +70,6 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, isDestroyed = false; // Whether the component is destroyed, used when calling fillContextMenu. contextMenuStatusObserver?: CoreEventObserver; // Observer of package status, used when calling fillContextMenu. contextFileStatusObserver?: CoreEventObserver; // Observer of file status, used when calling fillContextMenu. - showCompletion = false; // Whether to show completion inside the activity. protected fetchContentDefaultError = 'core.course.errorgetmodule'; // Default error to show when loading contents. protected isCurrentView = false; // Whether the component is in the current view. @@ -80,6 +79,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, protected completionObserver?: CoreEventObserver; protected logger: CoreLogger; protected debouncedUpdateModule?: () => void; // Update the module after a certain time. + protected showCompletion = false; // Whether to show completion inside the activity. constructor( @Optional() @Inject('') loggerName: string = 'CoreCourseModuleMainResourceComponent', @@ -97,7 +97,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, this.componentId = this.module.id; this.externalUrl = this.module.url; this.courseId = this.courseId || this.module.course!; - this.showCompletion = !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.11'); + this.showCompletion = !!CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('3.11'); if (this.showCompletion) { CoreCourseHelper.calculateModuleCompletionData(this.module, this.courseId); diff --git a/src/core/features/course/components/module-description/module-description.ts b/src/core/features/course/components/module-description/module-description.ts index d5fcf1139..6fc2ed236 100644 --- a/src/core/features/course/components/module-description/module-description.ts +++ b/src/core/features/course/components/module-description/module-description.ts @@ -28,7 +28,9 @@ import { Component, Input } from '@angular/core'; * * Example usage: * - * + * + * @deprecated since 4.0 use core-course-module-info */ @Component({ selector: 'core-course-module-description', diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html index d69b3148a..acd0b90e5 100644 --- a/src/core/features/course/components/module-info/core-course-module-info.html +++ b/src/core/features/course/components/module-info/core-course-module-info.html @@ -1,18 +1,37 @@ - - - - - - - {{ date.label }} {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }} - - + + + + + + + + + + + + + + + + + + + + + + + + {{ date.label }} {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }} + + - - - - - - + + + + + + diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss index ddf0beb55..a4d1bf7e1 100644 --- a/src/core/features/course/components/module-info/course-module-info.scss +++ b/src/core/features/course/components/module-info/course-module-info.scss @@ -2,5 +2,9 @@ :host { display: block; + box-shadow: 0px 3px 3px rgba(var(--drop-shadow)); + margin-bottom: 8px; + background-color: var(--contrast-background); + @include padding-horizontal(var(--ion-safe-area-left), var(--ion-safe-area-right)); -} \ No newline at end of file +} diff --git a/src/core/features/course/components/module-info/module-info.ts b/src/core/features/course/components/module-info/module-info.ts index 254ad3c7c..13cbd4e40 100644 --- a/src/core/features/course/components/module-info/module-info.ts +++ b/src/core/features/course/components/module-info/module-info.ts @@ -12,21 +12,48 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { CoreCourseModule, CoreCourseModuleCompletionData } from '@features/course/services/course-helper'; +import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; +import { CoreSites } from '@services/sites'; /** - * Display info about a module: dates and completion. + * Display info about a module: + * + * Description: + * Module descriptions are shortened by default, allowing the user to see the full description by clicking in it. + * + * Completion dates, status and buttons. + * + * You can add also add custom information that will be included at the end. */ @Component({ selector: 'core-course-module-info', templateUrl: 'core-course-module-info.html', styleUrls: ['course-module-info.scss'], }) -export class CoreCourseModuleInfoComponent { +export class CoreCourseModuleInfoComponent implements OnInit { @Input() module!: CoreCourseModule; // The module to render. - @Input() showManualCompletion = false; // Whether to show manual completion. + @Input() courseId!: number; // The courseId the module belongs to. + + @Input() component!: string; // Component for format text directive. + @Input() componentId!: string | number; // Component ID to use in conjunction with the component. + + @Input() description?: string | false; // The description to display. If false, no description will be shown. + @Output() completionChanged = new EventEmitter(); // Notify when completion changes. + modicon = ''; + showCompletion = false; // Whether to show completion. + + /** + * @inheritdoc + */ + async ngOnInit(): Promise { + this.modicon = await CoreCourseModuleDelegate.getModuleIconSrc(this.module.modname, this.module.modicon, this.module); + + this.showCompletion = CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('3.11'); + } + } diff --git a/src/core/features/course/components/unsupported-module/core-course-unsupported-module.html b/src/core/features/course/components/unsupported-module/core-course-unsupported-module.html index 10fb79074..4e27e6c44 100644 --- a/src/core/features/course/components/unsupported-module/core-course-unsupported-module.html +++ b/src/core/features/course/components/unsupported-module/core-course-unsupported-module.html @@ -1,7 +1,6 @@ - - + + {{ 'core.whoops' | translate }} {{ 'core.uhoh' | translate }} From f31fc5a6df2ec8a21212141a302745450ee6494d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 17 Nov 2021 11:46:37 +0100 Subject: [PATCH 4/9] MOBILE-3810 format-text: Remove format text full view and review toggle --- .../addon-mod-assign-feedback-plugin.html | 6 +- .../addon-mod-assign-submission-plugin.html | 6 +- .../addon-mod-assign-feedback-comments.html | 15 +- ...ddon-mod-assign-submission-onlinetext.html | 17 +-- .../index/addon-mod-workshop-index.html | 8 +- src/core/directives/format-text.ts | 128 ++++++++---------- .../core-course-module-description.html | 7 +- .../module-info/core-course-module-info.html | 2 +- .../components/module/core-course-module.html | 64 +++------ .../course/pages/preview/preview.html | 66 ++++----- .../courses/pages/categories/categories.html | 2 +- .../courses/services/courses-helper.ts | 2 +- .../features/grades/pages/grade/grade.html | 27 ++-- src/core/services/utils/text.ts | 2 +- src/theme/components/format-text.scss | 88 ++++++------ src/theme/theme.base.scss | 2 +- 16 files changed, 212 insertions(+), 230 deletions(-) diff --git a/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html b/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html index 0c6116e3c..fce2551b7 100644 --- a/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html +++ b/src/addons/mod/assign/components/feedback-plugin/addon-mod-assign-feedback-plugin.html @@ -1,4 +1,3 @@ - @@ -9,9 +8,8 @@ {{ 'addon.mod_assign.feedbacknotsupported' | translate }} - + @@ -9,9 +8,8 @@ {{ 'addon.mod_assign.submissionnotsupported' | translate }} - + {{ plugin.name }} - + - + @@ -25,9 +23,8 @@ {{ plugin.name }} - + diff --git a/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html b/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html index 6660c6c4f..f17a5dca5 100644 --- a/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html +++ b/src/addons/mod/assign/submission/onlinetext/component/addon-mod-assign-submission-onlinetext.html @@ -4,9 +4,8 @@ {{ plugin.name }} {{ 'addon.mod_assign.numwords' | translate: {'$a': words} }} - + @@ -15,7 +14,9 @@ - {{ plugin.name }} + + {{ plugin.name }} + = 0"> @@ -25,10 +26,10 @@ {{ plugin.name }} - + diff --git a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html index 35f7cac49..4004119c0 100644 --- a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html +++ b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html @@ -87,7 +87,7 @@ {{ 'addon.mod_workshop.conclusion' | translate }} - @@ -120,8 +120,8 @@ {{ 'addon.mod_workshop.areainstructauthors' | translate }} - + @@ -184,7 +184,7 @@ {{ 'addon.mod_workshop.areainstructreviewers' | translate }} - diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts index ea1ed3e5e..10c220e72 100644 --- a/src/core/directives/format-text.ts +++ b/src/core/directives/format-text.ts @@ -61,8 +61,6 @@ export class CoreFormatTextDirective implements OnChanges { @Input() adaptImg?: boolean | string = true; // Whether to adapt images to screen width. @Input() clean?: boolean | string; // Whether all the HTML tags should be removed. @Input() singleLine?: boolean | string; // Whether new lines should be removed (all text in single line). Only if clean=true. - @Input() fullOnClick?: boolean | string; // Whether it should open a new page with the full contents on click. - @Input() fullTitle?: string; // Title to use in full view. Defaults to "Description". @Input() highlight?: string; // Text to highlight. @Input() filter?: boolean | string; // Whether to filter the text. If not defined, true if contextLevel and instanceId are set. @Input() contextLevel?: string; // The context level of the text. @@ -73,6 +71,8 @@ export class CoreFormatTextDirective implements OnChanges { @Input() openLinksInApp?: boolean; // Whether links should be opened in InAppBrowser. @Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty. + @Input() fullOnClick?: boolean | string; // @deprecated on 4.0 Won't do anything. + @Input() fullTitle?: string; // @deprecated on 4.0 Won't do anything.. /** * Max height in pixels to render the content box. It should be 50 at least to make sense. * Using this parameter will force display: block to calculate height better. @@ -84,10 +84,11 @@ export class CoreFormatTextDirective implements OnChanges { @Output() onClick: EventEmitter = new EventEmitter(); // Called when clicked. protected element: HTMLElement; - protected showMoreDisplayed = false; + protected expanded = false; protected loadingChangedListener?: CoreEventObserver; protected emptyText = ''; protected contentSpan: HTMLElement; + protected toggleExpandEnabled = false; constructor( element: ElementRef, @@ -114,11 +115,12 @@ export class CoreFormatTextDirective implements OnChanges { } /** - * Detect changes on input properties. + * @inheritdoc */ ngOnChanges(changes: { [name: string]: SimpleChange }): void { if (changes.text || changes.filter || changes.contextLevel || changes.contextInstanceId) { - this.hideShowMore(); + this.setExpandButtonEnabled(false); + this.formatAndRenderContents(); } } @@ -267,37 +269,61 @@ export class CoreFormatTextDirective implements OnChanges { this.element.style.maxHeight = initialMaxHeight; // If cannot calculate height, shorten always. - if (!height || height > this.maxHeight) { - if (!this.showMoreDisplayed) { - this.displayShowMore(); - } - } else if (this.showMoreDisplayed) { - this.hideShowMore(); - } + this.setExpandButtonEnabled(!height || height > this.maxHeight); } /** - * Display the "Show more" in the element. + * Sets if expand button is enabled or not. + * + * @param enable Wether enable or disable. */ - protected displayShowMore(): void { - const expandInFullview = CoreUtils.isTrueOrOne(this.fullOnClick) || false; - const showMoreButton = document.createElement('ion-button'); + protected setExpandButtonEnabled(enable: boolean): void { + this.toggleExpandEnabled = enable; + this.element.classList.toggle('core-text-formatted', enable); - showMoreButton.classList.add('core-show-more'); - showMoreButton.setAttribute('fill', 'clear'); - showMoreButton.innerHTML = Translate.instant('core.showmore'); - this.element.appendChild(showMoreButton); - - if (expandInFullview) { - this.element.classList.add('core-expand-in-fullview'); - } else { - showMoreButton.setAttribute('aria-expanded', 'false'); + if (!enable || this.element.querySelector('ion-button.core-format-text-toggle')) { + return; } - this.element.classList.add('core-text-formatted'); - this.element.classList.add('core-shortened'); - this.element.style.maxHeight = this.maxHeight + 'px'; - this.showMoreDisplayed = true; + // Add expand/collapse buttons + const toggleButton = document.createElement('ion-button'); + toggleButton.classList.add('core-format-text-toggle'); + toggleButton.setAttribute('fill', 'clear'); + + const toggleText = document.createElement('span'); + toggleText.classList.add('core-format-text-toggle-text'); + toggleButton.appendChild(toggleText); + + const expandArrow = document.createElement('span'); + expandArrow.classList.add('core-format-text-arrow'); + toggleButton.appendChild(expandArrow); + + this.element.appendChild(toggleButton); + + this.toggleExpand(this.expanded); + } + + /** + * Expand or collapse text. + * + * @param expand Wether expand or collapse text. If undefined, will toggle. + */ + protected toggleExpand(expand?: boolean): void { + if (expand === undefined) { + expand = !this.expanded; + } + this.expanded = expand; + this.element.classList.toggle('core-text-format-expanded', expand); + this.element.classList.toggle('core-text-format-collapsed', !expand); + this.element.style.maxHeight = expand ? '' : this.maxHeight + 'px'; + + const toggleButton = this.element.querySelector('ion-button.core-format-text-toggle'); + const toggleText = toggleButton?.querySelector('.core-format-text-toggle-text'); + if (!toggleButton || !toggleText) { + return; + } + toggleText.innerHTML = expand ? Translate.instant('core.showless') : Translate.instant('core.showmore'); + toggleButton.setAttribute('aria-expanded', expand ? 'true' : 'false'); } /** @@ -321,9 +347,7 @@ export class CoreFormatTextDirective implements OnChanges { return; } - const expandInFullview = CoreUtils.isTrueOrOne(this.fullOnClick) || false; - - if (!expandInFullview && !this.showMoreDisplayed) { + if (!this.toggleExpandEnabled) { // Nothing to do on click, just stop. return; } @@ -331,28 +355,7 @@ export class CoreFormatTextDirective implements OnChanges { e.preventDefault(); e.stopPropagation(); - if (!expandInFullview) { - // Change class. - this.element.classList.toggle('core-shortened'); - - return; - } else { - // Open a new state with the contents. - const filter = typeof this.filter != 'undefined' ? CoreUtils.isTrueOrOne(this.filter) : undefined; - - CoreTextUtils.viewText( - this.fullTitle || Translate.instant('core.description'), - this.text, - { - component: this.component, - componentId: this.componentId, - filter: filter, - contextLevel: this.contextLevel, - instanceId: this.contextInstanceId, - courseId: this.courseId, - }, - ); - } + this.toggleExpand(); } /** @@ -361,6 +364,7 @@ export class CoreFormatTextDirective implements OnChanges { protected finishRender(): void { // Show the element again. this.element.classList.remove('core-format-text-loading'); + // Emit the afterRender output. this.afterRender.emit(); } @@ -393,7 +397,7 @@ export class CoreFormatTextDirective implements OnChanges { this.contentSpan.innerHTML = ''; // Remove current contents. if (this.maxHeight && result.div.innerHTML != '' && - (this.fullOnClick || (window.innerWidth < 576 || window.innerHeight < 576))) { // Don't collapse in big screens. + (window.innerWidth < 576 || window.innerHeight < 576)) { // Don't collapse in big screens. // Move the children to the current element to be able to calculate the height. CoreDomUtils.moveChildren(result.div, this.contentSpan); @@ -655,20 +659,6 @@ export class CoreFormatTextDirective implements OnChanges { return CoreDomUtils.getElementHeight(element) || 0; } - /** - * "Hide" the "Show more" in the element if it's shown. - */ - protected hideShowMore(): void { - const showMoreButton = this.element.querySelector('ion-button.core-show-more'); - showMoreButton?.remove(); - - this.element.classList.remove('core-expand-in-fullview'); - this.element.classList.remove('core-text-formatted'); - this.element.classList.remove('core-shortened'); - this.element.style.maxHeight = ''; - this.showMoreDisplayed = false; - } - /** * Add media adapt class and apply CoreExternalContentDirective to the media element and its sources and tracks. * diff --git a/src/core/features/course/components/module-description/core-course-module-description.html b/src/core/features/course/components/module-description/core-course-module-description.html index e07546c5a..0f6d34c0a 100644 --- a/src/core/features/course/components/module-description/core-course-module-description.html +++ b/src/core/features/course/components/module-description/core-course-module-description.html @@ -1,9 +1,8 @@ - + @@ -12,4 +11,4 @@ {{ note }} - \ No newline at end of file + diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html index acd0b90e5..8aac777b4 100644 --- a/src/core/features/course/components/module-info/core-course-module-info.html +++ b/src/core/features/course/components/module-info/core-course-module-info.html @@ -13,7 +13,7 @@ + [contextInstanceId]="module.id" [courseId]="courseId" [maxHeight]="120"> diff --git a/src/core/features/course/components/module/core-course-module.html b/src/core/features/course/components/module/core-course-module.html index 630c19e11..ea1bec5df 100644 --- a/src/core/features/course/components/module/core-course-module.html +++ b/src/core/features/course/components/module/core-course-module.html @@ -1,17 +1,12 @@ - + }" [button]="module.handlerData.action && module.uservisible" detail="false"> @@ -23,11 +18,8 @@ [courseId]="courseId" [attr.aria-label]="module.handlerData.a11yTitle + ', ' + modNameTranslated"> - + @@ -47,12 +39,8 @@ - + - + + (click)="buttonClicked($event, button)" [attr.aria-label]="button.label | translate:{$a: module.handlerData.title}"> - + }" detail="false"> @@ -94,12 +75,12 @@ - - @@ -107,14 +88,11 @@ - - + [ngClass]="['core-course-module-handler', 'core-module-loading', module.handlerData.class]" detail="false"> + + + diff --git a/src/core/features/course/pages/preview/preview.html b/src/core/features/course/pages/preview/preview.html index a69893d67..49a16a7ab 100644 --- a/src/core/features/course/pages/preview/preview.html +++ b/src/core/features/course/pages/preview/preview.html @@ -15,7 +15,7 @@ - + @@ -27,8 +27,10 @@ - + + + + {{course.startdate * 1000 | coreFormatDate:"strftimedatefullshort" }} - {{course.enddate * 1000 | coreFormatDate:"strftimedatefullshort" }} @@ -38,7 +40,7 @@ - + @@ -51,8 +53,7 @@ - + {{contact.fullname}} @@ -63,20 +64,20 @@ - - - - - - : - - - - - - + + + + + + : + + + + + + @@ -100,19 +101,19 @@ - {{ 'core.courses.notenrollable' | translate }} + + {{ 'core.courses.notenrollable' | translate }} + + [attr.aria-label]="prefetchCourseData.statusTranslatable | translate" button> - + - + {{ 'core.course.downloadcourse' | translate }} {{ 'core.course.refreshcourse' | translate }} @@ -121,12 +122,15 @@ - {{ 'core.course.contents' | translate }} + + {{ 'core.course.contents' | translate }} + - + - {{ 'core.openinbrowser' | translate }} + + {{ 'core.openinbrowser' | translate }} + diff --git a/src/core/features/courses/pages/categories/categories.html b/src/core/features/courses/pages/categories/categories.html index 495001569..0baf6bdff 100644 --- a/src/core/features/courses/pages/categories/categories.html +++ b/src/core/features/courses/pages/categories/categories.html @@ -31,7 +31,7 @@ - diff --git a/src/core/features/courses/services/courses-helper.ts b/src/core/features/courses/services/courses-helper.ts index 3cf1a014d..df8e4e92c 100644 --- a/src/core/features/courses/services/courses-helper.ts +++ b/src/core/features/courses/services/courses-helper.ts @@ -251,7 +251,7 @@ export class CoreCoursesHelperProvider { case 'lastaccess': courses.sort((a, b) => (b.lastaccess || 0) - (a.lastaccess || 0)); break; - // @todo Time modified property is not defined in CoreEnrolledCourseDataWithOptions, so it won't do nothing. + // @todo Time modified property is not defined in CoreEnrolledCourseDataWithOptions, so it Won't do anything. // case 'timemodified': // courses.sort((a, b) => b.timemodified - a.timemodified); // break; diff --git a/src/core/features/grades/pages/grade/grade.html b/src/core/features/grades/pages/grade/grade.html index 9abe2b1f3..f565c8388 100644 --- a/src/core/features/grades/pages/grade/grade.html +++ b/src/core/features/grades/pages/grade/grade.html @@ -14,26 +14,29 @@ - + - + - - + + + + - + - + - - + + + + @@ -89,8 +92,10 @@ {{ 'core.grades.feedback' | translate}} - + + + + diff --git a/src/core/services/utils/text.ts b/src/core/services/utils/text.ts index 2ea31bf2b..362298e18 100644 --- a/src/core/services/utils/text.ts +++ b/src/core/services/utils/text.ts @@ -571,7 +571,7 @@ export class CoreTextUtilsProvider { const regex = new RegExp('(' + searchText + ')', 'gi'); - return text.replace(regex, '$1'); + return text.replace(regex, '$1'); } /** diff --git a/src/theme/components/format-text.scss b/src/theme/components/format-text.scss index 204c0612b..7ac616332 100644 --- a/src/theme/components/format-text.scss +++ b/src/theme/components/format-text.scss @@ -51,11 +51,15 @@ core-format-text { display: inline; } - .core-show-more { + .core-format-text-toggle { display: none !important; } } + .core-format-text-toggle { + display: none; + } + .core-format-text-content { opacity: 1; @include core-transition(opacity, 200ms); @@ -84,30 +88,45 @@ core-format-text { cursor: pointer; pointer-events: auto; - .core-show-more { - display: none; + .core-format-text-toggle { + display: block; + position: absolute; + bottom: 0; + left: 0; + right: 0; + text-align: center; + z-index: 7; + text-transform: none; + text-align: end; + font-size: 14px; + background-color: var(--core-format-text-background); + color: var(--text-color); + margin: 0; + + + .core-format-text-arrow { + width: var(--a11y-min-target-size); + height: var(--a11y-min-target-size); + + background-position: center; + background-repeat: no-repeat; + background-size: 14px 14px; + @include core-transition(transform, 500ms); + + @include push-arrow-color(626262, true); + + @include darkmode() { + @include push-arrow-color(ffffff, true); + } + } } - &:not(.core-shortened) { - max-height: none !important; - } - - &.core-shortened { + &.core-text-format-collapsed { overflow: hidden; min-height: 50px; - .core-show-more { - text-transform: none; - text-align: end; - font-size: 14px; - display: block; - position: absolute; - @include position(null, 0, 0, null); - z-index: 7; - background-color: var(--core-format-text-background); - color: var(--text-color); - @include padding(null, null, null, 10px); - margin: 0; + .core-format-text-arrow { + transform: rotate(90deg); } &:before { @@ -115,26 +134,19 @@ core-format-text { height: 100%; position: absolute; @include position(null, 0, 0, 0); - background: -webkit-linear-gradient(top, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 15px)); - background: linear-gradient(to bottom, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 50px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 15px)); + background: -webkit-linear-gradient(top, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 60px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 40px)); + background: linear-gradient(to bottom, rgba(var(--core-format-text-background-gradient-rgb), 0) calc(100% - 60px), rgba(var(--core-format-text-background-gradient-rgb), 1) calc(100% - 40px)); z-index: 6; } } - } - &.core-expand-in-fullview { - cursor: pointer; + &.core-text-format-expanded { + max-height: none !important; - .core-show-more { - @include push-arrow-color(626262, true); - @include padding-horizontal(null, 5px); - @include background-position(end, 5px, center); + padding-bottom: 50px; // So the Show less button can fit. - background-repeat: no-repeat; - background-size: 14px 14px; - - @include darkmode() { - @include push-arrow-color(ffffff, true); + .core-format-text-arrow { + transform: rotate(-90deg); } } } @@ -143,10 +155,10 @@ core-format-text { @if ($core-format-text-never-shorten) { &[maxHeight], &[ng-reflect-max-height] { - &.core-text-formatted.core-shortened { + &.core-text-formatted.core-text-format-expanded { max-height: none !important; - .core-show-more { + .core-format-text-toggle { display: none !important; } @@ -354,7 +366,7 @@ core-rich-text-editor .core-rte-editor { height: 30px; display: inline-block; border: 1px solid var(--gray-dark); - background: var(--background-contrast); + background: var(--contrast-background); padding: 6px 8px; border-radius: 4px; margin-left: 2px; @@ -363,7 +375,7 @@ core-rich-text-editor .core-rte-editor { } select { - background-color: var(--background-contrast); + background-color: var(--contrast-background); background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23000000%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'); background-repeat: no-repeat, repeat; background-position: right .7em top 50%, 0 0; diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index c7150accd..12b4b04a1 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -848,7 +848,7 @@ core-block ion-item-divider .core-button-spinner { // Text formats. // Highlight text. -.matchtext { +mark, .matchtext { background-color: var(--text-hightlight-background-color); } From a0687821aea8933d60e6babbd78081f52b2f2949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 17 Nov 2021 11:46:37 +0100 Subject: [PATCH 5/9] MOBILE-3810 module: Add data to sync to module info --- .../components/index/addon-mod-assign-index.html | 12 +----------- .../components/index/addon-mod-choice-index.html | 10 +--------- .../data/components/index/addon-mod-data-index.html | 10 +--------- .../components/index/addon-mod-feedback-index.html | 10 +--------- src/addons/mod/forum/components/index/index.html | 12 ++---------- .../components/index/addon-mod-glossary-index.html | 10 +--------- .../index/addon-mod-h5pactivity-index.html | 10 +--------- .../components/index/addon-mod-lesson-index.html | 10 +--------- .../quiz/components/index/addon-mod-quiz-index.html | 11 ++--------- .../components/index/addon-mod-scorm-index.html | 10 +--------- .../components/index/addon-mod-survey-index.html | 12 ++---------- .../components/index/addon-mod-workshop-index.html | 10 +--------- .../module-info/core-course-module-info.html | 8 ++++++++ .../components/module-info/course-module-info.scss | 1 + .../course/components/module-info/module-info.ts | 6 ++++++ .../features/courses/pages/dashboard/dashboard.ts | 1 - 16 files changed, 30 insertions(+), 113 deletions(-) diff --git a/src/addons/mod/assign/components/index/addon-mod-assign-index.html b/src/addons/mod/assign/components/index/addon-mod-assign-index.html index 1efbaa292..fd835cefd 100644 --- a/src/addons/mod/assign/components/index/addon-mod-assign-index.html +++ b/src/addons/mod/assign/components/index/addon-mod-assign-index.html @@ -31,23 +31,13 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> - - - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - diff --git a/src/addons/mod/choice/components/index/addon-mod-choice-index.html b/src/addons/mod/choice/components/index/addon-mod-choice-index.html index f0e2aa0f5..a767fe487 100644 --- a/src/addons/mod/choice/components/index/addon-mod-choice-index.html +++ b/src/addons/mod/choice/components/index/addon-mod-choice-index.html @@ -30,7 +30,7 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> @@ -58,14 +58,6 @@ - - - - - {{ 'core.hasdatatosync' | translate:{$a: moduleName} }} - - - diff --git a/src/addons/mod/data/components/index/addon-mod-data-index.html b/src/addons/mod/data/components/index/addon-mod-data-index.html index f8a993361..8a1f45d10 100644 --- a/src/addons/mod/data/components/index/addon-mod-data-index.html +++ b/src/addons/mod/data/components/index/addon-mod-data-index.html @@ -40,17 +40,9 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - {{'core.groupsseparate' | translate }} diff --git a/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html b/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html index b6852c689..aacd8344e 100644 --- a/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html +++ b/src/addons/mod/feedback/components/index/addon-mod-feedback-index.html @@ -30,7 +30,7 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> @@ -106,14 +106,6 @@ - - - - - {{ 'core.hasdatatosync' | translate:{$a: moduleName} }} - - - diff --git a/src/addons/mod/forum/components/index/index.html b/src/addons/mod/forum/components/index/index.html index 642a96d2f..e61fce1ef 100644 --- a/src/addons/mod/forum/components/index/index.html +++ b/src/addons/mod/forum/components/index/index.html @@ -39,8 +39,8 @@ + [description]="forum && forum.type != 'single' && description" [component]="component" [componentId]="componentId" + [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> {{descriptionNote}} @@ -48,14 +48,6 @@ - - - - - {{ 'core.hasdatatosync' | translate:{$a: moduleName} }} - - - diff --git a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html index 61cee7db8..b0095c394 100644 --- a/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html +++ b/src/addons/mod/glossary/components/index/addon-mod-glossary-index.html @@ -51,17 +51,9 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> - - - - - {{ 'core.hasdatatosync' | translate:{$a: moduleName} }} - - - 0"> diff --git a/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html b/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html index 1811b5b44..4c7b7cd88 100644 --- a/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html +++ b/src/addons/mod/h5pactivity/components/index/addon-mod-h5pactivity-index.html @@ -37,17 +37,9 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - diff --git a/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html index aa28071e4..a9eeb2a60 100644 --- a/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html +++ b/src/addons/mod/lesson/components/index/addon-mod-lesson-index.html @@ -34,7 +34,7 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> @@ -45,14 +45,6 @@ - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - diff --git a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html index 519746fe0..cf49f5b7b 100644 --- a/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html +++ b/src/addons/mod/quiz/components/index/addon-mod-quiz-index.html @@ -30,7 +30,8 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" + [hasDataToSync]="buttonText && hasOffline && !showStatusSpinner"> @@ -194,14 +195,6 @@ - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - diff --git a/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html b/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html index 58f417175..f184db40a 100644 --- a/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html +++ b/src/addons/mod/scorm/components/index/addon-mod-scorm-index.html @@ -30,7 +30,7 @@ + [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="!errorMessage && hasOffline"> @@ -113,14 +113,6 @@ - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - 1)" class="addon-mod_scorm-toc"> diff --git a/src/addons/mod/survey/components/index/addon-mod-survey-index.html b/src/addons/mod/survey/components/index/addon-mod-survey-index.html index 16ebaa871..b5042fbf5 100644 --- a/src/addons/mod/survey/components/index/addon-mod-survey-index.html +++ b/src/addons/mod/survey/components/index/addon-mod-survey-index.html @@ -31,8 +31,8 @@ + [description]="survey && !survey.surveydone && !hasOffline && description" [component]="component" [componentId]="componentId" + [courseId]="courseId" [hasDataToSync]="hasOffline"> @@ -44,14 +44,6 @@ - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - diff --git a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html index 4004119c0..1aedc639d 100644 --- a/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html +++ b/src/addons/mod/workshop/components/index/addon-mod-workshop-index.html @@ -30,7 +30,7 @@ - + @@ -60,14 +60,6 @@ - - - - - {{ 'core.hasdatatosync' | translate: {$a: moduleName} }} - - - diff --git a/src/core/features/course/components/module-info/core-course-module-info.html b/src/core/features/course/components/module-info/core-course-module-info.html index 8aac777b4..a169e3604 100644 --- a/src/core/features/course/components/module-info/core-course-module-info.html +++ b/src/core/features/course/components/module-info/core-course-module-info.html @@ -35,3 +35,11 @@ + + + + + + {{ 'core.hasdatatosync' | translate: {$a: moduleNameTranslated} }} + + diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss index a4d1bf7e1..0a0b5bce7 100644 --- a/src/core/features/course/components/module-info/course-module-info.scss +++ b/src/core/features/course/components/module-info/course-module-info.scss @@ -4,6 +4,7 @@ display: block; box-shadow: 0px 3px 3px rgba(var(--drop-shadow)); margin-bottom: 8px; + padding-bottom: 1px; // To allow margins inside. background-color: var(--contrast-background); @include padding-horizontal(var(--ion-safe-area-left), var(--ion-safe-area-right)); diff --git a/src/core/features/course/components/module-info/module-info.ts b/src/core/features/course/components/module-info/module-info.ts index 13cbd4e40..063ebc88f 100644 --- a/src/core/features/course/components/module-info/module-info.ts +++ b/src/core/features/course/components/module-info/module-info.ts @@ -13,6 +13,7 @@ // limitations under the License. import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModule, CoreCourseModuleCompletionData } from '@features/course/services/course-helper'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreSites } from '@services/sites'; @@ -42,10 +43,13 @@ export class CoreCourseModuleInfoComponent implements OnInit { @Input() description?: string | false; // The description to display. If false, no description will be shown. + @Input() hasDataToSync = false; // If the activity has any data to be synced. + @Output() completionChanged = new EventEmitter(); // Notify when completion changes. modicon = ''; showCompletion = false; // Whether to show completion. + moduleNameTranslated = ''; /** * @inheritdoc @@ -53,6 +57,8 @@ export class CoreCourseModuleInfoComponent implements OnInit { async ngOnInit(): Promise { this.modicon = await CoreCourseModuleDelegate.getModuleIconSrc(this.module.modname, this.module.modicon, this.module); + this.moduleNameTranslated = CoreCourse.translateModuleName(this.module.modname || ''); + this.showCompletion = CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('3.11'); } diff --git a/src/core/features/courses/pages/dashboard/dashboard.ts b/src/core/features/courses/pages/dashboard/dashboard.ts index 2b7448a0b..e86d2d72a 100644 --- a/src/core/features/courses/pages/dashboard/dashboard.ts +++ b/src/core/features/courses/pages/dashboard/dashboard.ts @@ -109,7 +109,6 @@ export class CoreCoursesDashboardPage implements OnInit, OnDestroy { this.blocks = []; } - // this.dashboardEnabled = this.blockDelegate.hasSupportedBlock(this.blocks); this.loaded = true; } From 57b5266198d315263b7e9af0a085e0c0cb63c84d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 17 Nov 2021 11:46:37 +0100 Subject: [PATCH 6/9] MOBILE-3810 tabs: Disabled top tabs hide on scroll --- src/core/classes/tabs.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/classes/tabs.ts b/src/core/classes/tabs.ts index d77ca5b4d..d2b593398 100644 --- a/src/core/classes/tabs.ts +++ b/src/core/classes/tabs.ts @@ -43,8 +43,9 @@ export class CoreTabsBaseComponent implements OnInit, Aft // Minimum tab's width. protected static readonly MIN_TAB_WIDTH = 107; - // Max height that allows tab hiding. - protected static readonly MAX_HEIGHT_TO_HIDE_TABS = 768; + // @todo [4.0] + // Max height that allows tab hiding. WARNING: Hide tabs on scroll disabled. If confirmed, remove the associated code. + protected static readonly MAX_HEIGHT_TO_HIDE_TABS = 0; @Input() selectedIndex = 0; // Index of the tab to select. @Input() hideUntil = false; // Determine when should the contents be shown. @@ -179,7 +180,7 @@ export class CoreTabsBaseComponent implements OnInit, Aft } /** - * Detect changes on input properties. + * @inheritdoc */ // eslint-disable-next-line @typescript-eslint/no-unused-vars ngOnChanges(changes: Record): void { From d8718c5eaae68dc3f48b83d10ce995746c45b1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Fri, 19 Nov 2021 13:20:00 +0100 Subject: [PATCH 7/9] MOBILE-3810 core: Collapsible headers --- src/addons/mod/assign/pages/index/index.html | 2 +- src/addons/mod/book/pages/index/index.html | 5 +- src/addons/mod/chat/pages/index/index.html | 2 +- src/addons/mod/choice/pages/index/index.html | 2 +- src/addons/mod/data/pages/index/index.html | 2 +- .../mod/feedback/pages/index/index.html | 2 +- .../index/addon-mod-folder-index.html | 3 +- src/addons/mod/folder/pages/index/index.html | 2 +- src/addons/mod/forum/pages/index/index.html | 2 +- .../mod/glossary/pages/index/index.html | 2 +- .../mod/h5pactivity/pages/index/index.html | 2 +- src/addons/mod/imscp/pages/index/index.html | 2 +- src/addons/mod/lesson/pages/index/index.html | 5 +- src/addons/mod/lti/pages/index/index.html | 2 +- src/addons/mod/page/pages/index/index.html | 2 +- src/addons/mod/quiz/pages/index/index.html | 2 +- .../mod/resource/pages/index/index.html | 5 +- src/addons/mod/scorm/pages/index/index.html | 2 +- src/addons/mod/survey/pages/index/index.html | 2 +- src/addons/mod/url/pages/index/index.html | 2 +- src/addons/mod/wiki/components/index/index.ts | 19 +- src/addons/mod/wiki/pages/index/index.html | 6 +- src/addons/mod/wiki/pages/index/index.ts | 7 +- .../mod/workshop/pages/index/index.html | 2 +- src/core/classes/tabs.ts | 6 +- .../components/split-view/split-view.scss | 3 +- src/core/directives/collapsible-header.ts | 257 ++++++++++++++++++ src/core/directives/directives.module.ts | 3 + .../module-info/core-course-module-info.html | 6 +- .../core-course-unsupported-module.html | 6 +- .../unsupported-module.html | 2 +- src/theme/globals.mixins.scss | 12 +- src/theme/theme.base.scss | 138 +++++++--- 33 files changed, 424 insertions(+), 93 deletions(-) create mode 100644 src/core/directives/collapsible-header.ts diff --git a/src/addons/mod/assign/pages/index/index.html b/src/addons/mod/assign/pages/index/index.html index 8e1a710bc..c64cbdfdd 100644 --- a/src/addons/mod/assign/pages/index/index.html +++ b/src/addons/mod/assign/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/book/pages/index/index.html b/src/addons/mod/book/pages/index/index.html index 495b0b976..2d7faf457 100644 --- a/src/addons/mod/book/pages/index/index.html +++ b/src/addons/mod/book/pages/index/index.html @@ -1,4 +1,4 @@ - + @@ -17,7 +17,6 @@ - + diff --git a/src/addons/mod/chat/pages/index/index.html b/src/addons/mod/chat/pages/index/index.html index b228480b8..de71fbf74 100644 --- a/src/addons/mod/chat/pages/index/index.html +++ b/src/addons/mod/chat/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/choice/pages/index/index.html b/src/addons/mod/choice/pages/index/index.html index 9497c99fb..6f8b727cd 100644 --- a/src/addons/mod/choice/pages/index/index.html +++ b/src/addons/mod/choice/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/data/pages/index/index.html b/src/addons/mod/data/pages/index/index.html index 669549eb4..5d0caa151 100644 --- a/src/addons/mod/data/pages/index/index.html +++ b/src/addons/mod/data/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/feedback/pages/index/index.html b/src/addons/mod/feedback/pages/index/index.html index f7c6c173a..8eb3987ad 100644 --- a/src/addons/mod/feedback/pages/index/index.html +++ b/src/addons/mod/feedback/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/folder/components/index/addon-mod-folder-index.html b/src/addons/mod/folder/components/index/addon-mod-folder-index.html index e44e8a1b7..cb1093a10 100644 --- a/src/addons/mod/folder/components/index/addon-mod-folder-index.html +++ b/src/addons/mod/folder/components/index/addon-mod-folder-index.html @@ -26,9 +26,8 @@ - - {{subfolder.filename}} 0)"> diff --git a/src/addons/mod/folder/pages/index/index.html b/src/addons/mod/folder/pages/index/index.html index 198e37e5f..a3d8d8626 100644 --- a/src/addons/mod/folder/pages/index/index.html +++ b/src/addons/mod/folder/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/forum/pages/index/index.html b/src/addons/mod/forum/pages/index/index.html index c98bfc3a1..c72371b3f 100644 --- a/src/addons/mod/forum/pages/index/index.html +++ b/src/addons/mod/forum/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/glossary/pages/index/index.html b/src/addons/mod/glossary/pages/index/index.html index 2183e2bf6..c1b066a21 100644 --- a/src/addons/mod/glossary/pages/index/index.html +++ b/src/addons/mod/glossary/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/h5pactivity/pages/index/index.html b/src/addons/mod/h5pactivity/pages/index/index.html index 2f3d19f98..1001692cf 100644 --- a/src/addons/mod/h5pactivity/pages/index/index.html +++ b/src/addons/mod/h5pactivity/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/imscp/pages/index/index.html b/src/addons/mod/imscp/pages/index/index.html index fd8b7e083..98a8c22b2 100644 --- a/src/addons/mod/imscp/pages/index/index.html +++ b/src/addons/mod/imscp/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/lesson/pages/index/index.html b/src/addons/mod/lesson/pages/index/index.html index 4c5603526..ba95ea502 100644 --- a/src/addons/mod/lesson/pages/index/index.html +++ b/src/addons/mod/lesson/pages/index/index.html @@ -1,4 +1,4 @@ - + @@ -17,7 +17,6 @@ - + diff --git a/src/addons/mod/lti/pages/index/index.html b/src/addons/mod/lti/pages/index/index.html index bd9a3da32..f742d5232 100644 --- a/src/addons/mod/lti/pages/index/index.html +++ b/src/addons/mod/lti/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/page/pages/index/index.html b/src/addons/mod/page/pages/index/index.html index 464a81a0b..a5db017ea 100644 --- a/src/addons/mod/page/pages/index/index.html +++ b/src/addons/mod/page/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/quiz/pages/index/index.html b/src/addons/mod/quiz/pages/index/index.html index 9fcb5b5c2..2cbf6b449 100644 --- a/src/addons/mod/quiz/pages/index/index.html +++ b/src/addons/mod/quiz/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/resource/pages/index/index.html b/src/addons/mod/resource/pages/index/index.html index 0a03b540b..d86648348 100644 --- a/src/addons/mod/resource/pages/index/index.html +++ b/src/addons/mod/resource/pages/index/index.html @@ -1,4 +1,4 @@ - + @@ -14,8 +14,7 @@ - diff --git a/src/addons/mod/scorm/pages/index/index.html b/src/addons/mod/scorm/pages/index/index.html index 8b0a62177..2e3a4ded7 100644 --- a/src/addons/mod/scorm/pages/index/index.html +++ b/src/addons/mod/scorm/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/survey/pages/index/index.html b/src/addons/mod/survey/pages/index/index.html index e4c9e1717..8d0ffd272 100644 --- a/src/addons/mod/survey/pages/index/index.html +++ b/src/addons/mod/survey/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/url/pages/index/index.html b/src/addons/mod/url/pages/index/index.html index 6b546f69f..b93cbc153 100644 --- a/src/addons/mod/url/pages/index/index.html +++ b/src/addons/mod/url/pages/index/index.html @@ -1,4 +1,4 @@ - + diff --git a/src/addons/mod/wiki/components/index/index.ts b/src/addons/mod/wiki/components/index/index.ts index 8bbd2a3a8..1ae8303a8 100644 --- a/src/addons/mod/wiki/components/index/index.ts +++ b/src/addons/mod/wiki/components/index/index.ts @@ -135,6 +135,8 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp } if (!this.wiki) { + CoreNavigator.back(); + return; } @@ -143,7 +145,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp await AddonModWiki.logView(this.wiki.id, this.wiki.name); CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata); - } catch (error) { + } catch { // Ignore errors. } } else { @@ -210,7 +212,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp /** * @inheritdoc */ - protected async fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise { + protected async fetchContent(refresh = false, sync = false, showErrors = false): Promise { try { // Get the wiki instance. this.wiki = await AddonModWiki.getWiki(this.courseId, this.module.id); @@ -219,6 +221,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp // Page not loaded yet, emit the data to update the page title. this.dataRetrieved.emit(this.wiki); } + AddonModWiki.wikiPageOpened(this.wiki.id, this.currentPath); if (sync) { @@ -299,14 +302,14 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp // No page ID but we received a title. This means we're trying to load an offline page. try { - const title = this.pageTitle || this.wiki!.firstpagetitle!; + const title = this.pageTitle || this.wiki?.firstpagetitle || ''; const offlinePage = await AddonModWikiOffline.getNewPage( title, - this.currentSubwiki!.id, - this.currentSubwiki!.wikiid, - this.currentSubwiki!.userid, - this.currentSubwiki!.groupid, + this.currentSubwiki?.id, + this.currentSubwiki?.wikiid, + this.currentSubwiki?.userid, + this.currentSubwiki?.groupid, ); this.pageIsOffline = true; @@ -321,7 +324,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp this.currentPage = data.pageId; // Stop listening for new page events. - this.newPageObserver!.off(); + this.newPageObserver?.off(); this.newPageObserver = undefined; await this.showLoadingAndFetch(true, false); diff --git a/src/addons/mod/wiki/pages/index/index.html b/src/addons/mod/wiki/pages/index/index.html index fab061635..e8db7c3b0 100644 --- a/src/addons/mod/wiki/pages/index/index.html +++ b/src/addons/mod/wiki/pages/index/index.html @@ -1,4 +1,4 @@ - + @@ -7,6 +7,10 @@ + + + + diff --git a/src/addons/mod/wiki/pages/index/index.ts b/src/addons/mod/wiki/pages/index/index.ts index e98a10c9f..0d374feaa 100644 --- a/src/addons/mod/wiki/pages/index/index.ts +++ b/src/addons/mod/wiki/pages/index/index.ts @@ -47,8 +47,6 @@ export class AddonModWikiIndexPage extends CoreCourseModuleMainActivityPage + diff --git a/src/core/classes/tabs.ts b/src/core/classes/tabs.ts index d2b593398..b03b8f827 100644 --- a/src/core/classes/tabs.ts +++ b/src/core/classes/tabs.ts @@ -26,7 +26,7 @@ import { SimpleChange, } from '@angular/core'; import { IonSlides } from '@ionic/angular'; -import { BackButtonEvent } from '@ionic/core'; +import { BackButtonEvent, ScrollDetail } from '@ionic/core'; import { Subscription } from 'rxjs'; import { Platform, Translate } from '@singletons'; @@ -625,8 +625,8 @@ export class CoreTabsBaseComponent implements OnInit, Aft content.scrollEvents = true; this.scrollElements[id] = scroll; - content.addEventListener('ionScroll', (e: CustomEvent): void => { - this.showHideTabs(parseInt(e.detail.scrollTop, 10), scroll); + content.addEventListener('ionScroll', (e: CustomEvent
{{ 'addon.mod_survey.surveycompletednograph' | translate }}
{{ question.intro }}
{{ 'addon.mod_workshop.assignedassessmentsnone' | translate }}
- {{ date.label }} {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }} -
+ {{ date.label }} {{ date.timestamp * 1000 | coreFormatDate:'strftimedatetime' }} +
{{ 'addon.mod_assign.numwords' | translate: {'$a': words} }}
{{course.startdate * 1000 | coreFormatDate:"strftimedatefullshort" }} - {{course.enddate * 1000 | coreFormatDate:"strftimedatefullshort" }} @@ -38,7 +40,7 @@ - + @@ -51,8 +53,7 @@ - + {{contact.fullname}} @@ -63,20 +64,20 @@ - - - - - - : - - - - - - + + + + + + : + + + + + + @@ -100,19 +101,19 @@ - {{ 'core.courses.notenrollable' | translate }} + + {{ 'core.courses.notenrollable' | translate }} + + [attr.aria-label]="prefetchCourseData.statusTranslatable | translate" button> - + - + {{ 'core.course.downloadcourse' | translate }} {{ 'core.course.refreshcourse' | translate }} @@ -121,12 +122,15 @@ - {{ 'core.course.contents' | translate }} + + {{ 'core.course.contents' | translate }} + - + - {{ 'core.openinbrowser' | translate }} + + {{ 'core.openinbrowser' | translate }} +
{{contact.fullname}}
{{ 'core.courses.notenrollable' | translate }}