commit
						bcbecc48f2
					
				| @ -3,8 +3,10 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="badge">{{ badge.name }}</h1> | ||||
|             <h1 *ngIf="!badge">{{ 'addon.badges.badges' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -157,7 +159,9 @@ | ||||
|             <!-- Endorsement --> | ||||
|             <ion-item-group *ngIf="badge.endorsement"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label><h2>{{ 'addon.badges.bendorsement' | translate}}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.bendorsement' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issuername"> | ||||
|                     <ion-label> | ||||
| @ -169,8 +173,7 @@ | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.issueremail' | translate}}</h2> | ||||
|                         <p> | ||||
|                             <a href="mailto:{{badge.endorsement.issueremail}}" core-link auto-login="no" | ||||
|                                 [showBrowserWarning]="false"> | ||||
|                             <a href="mailto:{{badge.endorsement.issueremail}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                 {{ badge.endorsement.issueremail }} | ||||
|                             </a> | ||||
|                         </p> | ||||
| @ -205,27 +208,39 @@ | ||||
|             <!-- Related badges --> | ||||
|             <ion-item-group *ngIf="badge.relatedbadges"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label><h2>{{ 'addon.badges.relatedbages' | translate}}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.relatedbages' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let relatedBadge of badge.relatedbadges"> | ||||
|                     <ion-label><h2>{{ relatedBadge.name }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ relatedBadge.name }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.relatedbadges.length == 0"> | ||||
|                     <ion-label><h2>{{ 'addon.badges.norelated' | translate}}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.norelated' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
| 
 | ||||
|             <!-- Competencies alignment --> | ||||
|             <ion-item-group *ngIf="badge.alignment"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label><h2>{{ 'addon.badges.alignment' | translate}}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.alignment' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let alignment of badge.alignment" [href]="alignment.targeturl" core-link | ||||
|                     auto-login="no"> | ||||
|                     <ion-label><h2>{{ alignment.targetname }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ alignment.targetname }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.alignment.length == 0"> | ||||
|                     <ion-label><h2>{{ 'addon.badges.noalignment' | translate}}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.noalignment' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
|         </ng-container> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.badges.badges' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -12,8 +14,7 @@ | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="badges.loaded"> | ||||
|             <core-empty-box *ngIf="badges.empty" icon="fas-trophy" | ||||
|                 [message]="'addon.badges.nobadges' | translate"> | ||||
|             <core-empty-box *ngIf="badges.empty" icon="fas-trophy" [message]="'addon.badges.nobadges' | translate"> | ||||
|             </core-empty-box> | ||||
| 
 | ||||
|             <ion-list *ngIf="!badges.empty" class="ion-no-margin"> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ title | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <core-user-menu-button></core-user-menu-button> | ||||
|         </ion-buttons> | ||||
| @ -18,8 +20,7 @@ | ||||
|             <ion-label>{{ 'addon.blog.showonlyyourentries' | translate }}</ion-label> | ||||
|             <ion-toggle [(ngModel)]="onlyMyEntries" (ionChange)="onlyMyEntriesToggleChanged(onlyMyEntries)"></ion-toggle> | ||||
|         </ion-item> | ||||
|         <core-empty-box *ngIf="entries && entries.length == 0" icon="far-newspaper" | ||||
|             [message]="'addon.blog.noentriesyet' | translate"> | ||||
|         <core-empty-box *ngIf="entries && entries.length == 0" icon="far-newspaper" [message]="'addon.blog.noentriesyet' | translate"> | ||||
|         </core-empty-box> | ||||
|         <ng-container *ngFor="let entry of entries"> | ||||
|             <ion-card *ngIf="!onlyMyEntries || entry.userid == currentUserId"> | ||||
| @ -27,8 +28,7 @@ | ||||
|                     <core-user-avatar [user]="entry.user" slot="start" [courseId]="entry.courseid"></core-user-avatar> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="entry.subject" [contextLevel]="contextLevel" | ||||
|                                 [contextInstanceId]="contextInstanceId"> | ||||
|                             <core-format-text [text]="entry.subject" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"> | ||||
|                             </core-format-text> | ||||
|                             <ion-note class="ion-float-end ion-padding-start ion-text-end"> | ||||
|                                 {{ 'addon.blog.' + entry.publishTranslated! | translate}} | ||||
| @ -68,8 +68,8 @@ | ||||
|                 </ion-card-content> | ||||
|                 <div class="ion-text-center ion-margin-bottom" *ngIf="entry.lastmodified > entry.created"> | ||||
|                     <ion-note> | ||||
|                         <ion-icon name="fas-clock" | ||||
|                             [attr.aria-label]="'core.lastmodified' | translate"></ion-icon> {{entry.lastmodified | coreTimeAgo}} | ||||
|                         <ion-icon name="fas-clock" [attr.aria-label]="'core.lastmodified' | translate"></ion-icon> {{entry.lastmodified | | ||||
|                         coreTimeAgo}} | ||||
|                     </ion-note> | ||||
|                 </div> | ||||
|             </ion-card> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.calendar.reminders' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -36,15 +38,13 @@ | ||||
| 
 | ||||
|             <div class="flex-row"> | ||||
|                 <!-- Input to enter the value. --> | ||||
|                 <ion-input type="number" name="customvalue" [(ngModel)]="customValue" [disabled]="radioValue != 'custom'" | ||||
|                     placeholder="10"> | ||||
|                 <ion-input type="number" name="customvalue" [(ngModel)]="customValue" [disabled]="radioValue != 'custom'" placeholder="10"> | ||||
|                 </ion-input> | ||||
| 
 | ||||
|                 <!-- Units. --> | ||||
|                 <label class="accesshide" for="reminderUnits">{{ 'addon.calendar.units' | translate }}</label> | ||||
|                 <ion-select id="reminderUnits" name="customunits" [(ngModel)]="customUnits" interface="action-sheet" | ||||
|                     [disabled]="radioValue != 'custom'" slot="end" | ||||
|                     [interfaceOptions]="{header: 'addon.calendar.units' | translate}"> | ||||
|                     [disabled]="radioValue != 'custom'" slot="end" [interfaceOptions]="{header: 'addon.calendar.units' | translate}"> | ||||
|                     <ion-select-option *ngFor="let option of customUnitsOptions" [value]="option.value"> | ||||
|                         {{ option.label | translate }} | ||||
|                     </ion-select-option> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.calendar.calendarevents' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon> | ||||
| @ -13,8 +15,8 @@ | ||||
|                     iconAction="fas-calendar-day" (action)="goToCurrentDay()"> | ||||
|                 </core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!loaded || !hasOffline || !isOnline" [priority]="400" | ||||
|                     [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event)" | ||||
|                     [iconAction]="syncIcon" [closeOnClick]="false"> | ||||
|                     [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event)" [iconAction]="syncIcon" | ||||
|                     [closeOnClick]="false"> | ||||
|                 </core-context-menu-item> | ||||
|             </core-context-menu> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ title | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -40,12 +42,8 @@ | ||||
|                     <p class="item-heading" [core-mark-required]="true">{{ 'addon.calendar.eventkind' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <p *ngIf="eventTypes.length == 1" slot="end">{{eventTypes[0].name | translate }}</p> | ||||
|                 <ion-select | ||||
|                     *ngIf="eventTypes.length > 1" | ||||
|                     formControlName="eventtype" | ||||
|                     interface="action-sheet" | ||||
|                     [interfaceOptions]="{header: 'addon.calendar.eventkind' | translate}" | ||||
|                 > | ||||
|                 <ion-select *ngIf="eventTypes.length > 1" formControlName="eventtype" interface="action-sheet" | ||||
|                     [interfaceOptions]="{header: 'addon.calendar.eventkind' | translate}"> | ||||
|                     <ion-select-option *ngFor="let type of eventTypes" [value]="type.value"> | ||||
|                         {{ type.name | translate }} | ||||
|                     </ion-select-option> | ||||
| @ -83,8 +81,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading" [core-mark-required]="true">{{ 'core.course' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-select formControlName="groupcourseid" | ||||
|                         interface="action-sheet" [placeholder]="'core.noselection' | translate" | ||||
|                     <ion-select formControlName="groupcourseid" interface="action-sheet" [placeholder]="'core.noselection' | translate" | ||||
|                         (ionChange)="groupCourseSelected()" [interfaceOptions]="{header: 'core.course' | translate}"> | ||||
|                         <ion-select-option *ngFor="let course of courses" [value]="course.id"> | ||||
|                             {{ course.fullname }} | ||||
| @ -93,7 +90,9 @@ | ||||
|                 </ion-item> | ||||
|                 <!-- The course has no groups. --> | ||||
|                 <ion-item class="ion-text-wrap core-danger-item" *ngIf="!loadingGroups && courseGroupSet && !groups.length"> | ||||
|                     <ion-label><p>{{ 'core.coursenogroups' | translate }}</p></ion-label> | ||||
|                     <ion-label> | ||||
|                         <p>{{ 'core.coursenogroups' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <!-- Select the group. --> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!loadingGroups && groups.length > 0"> | ||||
| @ -128,8 +127,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p>{{ reminder.label }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-button fill="clear" (click)="removeReminder(reminder)" [attr.aria-label]="'core.delete' | translate" | ||||
|                         slot="end"> | ||||
|                     <ion-button fill="clear" (click)="removeReminder(reminder)" [attr.aria-label]="'core.delete' | translate" slot="end"> | ||||
|                         <ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                     </ion-button> | ||||
|                 </ion-item> | ||||
| @ -158,8 +156,7 @@ | ||||
|                     <ion-item *ngIf="form.controls.duration.value === 1"> | ||||
|                         <ion-label position="stacked"></ion-label> | ||||
|                         <ion-datetime formControlName="timedurationuntil" [max]="maxDate" [min]="minDate" | ||||
|                             [placeholder]="'addon.calendar.durationuntil' | translate" | ||||
|                             [displayFormat]="dateFormat" display-timezone="utc"> | ||||
|                             [placeholder]="'addon.calendar.durationuntil' | translate" [displayFormat]="dateFormat" display-timezone="utc"> | ||||
|                         </ion-datetime> | ||||
|                     </ion-item> | ||||
|                     <ion-item lines="none"> | ||||
| @ -171,8 +168,7 @@ | ||||
|                     <ion-item *ngIf="form.controls.duration.value === 2"> | ||||
|                         <ion-label class="sr-only">{{ 'addon.calendar.durationminutes' | translate }}</ion-label> | ||||
|                         <ion-input type="number" name="timedurationminutes" slot="end" | ||||
|                             [placeholder]="'addon.calendar.durationminutes' | translate" | ||||
|                             formControlName="timedurationminutes"></ion-input> | ||||
|                             [placeholder]="'addon.calendar.durationminutes' | translate" formControlName="timedurationminutes"></ion-input> | ||||
|                     </ion-item> | ||||
|                 </ion-radio-group> | ||||
|             </div> | ||||
| @ -223,8 +219,8 @@ | ||||
|                     <p class="item-heading">{{ 'core.description' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <core-rich-text-editor [control]="descriptionControl" [attr.aria-label]="'core.description' | translate" | ||||
|                     [placeholder]="'core.description' | translate" name="description" [component]="component" | ||||
|                     [componentId]="eventId" [autoSave]="false"></core-rich-text-editor> | ||||
|                     [placeholder]="'core.description' | translate" name="description" [component]="component" [componentId]="eventId" | ||||
|                     [autoSave]="false"></core-rich-text-editor> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Location. --> | ||||
|  | ||||
| @ -3,30 +3,31 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="event"> | ||||
|             <core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" [showAlt]="false" | ||||
|                 [modname]="event.modulename" [componentId]="event.instance"></core-mod-icon> | ||||
|                 <core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" [showAlt]="false" [modname]="event.modulename" | ||||
|                     [componentId]="event.instance"></core-mod-icon> | ||||
|                 <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" aria-hidden="true"></ion-icon> | ||||
|                 <!-- Add the icon title so accessibility tools read it. --> | ||||
|                 <span class="sr-only"> | ||||
|                     {{ 'addon.calendar.type' + event.formattedType | translate }} | ||||
|                     <span class="sr-only" *ngIf="event.moduleIcon && event.iconTitle">{{ event.iconTitle }}</span> | ||||
|                 </span> | ||||
|             <core-format-text [text]="event.name" [contextLevel]="event.contextLevel" | ||||
|                 [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                 <core-format-text [text]="event.name" [contextLevel]="event.contextLevel" [contextInstanceId]="event.contextInstanceId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <core-context-menu> | ||||
|                 <core-context-menu-item [hidden]="!eventLoaded || (!hasOffline && event && !event.deleted) || !isOnline" | ||||
|                     [priority]="400" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)" | ||||
|                 <core-context-menu-item [hidden]="!eventLoaded || (!hasOffline && event && !event.deleted) || !isOnline" [priority]="400" | ||||
|                     [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)" | ||||
|                     [iconAction]="syncIcon" [closeOnClick]="false"> | ||||
|                 </core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!event || !event.canedit || event.deleted || (!canEdit && event.id > 0)" | ||||
|                     [priority]="300" [content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-edit"> | ||||
|                 <core-context-menu-item [hidden]="!event || !event.canedit || event.deleted || (!canEdit && event.id > 0)" [priority]="300" | ||||
|                     [content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-edit"> | ||||
|                 </core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!event || !event.candelete || event.deleted" [priority]="200" | ||||
|                     [content]="'core.delete' | translate" (action)="deleteEvent()" | ||||
|                     iconAction="fas-trash"></core-context-menu-item> | ||||
|                     [content]="'core.delete' | translate" (action)="deleteEvent()" iconAction="fas-trash"></core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!event || !event.deleted" [priority]="200" [content]="'core.restore' | translate" | ||||
|                     (action)="undoDelete()" iconAction="fas-undo-alt"></core-context-menu-item> | ||||
|             </core-context-menu> | ||||
| @ -82,8 +83,10 @@ | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="categoryPath"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.category' | translate}}</h2> | ||||
|                         <p><core-format-text [text]="categoryPath" contextLevel="coursecat" | ||||
|                             [contextInstanceId]="event.categoryid"></core-format-text></p> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="categoryPath" contextLevel="coursecat" [contextInstanceId]="event.categoryid"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="event.description"> | ||||
| @ -123,13 +126,12 @@ | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ng-container *ngFor="let reminder of reminders"> | ||||
|                 <ion-item *ngIf="reminder.timestamp > 0" class="ion-text-wrap" | ||||
|                     [class.item-dimmed]="reminder.timestamp <= currentTime"> | ||||
|                 <ion-item *ngIf="reminder.timestamp > 0" class="ion-text-wrap" [class.item-dimmed]="reminder.timestamp <= currentTime"> | ||||
|                     <ion-label> | ||||
|                         <p>{{ reminder.label }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-button fill="clear" (click)="cancelNotification(reminder.id, $event)" | ||||
|                         [attr.aria-label]="'core.delete' | translate" slot="end" *ngIf="reminder.timestamp > currentTime"> | ||||
|                     <ion-button fill="clear" (click)="cancelNotification(reminder.id, $event)" [attr.aria-label]="'core.delete' | translate" | ||||
|                         slot="end" *ngIf="reminder.timestamp > currentTime"> | ||||
|                         <ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                     </ion-button> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -3,20 +3,20 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ (showCalendar ? 'addon.calendar.calendarevents' : 'addon.calendar.upcomingevents') | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="openFilter($event)" [attr.aria-label]="'core.filter' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|             <core-context-menu> | ||||
|                 <core-context-menu-item *ngIf="showCalendar" [priority]="800" | ||||
|                 [content]="'addon.calendar.upcomingevents' | translate" iconAction="fas-th-list" | ||||
|                 (action)="toggleDisplay()"></core-context-menu-item> | ||||
|                 <core-context-menu-item *ngIf="!showCalendar" [priority]="800" | ||||
|                 [content]="'addon.calendar.monthlyview' | translate" iconAction="fas-calendar-alt" | ||||
|                 (action)="toggleDisplay()"></core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600" | ||||
|                 [content]="'core.settings.settings' | translate" (action)="openSettings()" iconAction="fas-cogs"> | ||||
|                 <core-context-menu-item *ngIf="showCalendar" [priority]="800" [content]="'addon.calendar.upcomingevents' | translate" | ||||
|                     iconAction="fas-th-list" (action)="toggleDisplay()"></core-context-menu-item> | ||||
|                 <core-context-menu-item *ngIf="!showCalendar" [priority]="800" [content]="'addon.calendar.monthlyview' | translate" | ||||
|                     iconAction="fas-calendar-alt" (action)="toggleDisplay()"></core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!notificationsEnabled" [priority]="600" [content]="'core.settings.settings' | translate" | ||||
|                     (action)="openSettings()" iconAction="fas-cogs"> | ||||
|                 </core-context-menu-item> | ||||
|                 <core-context-menu-item [hidden]="!loaded || !hasOffline || !isOnline" [priority]="400" | ||||
|                     [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)" | ||||
| @ -43,8 +43,7 @@ | ||||
|         [displayNavButtons]="showCalendar" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)"> | ||||
|     </addon-calendar-calendar> | ||||
| 
 | ||||
|     <addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [filter]="filter" | ||||
|         (onEventClicked)="gotoEvent($event)"> | ||||
|     <addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [filter]="filter" (onEventClicked)="gotoEvent($event)"> | ||||
|     </addon-calendar-upcoming-events> | ||||
| 
 | ||||
|     <!-- Create a calendar event. --> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'core.settings.settings' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ title }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
| @ -3,9 +3,11 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="competency"> | ||||
|                 {{ competency.competency.competency.shortname }} <small>{{ competency.competency.competency.idnumber }}</small> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -16,7 +18,9 @@ | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <core-user-avatar [user]="user" slot="start"></core-user-avatar> | ||||
|                 <ion-label><h2>{{ user.fullname }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ user.fullname }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
| @ -32,11 +36,9 @@ | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
|                     <p> | ||||
|                         <a *ngIf="competency.competency.comppath.showlinks" | ||||
|                             [href]="competency.competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + | ||||
|                         <a *ngIf="competency.competency.comppath.showlinks" [href]="competency.competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + | ||||
|                             competency.competency.comppath.framework.id + '&pagecontextid=' + | ||||
|                             competency.competency.comppath.pagecontextid" | ||||
|                             core-link> | ||||
|                             competency.competency.comppath.pagecontextid" core-link> | ||||
|                             {{ competency.competency.comppath.framework.name }} | ||||
|                         </a> | ||||
|                         <ng-container *ngIf="!competency.competency.comppath.showlinks"> | ||||
| @ -129,7 +131,9 @@ | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label> | ||||
|                         <p><ion-badge color="dark">{{ evidence.gradename }}</ion-badge></p> | ||||
|                         <p> | ||||
|                             <ion-badge color="dark">{{ evidence.gradename }}</ion-badge> | ||||
|                         </p> | ||||
|                         <p class="ion-margin-top" *ngIf="evidence.description">{{ evidence.description }}</p> | ||||
|                         <blockquote *ngIf="evidence.note">{{ evidence.note }}</blockquote> | ||||
|                     </ion-label> | ||||
|  | ||||
| @ -3,9 +3,11 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="competency"> | ||||
|                 {{ competency.competency.shortname }} <small>{{ competency.competency.idnumber }}</small> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.competency.coursecompetencies' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -50,11 +52,13 @@ | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <core-user-avatar [user]="user" slot="start"></core-user-avatar> | ||||
|                <ion-label><h2>{{ user.fullname }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ user.fullname }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|         <core-empty-box *ngIf="competencies && competencies.statistics.competencycount == 0" | ||||
|             icon="fas-award" message="{{ 'addon.competency.nocompetenciesincourse' | translate }}"> | ||||
|         <core-empty-box *ngIf="competencies && competencies.statistics.competencycount == 0" icon="fas-award" | ||||
|             message="{{ 'addon.competency.nocompetenciesincourse' | translate }}"> | ||||
|         </core-empty-box> | ||||
| 
 | ||||
|         <div *ngIf="competencies"> | ||||
| @ -81,10 +85,9 @@ | ||||
|                         <div> | ||||
|                             <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
|                             <p> | ||||
|                                 <a *ngIf="competency.comppath.showlinks" | ||||
|                                     [href]="competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + | ||||
|                                     competency.comppath.framework.id + '&pagecontextid=' + competency.comppath.pagecontextid" | ||||
|                                     core-link [title]="competency.comppath.framework.name"> | ||||
|                                 <a *ngIf="competency.comppath.showlinks" [href]="competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + | ||||
|                                     competency.comppath.framework.id + '&pagecontextid=' + competency.comppath.pagecontextid" core-link | ||||
|                                     [title]="competency.comppath.framework.name"> | ||||
|                                     {{ competency.comppath.framework.name }} | ||||
|                                 </a> | ||||
|                                 <ng-container *ngIf="!competency.comppath.showlinks"> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="plan">{{plan.plan.name}}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -24,8 +26,7 @@ | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="plan.plan.description" lines="none"> | ||||
|                     <ion-label> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="plan.plan.description" contextLevel="user" | ||||
|                                 [contextInstanceId]="plan.plan.userid"> | ||||
|                             <core-format-text [text]="plan.plan.description" contextLevel="user" [contextInstanceId]="plan.plan.userid"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
| @ -74,8 +75,8 @@ | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let competency of plan.competencies" | ||||
|                     (click)="openCompetency(competency.competency.id)" | ||||
|                     [attr.aria-label]="competency.competency.shortname" detail="true" button> | ||||
|                     (click)="openCompetency(competency.competency.id)" [attr.aria-label]="competency.competency.shortname" detail="true" | ||||
|                     button> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></p> | ||||
|                     </ion-label> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.competency.userplans' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -16,8 +18,8 @@ | ||||
| 
 | ||||
|             </core-empty-box> | ||||
|             <ion-list *ngIf="!plans.empty" class="ion-no-margin"> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let plan of plans.items" [attr.aria-label]="plan.name" | ||||
|                     (click)="plans.select(plan)" [attr.aria-current]="plans.getItemAriaCurrent(plan)" button detail="true"> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let plan of plans.items" [attr.aria-label]="plan.name" (click)="plans.select(plan)" | ||||
|                     [attr.aria-current]="plans.getItemAriaCurrent(plan)" button detail="true"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ plan.name }}</p> | ||||
|                         <p *ngIf="plan.duedate > 0"> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.coursecompletion.coursecompletion' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -28,14 +30,18 @@ | ||||
|         </ion-card> | ||||
|         <ion-card *ngIf="completion && tracked"> | ||||
|             <ion-item-divider> | ||||
|                 <ion-label><h2>{{ 'addon.coursecompletion.requiredcriteria' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.coursecompletion.requiredcriteria' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <ion-item class="ion-hide-md-up ion-text-wrap" *ngFor="let criteria of completion.completions"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading"> | ||||
|                         <core-format-text clean="true" [text]="criteria.details.criteria" [filter]="false"></core-format-text> | ||||
|                     </p> | ||||
|                     <p><core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false"></core-format-text></p> | ||||
|                     <p> | ||||
|                         <core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false"></core-format-text> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|                 <strong slot="end">{{ criteria.status }}</strong> | ||||
|             </ion-item> | ||||
| @ -73,7 +79,9 @@ | ||||
|         </ion-card> | ||||
|         <ion-card *ngIf="showSelfComplete && tracked"> | ||||
|             <ion-item-divider> | ||||
|                 <ion-label><h2>{{ 'addon.coursecompletion.manualselfcompletion' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.coursecompletion.manualselfcompletion' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <ion-item> | ||||
|                 <ion-label> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messageoutput_airnotifier.processorsettingsdesc' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -21,10 +23,7 @@ | ||||
|                     <p>{{ device.platform }} {{ device.version }}</p> | ||||
|                 </ion-label> | ||||
|                 <core-button-with-spinner [loading]="device.updating" slot="end"> | ||||
|                     <ion-toggle | ||||
|                         [(ngModel)]="device.enable" | ||||
|                         (ngModelChange)="enableDevice(device, device.enable)" | ||||
|                     > | ||||
|                     <ion-toggle [(ngModel)]="device.enable" (ngModelChange)="enableDevice(device, device.enable)"> | ||||
|                     </ion-toggle> | ||||
|                 </core-button-with-spinner> | ||||
|             </ion-item> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.messages.groupinfo' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
| @ -32,8 +34,8 @@ | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let member of members" | ||||
|             (click)="closeModal(member.id)" detail="true" button> | ||||
|         <ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let member of members" (click)="closeModal(member.id)" | ||||
|             detail="true" button> | ||||
|             <core-user-avatar [user]="member" [linkProfile]="false" [checkOnline]="member.showonlinestatus" slot="start"> | ||||
|             </core-user-avatar> | ||||
|             <ion-label> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.contacts' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -14,9 +16,8 @@ | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
| 
 | ||||
|         <core-search-box (onSubmit)="search($event)" (onClear)="clearSearch()" | ||||
|             [placeholder]="'addon.messages.contactname' | translate" autocorrect="off" spellcheck="false" lengthCheck="2" | ||||
|             [disabled]="!loaded" searchArea="AddonMessagesContacts"></core-search-box> | ||||
|         <core-search-box (onSubmit)="search($event)" (onClear)="clearSearch()" [placeholder]="'addon.messages.contactname' | translate" | ||||
|             autocorrect="off" spellcheck="false" lengthCheck="2" [disabled]="!loaded" searchArea="AddonMessagesContacts"></core-search-box> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded" [message]="loadingMessage"> | ||||
|             <core-empty-box *ngIf="!hasContacts && searchString == ''" icon="fas-address-book" | ||||
| @ -28,17 +29,23 @@ | ||||
|             <ion-list *ngFor="let contactType of contactTypes" class="ion-no-margin"> | ||||
|                 <ng-container *ngIf="contacts[contactType] && (contacts[contactType].length > 0 || contactType === searchType)"> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label><p class="item-heading">{{ 'addon.messages.type_' + contactType | translate }}</p></ion-label> | ||||
|                         <ion-note slot="end" class="ion-padding-end"><ion-badge>{{ contacts[contactType].length }}</ion-badge></ion-note> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ 'addon.messages.type_' + contactType | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-note slot="end" class="ion-padding-end"> | ||||
|                             <ion-badge>{{ contacts[contactType].length }}</ion-badge> | ||||
|                         </ion-note> | ||||
|                     </ion-item-divider> | ||||
|                     <ng-container *ngFor="let contact of contacts[contactType]"> | ||||
|                         <!-- Don't show deleted users --> | ||||
|                         <ion-item class="ion-text-wrap addon-messages-conversation-item" | ||||
|                             *ngIf="contact.profileimageurl || contact.profileimageurlsmall" | ||||
|                             [attr.aria-label]="contact.fullname" (click)="gotoDiscussion(contact.id)" detail="true" button | ||||
|                             *ngIf="contact.profileimageurl || contact.profileimageurlsmall" [attr.aria-label]="contact.fullname" | ||||
|                             (click)="gotoDiscussion(contact.id)" detail="true" button | ||||
|                             [attr.aria-current]="contact.id == discussionUserId ? 'page' : 'false'"> | ||||
|                             <core-user-avatar [user]="contact" slot="start" [checkOnline]="contact.showonlinestatus"></core-user-avatar> | ||||
|                             <ion-label><p class="item-heading">{{ contact.fullname }}</p></ion-label> | ||||
|                             <ion-label> | ||||
|                                 <p class="item-heading">{{ contact.fullname }}</p> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
|                     </ng-container> | ||||
|                 </ng-container> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.contacts' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="gotoSearch()" [attr.aria-label]="'addon.messages.searchcombined' | translate"> | ||||
|                 <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
| @ -26,8 +28,8 @@ | ||||
|                             <ion-item class="ion-text-wrap addon-messages-conversation-item" (click)="selectUser(contact.id)" button | ||||
|                                 *ngFor="let contact of confirmedContacts" [attr.aria-label]="contact.fullname" detail="true" | ||||
|                                 [attr.aria-current]="contact.id == selectedUserId ? 'page' : 'false'"> | ||||
|                                 <core-user-avatar slot="start" [user]="contact" | ||||
|                                     [checkOnline]="contact.showonlinestatus" [linkProfile]="false"> | ||||
|                                 <core-user-avatar slot="start" [user]="contact" [checkOnline]="contact.showonlinestatus" | ||||
|                                     [linkProfile]="false"> | ||||
|                                 </core-user-avatar> | ||||
|                                 <ion-label> | ||||
|                                     <p class="item-heading"> | ||||
| @ -45,8 +47,8 @@ | ||||
|                             [message]="'addon.messages.nocontactsgetstarted' | translate"> | ||||
|                         </core-empty-box> | ||||
| 
 | ||||
|                         <core-infinite-loading [enabled]="confirmedCanLoadMore" (action)="loadMore($event)" | ||||
|                             [error]="confirmedLoadMoreError" position="bottom"> | ||||
|                         <core-infinite-loading [enabled]="confirmedCanLoadMore" (action)="loadMore($event)" [error]="confirmedLoadMoreError" | ||||
|                             position="bottom"> | ||||
|                         </core-infinite-loading> | ||||
|                     </core-loading> | ||||
|                 </ng-template> | ||||
| @ -77,8 +79,8 @@ | ||||
|                         <core-empty-box *ngIf="!requests.length" icon="far-address-book" | ||||
|                             [message]="'addon.messages.nocontactrequests' | translate"> | ||||
|                         </core-empty-box> | ||||
|                         <core-infinite-loading [enabled]="requestsCanLoadMore" (action)="loadMore($event)" | ||||
|                             [error]="requestsLoadMoreError" position="bottom"> | ||||
|                         <core-infinite-loading [enabled]="requestsCanLoadMore" (action)="loadMore($event)" [error]="requestsLoadMoreError" | ||||
|                             position="bottom"> | ||||
|                         </core-infinite-loading> | ||||
|                     </core-loading> | ||||
|                 </ng-template> | ||||
|  | ||||
| @ -3,12 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|             <img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [src]="conversationImage" | ||||
|                 alt="" onError="this.src='assets/img/group-avatar.png'" core-external-content role="presentation" | ||||
|                 [siteId]="siteId || null"> | ||||
|             <core-user-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" [user]="otherMember" | ||||
|                 [linkProfile]="false" [checkOnline]="otherMember.showonlinestatus"> | ||||
|                 <img *ngIf="loaded && !otherMember && conversationImage" class="core-bar-button-image" [src]="conversationImage" alt="" | ||||
|                     onError="this.src='assets/img/group-avatar.png'" core-external-content role="presentation" [siteId]="siteId || null"> | ||||
|                 <core-user-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" [user]="otherMember" [linkProfile]="false" | ||||
|                     [checkOnline]="otherMember.showonlinestatus"> | ||||
|                 </core-user-avatar> | ||||
|                 <core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|                 <ion-icon *ngIf="conversation && conversation.isfavourite" name="fas-star" | ||||
| @ -18,44 +18,41 @@ | ||||
|                     [attr.aria-label]="'addon.messages.mutedconversation' | translate"> | ||||
|                 </ion-icon> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"></ion-buttons> | ||||
|     </ion-toolbar> | ||||
|     <core-navbar-buttons slot="end"> | ||||
|         <core-context-menu [attr.aria-label]="'addon.messages.conversationactions' | translate"> | ||||
|             <core-context-menu-item [hidden]="isSelf || !showInfo || isGroup" [priority]="1000" | ||||
|                 [content]="'addon.messages.info' | translate" (action)="viewInfo()" | ||||
|                 iconAction="fas-info-circle"></core-context-menu-item> | ||||
|                 [content]="'addon.messages.info' | translate" (action)="viewInfo()" iconAction="fas-info-circle"></core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="isSelf || !showInfo || !isGroup" [priority]="1000" | ||||
|                 [content]="'addon.messages.groupinfo' | translate" (action)="viewInfo()" | ||||
|                 iconAction="fas-info-circle"></core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="!groupMessagingEnabled || !conversation" [priority]="800" | ||||
|                 [content]="(conversation && conversation.isfavourite ? 'addon.messages.removefromfavourites' : | ||||
|                 'addon.messages.addtofavourites') | translate" | ||||
|                 (action)="changeFavourite($event)" [closeOnClick]="false" [iconAction]="favouriteIcon" | ||||
|                 [iconSlash]="favouriteIconSlash"></core-context-menu-item> | ||||
|                 [content]="'addon.messages.groupinfo' | translate" (action)="viewInfo()" iconAction="fas-info-circle"> | ||||
|             </core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="!groupMessagingEnabled || !conversation" [priority]="800" [content]="(conversation && conversation.isfavourite ? 'addon.messages.removefromfavourites' : | ||||
|                 'addon.messages.addtofavourites') | translate" (action)="changeFavourite($event)" [closeOnClick]="false" | ||||
|                 [iconAction]="favouriteIcon" [iconSlash]="favouriteIconSlash"></core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="isSelf || !otherMember || otherMember.isblocked" [priority]="700" | ||||
|                 [content]="'addon.messages.blockuser' | translate" (action)="blockUser()" [iconAction]="blockIcon"> | ||||
|             </core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="isSelf || !otherMember || !otherMember.isblocked" [priority]="700" | ||||
|                 [content]="'addon.messages.unblockuser' | translate" (action)="unblockUser()" [iconAction]="blockIcon"> | ||||
|             </core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" | ||||
|                 [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' : | ||||
|             <core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' : | ||||
|                 'addon.messages.muteconversation') | translate" (action)="changeMute($event)" [closeOnClick]="false" | ||||
|                 [iconAction]="muteIcon"></core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="!canDelete || !messages || !messages.length" [priority]="400" | ||||
|                 [content]="'addon.messages.showdeletemessages' | translate" | ||||
|                 iconAction="toggle" [(toggle)]="showDelete"></core-context-menu-item> | ||||
|                 [content]="'addon.messages.showdeletemessages' | translate" iconAction="toggle" [(toggle)]="showDelete"> | ||||
|             </core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="!groupMessagingEnabled || !conversationId || isGroup || !messages || !messages.length" | ||||
|                 [priority]="200" [content]="'addon.messages.deleteconversation' | translate" (action)="deleteConversation($event)" | ||||
|                 [closeOnClick]="false" [iconAction]="deleteIcon"></core-context-menu-item> | ||||
|             <core-context-menu-item | ||||
|                 [hidden]="isSelf || !otherMember || otherMember.iscontact || requestContactSent || requestContactReceived" | ||||
|                 [priority]="100" [content]="'addon.messages.addtoyourcontacts' | translate" (action)="createContactRequest()" | ||||
|                 [iconAction]="addRemoveIcon"></core-context-menu-item> | ||||
|                 [hidden]="isSelf || !otherMember || otherMember.iscontact || requestContactSent || requestContactReceived" [priority]="100" | ||||
|                 [content]="'addon.messages.addtoyourcontacts' | translate" (action)="createContactRequest()" [iconAction]="addRemoveIcon"> | ||||
|             </core-context-menu-item> | ||||
|             <core-context-menu-item [hidden]="isSelf || !otherMember || !otherMember.iscontact" [priority]="100" | ||||
|                 [content]="'addon.messages.removefromyourcontacts' | translate" (action)="removeContact()" | ||||
|                 [iconAction]="addRemoveIcon" [iconSlash]="true"></core-context-menu-item> | ||||
|                 [content]="'addon.messages.removefromyourcontacts' | translate" (action)="removeContact()" [iconAction]="addRemoveIcon" | ||||
|                 [iconSlash]="true"></core-context-menu-item> | ||||
|         </core-context-menu> | ||||
|     </core-navbar-buttons> | ||||
| </ion-header> | ||||
| @ -72,15 +69,13 @@ | ||||
| 
 | ||||
|         <h2 class="sr-only">{{ title }}</h2> | ||||
| 
 | ||||
|         <ion-list class="addon-messages-discussion-container" [class.addon-messages-discussion-group]="isGroup" | ||||
|             [attr.aria-live]="'polite'"> | ||||
|         <ion-list class="addon-messages-discussion-container" [class.addon-messages-discussion-group]="isGroup" [attr.aria-live]="'polite'"> | ||||
|             <ng-container *ngFor="let message of messages; index as index; last as last"> | ||||
|                 <h3 class="ion-text-center addon-messages-date" *ngIf="message.showDate"> | ||||
|                     {{ message.timecreated | coreFormatDate: "strftimedayshort" }} | ||||
|                 </h3> | ||||
| 
 | ||||
|                 <ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" | ||||
|                     color="light"> | ||||
|                 <ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" color="light"> | ||||
|                     <ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label> | ||||
|                     <ion-icon name="fas-arrow-down" aria-hidden="true"></ion-icon> | ||||
|                 </ion-chip> | ||||
| @ -93,8 +88,7 @@ | ||||
|                     <ion-label> | ||||
|                         <!-- User data. --> | ||||
|                         <div *ngIf="message.showUserData" class="item-heading addon-message-user"> | ||||
|                             <core-user-avatar slot="start" [user]="members[message.useridfrom]" [linkProfile]="false" | ||||
|                                 aria-hidden="true"> | ||||
|                             <core-user-avatar slot="start" [user]="members[message.useridfrom]" [linkProfile]="false" aria-hidden="true"> | ||||
|                             </core-user-avatar> | ||||
|                             <div>{{ members[message.useridfrom].fullname }}</div> | ||||
|                         </div> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.messages' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <core-user-menu-button></core-user-menu-button> | ||||
|         </ion-buttons> | ||||
| @ -15,9 +17,9 @@ | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
| 
 | ||||
|         <core-search-box (onSubmit)="searchMessage($event)" (onClear)="clearSearch()" | ||||
|             [placeholder]=" 'addon.messages.message' | translate" autocorrect="off" spellcheck="false" lengthCheck="2" | ||||
|             [disabled]="!loaded" searchArea="AddonMessagesDiscussions" [autoFocus]="false"></core-search-box> | ||||
|         <core-search-box (onSubmit)="searchMessage($event)" (onClear)="clearSearch()" [placeholder]=" 'addon.messages.message' | translate" | ||||
|             autocorrect="off" spellcheck="false" lengthCheck="2" [disabled]="!loaded" searchArea="AddonMessagesDiscussions" | ||||
|             [autoFocus]="false"></core-search-box> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded" [message]="loadingMessage"> | ||||
| 
 | ||||
| @ -26,7 +28,9 @@ | ||||
|                 <ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()" | ||||
|                     [attr.aria-label]="'addon.messages.contacts' | translate" detail="true" button> | ||||
|                     <ion-icon name="fas-address-book" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.messages.contacts' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <ng-container *ngIf="search.showResults"> | ||||
| @ -34,7 +38,9 @@ | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'core.searchresults' | translate }}</h2> | ||||
|                         </ion-label> | ||||
|                         <ion-note slot="end" class="ion-padding-end"><ion-badge>{{ search.results.length }}</ion-badge></ion-note> | ||||
|                         <ion-note slot="end" class="ion-padding-end"> | ||||
|                             <ion-badge>{{ search.results.length }}</ion-badge> | ||||
|                         </ion-note> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let result of search.results" button | ||||
|                         [attr.aria-label]="result.fullname" (click)="gotoDiscussion(result.userid, result.messageid)" | ||||
| @ -42,8 +48,10 @@ | ||||
|                         <core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ result.fullname }}</p> | ||||
|                             <p><core-format-text clean="true" singleLine="true" [text]="result.lastmessage" contextLevel="system" | ||||
|                                 [contextInstanceId]="0"></core-format-text></p> | ||||
|                             <p> | ||||
|                                 <core-format-text clean="true" singleLine="true" [text]="result.lastmessage" contextLevel="system" | ||||
|                                     [contextInstanceId]="0"></core-format-text> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ng-container> | ||||
| @ -67,8 +75,8 @@ | ||||
|                                 </ion-note> | ||||
|                             </div> | ||||
|                             <p> | ||||
|                                 <core-format-text clean="true" singleLine="true" [text]="discussion.message!.message" | ||||
|                                     contextLevel="system" [contextInstanceId]="0"> | ||||
|                                 <core-format-text clean="true" singleLine="true" [text]="discussion.message!.message" contextLevel="system" | ||||
|                                     [contextInstanceId]="0"> | ||||
|                                 </core-format-text> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.messages' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="gotoSearch()" [attr.aria-label]="'addon.messages.searchcombined' | translate"> | ||||
|                 <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
| @ -25,28 +27,25 @@ | ||||
|             <ion-list> | ||||
|                 <ion-item class="ion-text-wrap addon-message-discussion" (click)="gotoContacts()" detail="true" button> | ||||
|                     <ion-icon name="fas-address-book" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label><h2>{{ 'addon.messages.contacts' | translate }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.messages.contacts' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                     <ion-badge *ngIf="contactRequestsCount > 0" slot="end" aria-hidden="true">{{contactRequestsCount}}</ion-badge> | ||||
|                     <span *ngIf="contactRequestsCount > 0" class="sr-only"> | ||||
|                         {{ 'addon.messages.pendingcontactrequests' | translate:{$a: contactRequestsCount} }} | ||||
|                     </span> | ||||
|                 </ion-item> | ||||
|                 <!-- Favourite conversations. --> | ||||
|                 <ion-item | ||||
|                     button | ||||
|                     class="ion-text-wrap divider" | ||||
|                     (click)="toggle(favourites)" | ||||
|                     sticky="true" | ||||
|                 <ion-item button class="ion-text-wrap divider" (click)="toggle(favourites)" sticky="true" | ||||
|                     [attr.aria-label]="(favourites.expanded ? 'core.collapse' : 'core.expand') | translate" | ||||
|                     [attr.aria-expanded]="favourites.expanded" | ||||
|                     aria-controls="addon-messages-groupconversations-favourite" | ||||
|                     role="heading" | ||||
|                     detail="false" | ||||
|                 > | ||||
|                     [attr.aria-expanded]="favourites.expanded" aria-controls="addon-messages-groupconversations-favourite" role="heading" | ||||
|                     detail="false"> | ||||
|                     <ion-icon *ngIf="!favourites.expanded" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"> | ||||
|                     </ion-icon> | ||||
|                     <ion-icon *ngIf="favourites.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label><h2>{{ 'core.favourites' | translate }} ({{ favourites.count }})</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.favourites' | translate }} ({{ favourites.count }})</h2> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" *ngIf="favourites.unread" aria-hidden="true">{{ favourites.unread }}</ion-badge> | ||||
|                     <span *ngIf="favourites.unread" class="sr-only"> | ||||
|                         {{ 'addon.messages.unreadconversations' | translate:{$a: favourites.unread} }} | ||||
| @ -60,28 +59,26 @@ | ||||
|                     <core-infinite-loading [enabled]="favourites.canLoadMore" (action)="loadMoreConversations(favourites, $event)" | ||||
|                         [error]="favourites.loadMoreError"></core-infinite-loading> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="favourites.conversations && favourites.conversations.length == 0"> | ||||
|                         <ion-label><p>{{ 'addon.messages.nofavourites' | translate }}</p></ion-label> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.nofavourites' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-center" *ngIf="favourites.loading"> | ||||
|                     <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <!-- Group conversations. --> | ||||
|                 <ion-item | ||||
|                     button | ||||
|                     class="divider ion-text-wrap" | ||||
|                     (click)="toggle(group)" | ||||
|                     sticky="true" | ||||
|                     [attr.aria-label]="(group.expanded ? 'core.collapse' : 'core.expand') | translate" | ||||
|                     [attr.aria-expanded]="group.expanded" | ||||
|                     aria-controls="addon-messages-groupconversations-group" | ||||
|                     role="heading" | ||||
|                     detail="false" | ||||
|                 > | ||||
|                 <ion-item button class="divider ion-text-wrap" (click)="toggle(group)" sticky="true" | ||||
|                     [attr.aria-label]="(group.expanded ? 'core.collapse' : 'core.expand') | translate" [attr.aria-expanded]="group.expanded" | ||||
|                     aria-controls="addon-messages-groupconversations-group" role="heading" detail="false"> | ||||
|                     <ion-icon *ngIf="!group.expanded" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon *ngIf="group.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label><h2>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</h2> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" *ngIf="group.unread" aria-hidden="true">{{ group.unread }}</ion-badge> | ||||
|                     <span *ngIf="group.unread" class="sr-only"> | ||||
|                         {{ 'addon.messages.unreadconversations' | translate:{$a: group.unread} }} | ||||
| @ -95,24 +92,21 @@ | ||||
|                     <core-infinite-loading [enabled]="group.canLoadMore" (action)="loadMoreConversations(group, $event)" | ||||
|                         [error]="group.loadMoreError"></core-infinite-loading> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="group.conversations && group.conversations.length == 0"> | ||||
|                         <ion-label><p>{{ 'addon.messages.nogroupconversations' | translate }}</p></ion-label> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.nogroupconversations' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-center" *ngIf="group.loading"> | ||||
|                     <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <ion-item | ||||
|                     button | ||||
|                     class="divider ion-text-wrap" | ||||
|                     (click)="toggle(individual)" | ||||
|                     sticky="true" | ||||
|                 <ion-item button class="divider ion-text-wrap" (click)="toggle(individual)" sticky="true" | ||||
|                     [attr.aria-label]="(individual.expanded ? 'core.collapse' : 'core.expand') | translate" | ||||
|                     [attr.aria-expanded]="individual.expanded" | ||||
|                     aria-controls="addon-messages-groupconversations-individual" | ||||
|                     role="heading" | ||||
|                     detail="false" | ||||
|                 > | ||||
|                     [attr.aria-expanded]="individual.expanded" aria-controls="addon-messages-groupconversations-individual" role="heading" | ||||
|                     detail="false"> | ||||
|                     <ion-icon *ngIf="!individual.expanded" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"> | ||||
|                     </ion-icon> | ||||
|                     <ion-icon *ngIf="individual.expanded" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
| @ -132,11 +126,15 @@ | ||||
|                     <core-infinite-loading [enabled]="individual.canLoadMore" (action)="loadMoreConversations(individual, $event)" | ||||
|                         [error]="individual.loadMoreError"></core-infinite-loading> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="individual.conversations && individual.conversations.length == 0"> | ||||
|                         <ion-label><p>{{ 'addon.messages.noindividualconversations' | translate }}</p></ion-label> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.noindividualconversations' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-center" *ngIf="individual.loading"> | ||||
|                     <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|             </ion-list> | ||||
| @ -147,8 +145,7 @@ | ||||
| <!-- Template to render a list of conversations. --> | ||||
| <ng-template #conversationsTemplate let-conversations="conversations"> | ||||
|     <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let conversation of conversations" button detail="false" | ||||
|         [attr.aria-label]="conversation.name" (click)="gotoConversation(conversation.id, conversation.userid)" | ||||
|         [attr.aria-current]="((conversation.id && conversation.id == selectedConversationId) || | ||||
|         [attr.aria-label]="conversation.name" (click)="gotoConversation(conversation.id, conversation.userid)" [attr.aria-current]="((conversation.id && conversation.id == selectedConversationId) || | ||||
|             (conversation.userid && conversation.userid == selectedUserId)) ? 'page': 'false'" | ||||
|         id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}"> | ||||
|         <!-- Group conversation image. --> | ||||
| @ -158,17 +155,17 @@ | ||||
|         </ion-avatar> | ||||
| 
 | ||||
|         <!-- Avatar for individual conversations. --> | ||||
|         <core-user-avatar *ngIf="conversation.type != typeGroup" core-user-avatar [user]="conversation.otherUser" | ||||
|             [linkProfile]="false" [checkOnline]="conversation.showonlinestatus" slot="start"></core-user-avatar> | ||||
|         <core-user-avatar *ngIf="conversation.type != typeGroup" core-user-avatar [user]="conversation.otherUser" [linkProfile]="false" | ||||
|             [checkOnline]="conversation.showonlinestatus" slot="start"></core-user-avatar> | ||||
| 
 | ||||
|         <ion-label> | ||||
|             <div class="flex-row ion-justify-content-between"> | ||||
|                 <p class="item-heading"> | ||||
|                     <core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|                     <ion-icon name="fas-user-slash" *ngIf="conversation.isblocked" | ||||
|                         [title]="'addon.messages.contactblocked' | translate"></ion-icon> | ||||
|                     <ion-icon *ngIf="conversation.ismuted" name="fas-volume-mute" | ||||
|                         [title]="'addon.messages.mutedconversation' | translate"></ion-icon> | ||||
|                     <ion-icon name="fas-user-slash" *ngIf="conversation.isblocked" [title]="'addon.messages.contactblocked' | translate"> | ||||
|                     </ion-icon> | ||||
|                     <ion-icon *ngIf="conversation.ismuted" name="fas-volume-mute" [title]="'addon.messages.mutedconversation' | translate"> | ||||
|                     </ion-icon> | ||||
|                 </p> | ||||
|                 <ion-note *ngIf="conversation.lastmessagedate > 0 || conversation.unreadcount"> | ||||
|                     <span *ngIf="conversation.lastmessagedate > 0" class="addon-message-last-message-date"> | ||||
| @ -180,16 +177,17 @@ | ||||
|                     </span> | ||||
|                 </ion-note> | ||||
|             </div> | ||||
|             <p *ngIf="conversation.subname"><core-format-text [text]="conversation.subname" contextLevel="system" | ||||
|                 [contextInstanceId]="0"></core-format-text></p> | ||||
|             <p *ngIf="conversation.subname"> | ||||
|                 <core-format-text [text]="conversation.subname" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|             </p> | ||||
|             <p class="addon-message-last-message"> | ||||
|                 <span *ngIf="conversation.sentfromcurrentuser" class="addon-message-last-message-user"> | ||||
|                     {{ 'addon.messages.you' | translate }} | ||||
|                 </span> | ||||
|                 <span *ngIf="!conversation.sentfromcurrentuser && conversation.type == typeGroup && conversation.members[0]" | ||||
|                     class="addon-message-last-message-user">{{ conversation.members[0].fullname + ':' }}</span> | ||||
|                 <core-format-text clean="true" singleLine="true" [text]="conversation.lastmessage" | ||||
|                     class="addon-message-last-message-text" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|                 <core-format-text clean="true" singleLine="true" [text]="conversation.lastmessage" class="addon-message-last-message-text" | ||||
|                     contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|             </p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.searchcombined' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -23,8 +25,7 @@ | ||||
|                     [error]="messages.loadMoreError"></core-infinite-loading> | ||||
|             </ion-list> | ||||
| 
 | ||||
|             <core-empty-box | ||||
|                 *ngIf="displayResults && !contacts.results.length && !nonContacts.results.length && !messages.results.length" | ||||
|             <core-empty-box *ngIf="displayResults && !contacts.results.length && !nonContacts.results.length && !messages.results.length" | ||||
|                 icon="fas-search" [message]="'core.noresults' | translate"> | ||||
|             </core-empty-box> | ||||
|         </core-loading> | ||||
| @ -35,20 +36,20 @@ | ||||
| <ng-template #resultsTemplate let-item="item"> | ||||
|     <ng-container *ngIf="item.results.length > 0"> | ||||
|         <ion-item-divider class="ion-text-wrap"> | ||||
|             <ion-label><h2>{{ item.titleString | translate }}</h2></ion-label> | ||||
|             <ion-label> | ||||
|                 <h2>{{ item.titleString | translate }}</h2> | ||||
|             </ion-label> | ||||
|         </ion-item-divider> | ||||
| 
 | ||||
|         <!-- List of results --> | ||||
|         <ion-item class="addon-message-discussion ion-text-wrap" *ngFor="let result of item.results" [attr.aria-label]="result.fullname" | ||||
|             (click)="openConversation(result)" [attr.aria-current]="result == selectedResult ? 'page' : 'false'" detail="true" | ||||
|             button> | ||||
|             (click)="openConversation(result)" [attr.aria-current]="result == selectedResult ? 'page' : 'false'" detail="true" button> | ||||
|             <core-user-avatar slot="start" [user]="result" [checkOnline]="true" [linkProfile]="false"></core-user-avatar> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading"> | ||||
|                     <core-format-text [text]="result.fullname" [highlight]="result.highlightName" [filter]="false"> | ||||
|                     </core-format-text> | ||||
|                     <ion-icon name="fas-ban" *ngIf="result.isblocked" | ||||
|                         [attr.aria-label]="'addon.messages.contactblocked' | translate"> | ||||
|                     <ion-icon name="fas-ban" *ngIf="result.isblocked" [attr.aria-label]="'addon.messages.contactblocked' | translate"> | ||||
|                     </ion-icon> | ||||
|                 </p> | ||||
|                 <ion-note *ngIf="result.lastmessagedate > 0"> | ||||
| @ -58,9 +59,8 @@ | ||||
|                     <span *ngIf="result.sentfromcurrentuser" class="addon-message-last-message-user"> | ||||
|                         {{ 'addon.messages.you' | translate }} | ||||
|                     </span> | ||||
|                     <core-format-text clean="true" singleLine="true" [text]="result.lastmessage" | ||||
|                         [highlight]="result.highlightMessage" contextLevel="system" [contextInstanceId]="0" | ||||
|                         class="addon-message-last-message-text"></core-format-text> | ||||
|                     <core-format-text clean="true" singleLine="true" [text]="result.lastmessage" [highlight]="result.highlightMessage" | ||||
|                         contextLevel="system" [contextInstanceId]="0" class="addon-message-last-message-text"></core-format-text> | ||||
|                 </p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.messages' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -22,7 +24,9 @@ | ||||
|             <ion-list *ngIf="advancedContactable" class="ion-text-wrap"> | ||||
|                 <ion-radio-group [(ngModel)]="contactablePrivacy" (ionChange)="saveContactablePrivacy(contactablePrivacy)"> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label><h2>{{ 'addon.messages.contactableprivacy' | translate }}</h2></ion-label> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.messages.contactableprivacy' | translate }}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item> | ||||
|                         <ion-label>{{ 'addon.messages.contactableprivacy_onlycontacts' | translate }}</ion-label> | ||||
| @ -66,16 +70,9 @@ | ||||
|                         <ng-container *ngIf="groupMessagingEnabled"> | ||||
|                             <ion-item class="ion-text-wrap"> | ||||
|                                 <ion-label>{{ processor.displayname }}</ion-label> | ||||
|                                 <core-button-with-spinner | ||||
|                                     *ngIf="!preferences.disableall" | ||||
|                                     [loading]="!!notification.updating" | ||||
|                                     slot="end" | ||||
|                                 > | ||||
|                                     <ion-toggle | ||||
|                                         *ngIf="!processor.locked" | ||||
|                                         [(ngModel)]="processor.checked" | ||||
|                                         (ngModelChange)="changePreference(notification, '', processor)" | ||||
|                                     > | ||||
|                                 <core-button-with-spinner *ngIf="!preferences.disableall" [loading]="!!notification.updating" slot="end"> | ||||
|                                     <ion-toggle *ngIf="!processor.locked" [(ngModel)]="processor.checked" | ||||
|                                         (ngModelChange)="changePreference(notification, '', processor)"> | ||||
|                                     </ion-toggle> | ||||
|                                     <ion-note *ngIf="processor.locked"> | ||||
|                                         {{ processor.lockedmessage }} | ||||
| @ -92,15 +89,11 @@ | ||||
|                             <ion-row class="ion-text-wrap ion-hide-md-down ion-align-items-center"> | ||||
|                                 <ion-col class="ion-margin-horizontal">{{ processor.displayname }}</ion-col> | ||||
|                                 <ion-col size="2" class="ion-text-center" *ngFor="let state of ['loggedin', 'loggedoff']"> | ||||
|                                     <core-button-with-spinner | ||||
|                                         *ngIf="!preferences.disableall" | ||||
|                                         [loading]="notification.updating && notification.updating[state]" | ||||
|                                     > | ||||
|                                     <core-button-with-spinner *ngIf="!preferences.disableall" | ||||
|                                         [loading]="notification.updating && notification.updating[state]"> | ||||
|                                         <!-- If notifications not disabled, show toggle. --> | ||||
|                                         <ion-toggle *ngIf="!processor.locked" | ||||
|                                             [(ngModel)]="processor[state].checked" | ||||
|                                             (ngModelChange)="changePreference(notification, state, processor)" | ||||
|                                         > | ||||
|                                         <ion-toggle *ngIf="!processor.locked" [(ngModel)]="processor[state].checked" | ||||
|                                             (ngModelChange)="changePreference(notification, state, processor)"> | ||||
|                                         </ion-toggle> | ||||
|                                         <div class="ion-padding text-gray" *ngIf="processor.locked"> | ||||
|                                             {{'core.settings.locked' | translate }} | ||||
| @ -118,14 +111,10 @@ | ||||
|                                 If notifications are disabled, show "Disabled" instead of toggle. --> | ||||
|                             <ion-item *ngFor="let state of ['loggedin', 'loggedoff']" class="ion-text-wrap ion-hide-md-up"> | ||||
|                                 <ion-label>{{ 'core.settings.' + state | translate }}</ion-label> | ||||
|                                 <core-button-with-spinner slot="end" | ||||
|                                     *ngIf="!preferences.disableall" | ||||
|                                     [loading]="notification.updating && notification.updating[state]" | ||||
|                                 > | ||||
|                                     <ion-toggle *ngIf="!processor.locked" | ||||
|                                         [(ngModel)]="processor[state].checked" | ||||
|                                         (ngModelChange)="changePreference(notification, state, processor)" | ||||
|                                     > | ||||
|                                 <core-button-with-spinner slot="end" *ngIf="!preferences.disableall" | ||||
|                                     [loading]="notification.updating && notification.updating[state]"> | ||||
|                                     <ion-toggle *ngIf="!processor.locked" [(ngModel)]="processor[state].checked" | ||||
|                                         (ngModelChange)="changePreference(notification, state, processor)"> | ||||
|                                     </ion-toggle> | ||||
|                                     <ion-note *ngIf="processor.locked"> | ||||
|                                         {{'core.settings.locked' | translate }} | ||||
| @ -144,7 +133,11 @@ | ||||
|         <!-- General settings. --> | ||||
|         <ion-card> | ||||
|             <ion-list class="ion-text-wrap"> | ||||
|                 <ion-item-divider><ion-label><h2>{{ 'core.settings.general' | translate }}</h2></ion-label></ion-item-divider> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.settings.general' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ 'addon.messages.useentertosend' | translate }}</p> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ plugin.name }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -10,8 +12,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <form name="addon-mod_assign-edit-feedback-form" *ngIf="userId && plugin" #editFeedbackForm> | ||||
|         <addon-mod-assign-feedback-plugin [assign]="assign" [submission]="submission" [userId]="userId" | ||||
|             [plugin]="plugin" [edit]="true"> | ||||
|         <addon-mod-assign-feedback-plugin [assign]="assign" [submission]="submission" [userId]="userId" [plugin]="plugin" [edit]="true"> | ||||
|         </addon-mod-assign-feedback-plugin> | ||||
|         <ion-button expand="block" (click)="done($event)">{{ 'core.done' | translate }}</ion-button> | ||||
|     </form> | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| 
 | ||||
| <core-dynamic-component [component]="pluginComponent" [data]="data"> | ||||
|     <!-- This content will be replaced by the component if found. --> | ||||
|     <core-loading [hideUntil]="pluginLoaded"> | ||||
| @ -9,9 +8,8 @@ | ||||
|                     {{ 'addon.mod_assign.feedbacknotsupported' | translate }} | ||||
|                 </ion-badge> | ||||
|                 <p *ngIf="text"> | ||||
|                     <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" | ||||
|                         [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" | ||||
|                         [courseId]="assign.course"> | ||||
|                     <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="120" [text]="text" | ||||
|                         contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|                     </core-format-text> | ||||
|                 </p> | ||||
|                 <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" | ||||
|  | ||||
| @ -1,15 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="assign && (description || (assign.introattachments && assign.introattachments.length))" | ||||
|             [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" | ||||
|             iconAction="fas-arrow-right"> | ||||
|             [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -31,34 +30,13 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <!-- Description and intro attachments. --> | ||||
|     <ion-card *ngIf="description"> | ||||
|         <ion-item class="ion-text-wrap"> | ||||
|             <ion-label> | ||||
|                 <core-format-text [text]="description" [component]="component" [componentId]="componentId" maxHeight="120" | ||||
|                     contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" | ||||
|                     (onClick)="expandDescription($event)"> | ||||
|                 </core-format-text> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <ion-card *ngIf="assign && assign.introattachments && assign.introattachments.length"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> | ||||
|         <ion-list inset="true" description *ngIf="assign && assign.introattachments && assign.introattachments.length"> | ||||
|             <core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId"> | ||||
|             </core-file> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <!-- Assign has something offline. --> | ||||
|     <ion-card class="core-warning-card" *ngIf="hasOffline"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
|         </ion-list> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <!-- User can view all submissions (teacher). --> | ||||
|     <ng-container *ngIf="assign && canViewAllSubmissions"> | ||||
| @ -90,8 +68,7 @@ | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Summary of all submissions. --> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="summary && summary.participantcount" (click)="goToSubmissionList()" detail="true" | ||||
|                 button> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="summary && summary.participantcount" (click)="goToSubmissionList()" detail="true" button> | ||||
|                 <ion-label> | ||||
|                     <h2 *ngIf="assign.teamsubmission">{{ 'addon.mod_assign.numberofteams' | translate }}</h2> | ||||
|                     <h2 *ngIf="!assign.teamsubmission">{{ 'addon.mod_assign.numberofparticipants' | translate }}</h2> | ||||
| @ -109,11 +86,11 @@ | ||||
| 
 | ||||
|             <!-- Summary of submissions with draft status. --> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="assign.submissiondrafts && summary && summary.submissionsenabled" | ||||
|                 [class.hide-detail]="!summary.submissiondraftscount" | ||||
|                 detail="true" | ||||
|                 [button]="summary.submissiondraftscount" | ||||
|                 [class.hide-detail]="!summary.submissiondraftscount" detail="true" [button]="summary.submissiondraftscount" | ||||
|                 (click)="goToSubmissionList(submissionStatusDraft, !!summary.submissiondraftscount)"> | ||||
|                 <ion-label><h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_assign.numberofdraftsubmissions' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|                 <ion-badge slot="end" color="primary"> | ||||
|                     <span aria-hidden="true">{{ summary.submissiondraftscount }}</span> | ||||
|                     <span class="sr-only"> | ||||
| @ -125,11 +102,11 @@ | ||||
| 
 | ||||
|             <!-- Summary of submissions with submitted status. --> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled" | ||||
|                 [class.hide-detail]="!summary.submissionssubmittedcount" | ||||
|                 detail="true" | ||||
|                 [button]="summary.submissionssubmittedcount" | ||||
|                 [class.hide-detail]="!summary.submissionssubmittedcount" detail="true" [button]="summary.submissionssubmittedcount" | ||||
|                 (click)="goToSubmissionList(submissionStatusSubmitted, !!summary.submissionssubmittedcount)"> | ||||
|                 <ion-label><h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_assign.numberofsubmittedassignments' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|                 <ion-badge slot="end" color="primary"> | ||||
|                     <span aria-hidden="true">{{ summary.submissionssubmittedcount }}</span> | ||||
|                     <span class="sr-only"> | ||||
| @ -141,11 +118,11 @@ | ||||
| 
 | ||||
|             <!-- Summary of submissions that need grading. --> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="summary && summary.submissionsenabled && !assign.teamsubmission" | ||||
|                 [class.hide-detail]="!needsGradingAvailable" | ||||
|                 detail="true" | ||||
|                 [button]="needsGradingAvailable" | ||||
|                 [class.hide-detail]="!needsGradingAvailable" detail="true" [button]="needsGradingAvailable" | ||||
|                 (click)="goToSubmissionList(needGrading, needsGradingAvailable)"> | ||||
|                 <ion-label><h2>{{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_assign.numberofsubmissionsneedgrading' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|                 <ion-badge slot="end" color="primary"> | ||||
|                     <span aria-hidden="true">{{ summary.submissionsneedgradingcount }}</span> | ||||
|                     <span class="sr-only"> | ||||
|  | ||||
| @ -1,4 +1,3 @@ | ||||
| 
 | ||||
| <core-dynamic-component [component]="pluginComponent" [data]="data"> | ||||
|     <!-- This content will be replaced by the component if found. --> | ||||
|     <core-loading [hideUntil]="pluginLoaded"> | ||||
| @ -9,9 +8,8 @@ | ||||
|                     {{ 'addon.mod_assign.submissionnotsupported' | translate }} | ||||
|                 </ion-badge> | ||||
|                 <p *ngIf="text"> | ||||
|                     <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" | ||||
|                         [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" | ||||
|                         [courseId]="assign.course"> | ||||
|                     <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="120" [text]="text" | ||||
|                         contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|                     </core-format-text> | ||||
|                 </p> | ||||
|                 <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" | ||||
|  | ||||
| @ -3,16 +3,14 @@ | ||||
|     <ion-label> | ||||
|         <h2>{{ plugin.name }}</h2> | ||||
|         <p> | ||||
|             <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" | ||||
|                 [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" | ||||
|                 [courseId]="assign.course"> | ||||
|             <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="120" [text]="text" contextLevel="module" | ||||
|                 [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|             </core-format-text> | ||||
|         </p> | ||||
|     </ion-label> | ||||
|     <div slot="end"> | ||||
|         <div class="ion-text-end"> | ||||
|             <ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" color="dark" | ||||
|                 [attr.aria-label]="'core.edit' | translate"> | ||||
|             <ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" color="dark" [attr.aria-label]="'core.edit' | translate"> | ||||
|                 <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|         </div> | ||||
| @ -25,9 +23,8 @@ | ||||
| <!-- Edit --> | ||||
| <ion-item class="ion-text-wrap" *ngIf="edit && loaded"> | ||||
|     <ion-label class="sr-only">{{ plugin.name }}</ion-label> | ||||
|     <core-rich-text-editor [control]="control" [placeholder]="plugin.name" | ||||
|         name="assignfeedbackcomments_editor" [component]="component" [componentId]="assign.cmid" [autoSave]="true" | ||||
|         contextLevel="module" [contextInstanceId]="assign.cmid" elementId="assignfeedbackcomments_editor" | ||||
|         [draftExtraParams]="{userid: userId, action: 'grade'}"> | ||||
|     <core-rich-text-editor [control]="control" [placeholder]="plugin.name" name="assignfeedbackcomments_editor" [component]="component" | ||||
|         [componentId]="assign.cmid" [autoSave]="true" contextLevel="module" [contextInstanceId]="assign.cmid" | ||||
|         elementId="assignfeedbackcomments_editor" [draftExtraParams]="{userid: userId, action: 'grade'}"> | ||||
|     </core-rich-text-editor> | ||||
| </ion-item> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="save()"> | ||||
|                 {{ 'core.save' | translate }} | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"></ion-buttons> | ||||
|     </ion-toolbar> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"></ion-buttons> | ||||
|     </ion-toolbar> | ||||
|  | ||||
| @ -4,9 +4,8 @@ | ||||
|         <h2>{{ plugin.name }}</h2> | ||||
|         <p *ngIf="words">{{ 'addon.mod_assign.numwords' | translate: {'$a': words} }}</p> | ||||
|         <p> | ||||
|             <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="80" [fullOnClick]="true" | ||||
|                 [fullTitle]="plugin.name" [text]="text" contextLevel="module" [contextInstanceId]="assign.cmid" | ||||
|                 [courseId]="assign.course"> | ||||
|             <core-format-text [component]="component" [componentId]="assign.cmid" [maxHeight]="120" [text]="text" contextLevel="module" | ||||
|                 [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|             </core-format-text> | ||||
|         </p> | ||||
|     </ion-label> | ||||
| @ -15,7 +14,9 @@ | ||||
| <!-- Edit --> | ||||
| <div *ngIf="edit && loaded"> | ||||
|     <ion-item-divider class="ion-text-wrap" sticky="true"> | ||||
|         <ion-label><h2>{{ plugin.name }}</h2></ion-label> | ||||
|         <ion-label> | ||||
|             <h2>{{ plugin.name }}</h2> | ||||
|         </ion-label> | ||||
|     </ion-item-divider> | ||||
|     <ion-item class="ion-text-wrap" *ngIf="wordLimitEnabled && words >= 0"> | ||||
|         <ion-label> | ||||
| @ -25,10 +26,10 @@ | ||||
|     </ion-item> | ||||
|     <ion-item class="ion-text-wrap"> | ||||
|         <ion-label class="sr-only">{{ plugin.name }}</ion-label> | ||||
|         <core-rich-text-editor [control]="control" [placeholder]="plugin.name" | ||||
|             name="onlinetext_editor_text" (contentChanged)="onChange($event)" [component]="component" | ||||
|             [componentId]="assign.cmid" [autoSave]="true" contextLevel="module" [contextInstanceId]="assign.cmid" | ||||
|             elementId="onlinetext_editor" [draftExtraParams]="{userid: currentUserId, action: 'editsubmission'}"> | ||||
|         <core-rich-text-editor [control]="control" [placeholder]="plugin.name" name="onlinetext_editor_text" | ||||
|             (contentChanged)="onChange($event)" [component]="component" [componentId]="assign.cmid" [autoSave]="true" contextLevel="module" | ||||
|             [contextInstanceId]="assign.cmid" elementId="onlinetext_editor" | ||||
|             [draftExtraParams]="{userid: currentUserId, action: 'editsubmission'}"> | ||||
|         </core-rich-text-editor> | ||||
|     </ion-item> | ||||
| </div> | ||||
|  | ||||
| @ -4,12 +4,12 @@ | ||||
|         <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"></core-context-menu-item> | ||||
|         <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" | ||||
|             [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" | ||||
| @ -24,13 +24,10 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"></core-course-module-description> | ||||
| 
 | ||||
|     <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
| @ -39,9 +36,8 @@ | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <div class="ion-padding safe-area-padding-horizontal"> | ||||
|         <core-navigation-bar *ngIf="displayNavBar" [previous]="previousChapter?.id" | ||||
|             [previousTitle]="previousNavBarTitle" [next]="nextChapter?.id" [nextTitle]="nextNavBarTitle" | ||||
|             (action)="changeChapter($event)"> | ||||
|         <core-navigation-bar *ngIf="displayNavBar" [previous]="previousChapter?.id" [previousTitle]="previousNavBarTitle" | ||||
|             [next]="nextChapter?.id" [nextTitle]="nextNavBarTitle" (action)="changeChapter($event)"> | ||||
|         </core-navigation-bar> | ||||
| 
 | ||||
|         <core-format-text [component]="component" [componentId]="componentId" [text]="chapterContent" contextLevel="module" | ||||
| @ -51,9 +47,8 @@ | ||||
|             <core-tag-list [tags]="tags"></core-tag-list> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-navigation-bar *ngIf="displayNavBar" [previous]="previousChapter?.id" | ||||
|             [previousTitle]="previousNavBarTitle" [next]="nextChapter?.id" [nextTitle]="nextNavBarTitle" | ||||
|             (action)="changeChapter($event)"></core-navigation-bar> | ||||
|         <core-navigation-bar *ngIf="displayNavBar" [previous]="previousChapter?.id" [previousTitle]="previousNavBarTitle" | ||||
|             [next]="nextChapter?.id" [nextTitle]="nextNavBarTitle" (action)="changeChapter($event)"></core-navigation-bar> | ||||
|     </div> | ||||
| 
 | ||||
| </core-loading> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <h1>{{ 'addon.mod_book.toc' | translate }}</h1> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.mod_book.toc' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-times" slot="icon-only" aria-hidden=true></ion-icon> | ||||
| @ -12,14 +14,12 @@ | ||||
|     <nav> | ||||
|         <ion-list> | ||||
|             <ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)" | ||||
|                 [attr.aria-current]="selected == chapter.id ? 'page' : 'false'" button | ||||
|                 [class.item-dimmed]="chapter.hidden" detail="false"> | ||||
|                 [attr.aria-current]="selected == chapter.id ? 'page' : 'false'" button [class.item-dimmed]="chapter.hidden" detail="false"> | ||||
|                 <ion-label> | ||||
|                     <p [class.ion-padding-start]="addPadding && chapter.level == 1 ? true : null" class="item-heading"> | ||||
|                         <span *ngIf="showNumbers" class="addon-mod-book-number">{{chapter.indexNumber}} </span> | ||||
|                         <span *ngIf="showBullets" class="addon-mod-book-bullet">• </span> | ||||
|                         <core-format-text [text]="chapter.title" contextLevel="module" [contextInstanceId]="moduleId" | ||||
|                             [courseId]="courseId"> | ||||
|                         <core-format-text [text]="chapter.title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
| @ -17,7 +19,6 @@ | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-book-index [module]="module" [courseId]="courseId" [initialChapterId]="chapterId" | ||||
|         (dataRetrieved)="updateData($event)"> | ||||
|     <addon-mod-book-index [module]="module" [courseId]="courseId" [initialChapterId]="chapterId" (dataRetrieved)="updateData($event)"> | ||||
|     </addon-mod-book-index> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -27,14 +27,10 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <ion-card *ngIf="chatInfo" class="core-info-card"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-clock" slot="start" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -1,9 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.mod_chat.currentusers' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -13,8 +12,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-loading [hideUntil]="usersLoaded"> | ||||
|         <ion-item class="ion-text-wrap" *ngFor="let user of users" | ||||
|             [class.addon-mod-chat-user]="currentUserId != user.id && isOnline"> | ||||
|         <ion-item class="ion-text-wrap" *ngFor="let user of users" [class.addon-mod-chat-user]="currentUserId != user.id && isOnline"> | ||||
| 
 | ||||
|             <core-user-avatar [user]="user" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|             <ion-label> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" *ngIf="loaded" (click)="showChatUsers()" [attr.aria-label]="'core.users' | translate"> | ||||
|                 <ion-icon name="fas-users" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
| @ -81,8 +83,7 @@ | ||||
| 
 | ||||
|                 <ion-item *ngIf="!message.special" class="ion-text-wrap addon-message" | ||||
|                     [class.addon-message-mine]="message.userid == currentUserId" | ||||
|                     [class.addon-message-not-mine]="message.userid != currentUserId" | ||||
|                     [class.addon-message-no-user]="!message.showUserData" | ||||
|                     [class.addon-message-not-mine]="message.userid != currentUserId" [class.addon-message-no-user]="!message.showUserData" | ||||
|                     [@coreSlideInOut]="message.userid == currentUserId ? '' : 'fromLeft'"> | ||||
|                     <ion-label> | ||||
|                         <!-- User data. --> | ||||
| @ -104,8 +105,7 @@ | ||||
|             </ng-container> | ||||
|         </ion-list> | ||||
| 
 | ||||
|         <core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments" | ||||
|             [message]="'addon.mod_chat.nomessages' | translate"> | ||||
|         <core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments" [message]="'addon.mod_chat.nomessages' | translate"> | ||||
|         </core-empty-box> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_chat.messages' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -75,8 +77,7 @@ | ||||
| 
 | ||||
|                 <ion-item *ngIf="!message.special" class="ion-text-wrap addon-message" | ||||
|                     [class.addon-message-mine]="message.userid == currentUserId" | ||||
|                     [class.addon-message-not-mine]="message.userid != currentUserId" | ||||
|                     [class.addon-message-no-user]="!message.showUserData"> | ||||
|                     [class.addon-message-not-mine]="message.userid != currentUserId" [class.addon-message-no-user]="!message.showUserData"> | ||||
|                     <ion-label> | ||||
|                         <!-- User data. --> | ||||
|                         <h2 class="addon-message-user"> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_chat.chatreport' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -29,14 +29,10 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <!-- Activity availability messages --> | ||||
|     <ion-card class="core-info-card" *ngIf="choiceNotOpenYet"> | ||||
|         <ion-item> | ||||
| @ -54,8 +50,7 @@ | ||||
|             <ion-label> | ||||
|                 <p *ngIf="options.length"> | ||||
|                     {{ 'addon.mod_choice.yourselection' | translate }} | ||||
|                     <core-format-text [text]="options[0].text" contextLevel="module" [contextInstanceId]="module.id" | ||||
|                         [courseId]="courseId"> | ||||
|                     <core-format-text [text]="options[0].text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                 </p> | ||||
|                 <p>{{ 'addon.mod_choice.expired' | translate:{$a: closeTimeReadable} }}</p> | ||||
| @ -63,14 +58,6 @@ | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <!-- Choice done in offline but not synchronized --> | ||||
|     <ion-card class="core-warning-card" *ngIf="hasOffline"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <!-- Inform what will happen with the choices. --> | ||||
|     <ion-card class="core-info-card" *ngIf="canEdit && publishInfo && options.length"> | ||||
|         <ion-item> | ||||
| @ -145,10 +132,12 @@ | ||||
|                                 </p> | ||||
|                             </ion-label> | ||||
|                         </ion-item-divider> | ||||
|                         <ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseId" | ||||
|                             [userId]="user.userid" [attr.aria-label]="user.fullname" class="ion-text-wrap"> | ||||
|                         <ion-item *ngFor="let user of result.userresponses" core-user-link [courseId]="courseId" [userId]="user.userid" | ||||
|                             [attr.aria-label]="user.fullname" class="ion-text-wrap"> | ||||
|                             <core-user-avatar [user]="user" slot="start" [courseId]="courseId"></core-user-avatar> | ||||
|                             <ion-label><p>{{user.fullname}}</p></ion-label> | ||||
|                             <ion-label> | ||||
|                                 <p>{{user.fullname}}</p> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
|                     </ion-item-group> | ||||
|                 </ion-col> | ||||
| @ -159,7 +148,9 @@ | ||||
|     <ion-card class="core-info-card" *ngIf="!canSeeResults && !choiceNotOpenYet"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-label><p>{{ 'addon.mod_choice.noresultsviewable' | translate }}</p></ion-label> | ||||
|             <ion-label> | ||||
|                 <p>{{ 'addon.mod_choice.noresultsviewable' | translate }}</p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| </core-loading> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -4,28 +4,27 @@ | ||||
|         <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !(hasOffline || hasOfflineRatings) && isOnline" [priority]="700" | ||||
|             [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" | ||||
|             [closeOnClick]="false"> | ||||
|             [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && (hasOffline || hasOfflineRatings) && isOnline" [priority]="600" | ||||
|             [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" | ||||
|             [closeOnClick]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [priority]="500" *ngIf="canAdd" [content]="'addon.mod_data.addentries' | translate" | ||||
|             iconAction="fas-plus" (action)="gotoAddEntries()"> | ||||
|         <core-context-menu-item [priority]="500" *ngIf="canAdd" [content]="'addon.mod_data.addentries' | translate" iconAction="fas-plus" | ||||
|             (action)="gotoAddEntries()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [priority]="400" *ngIf="firstEntry" [content]="'addon.mod_data.single' | translate" | ||||
|             iconAction="fas-file" (action)="gotoEntry(firstEntry)"> | ||||
|         <core-context-menu-item [priority]="400" *ngIf="firstEntry" [content]="'addon.mod_data.single' | translate" iconAction="fas-file" | ||||
|             (action)="gotoEntry(firstEntry)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="300" [content]="prefetchText" (action)="prefetch($event)" | ||||
|             [iconAction]="prefetchStatusIcon" [closeOnClick]="false"> | ||||
| @ -40,22 +39,10 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <!-- Data done in offline but not synchronized --> | ||||
|     <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <ion-item class="ion-text-wrap" *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)"> | ||||
|         <ion-label id="addon-data-groupslabel"> | ||||
|             <ng-container *ngIf="groupInfo.separateGroups">{{'core.groupsseparate' | translate }}</ng-container> | ||||
|  | ||||
| @ -1,9 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.mod_data.search' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-times" slot="icon-only" aria-hidden=true></ion-icon> | ||||
| @ -20,14 +19,14 @@ | ||||
|         <ion-list class="ion-no-margin"> | ||||
|             <ion-item [hidden]="search.searchingAdvanced"> | ||||
|                 <ion-label class="sr-only">{{ 'addon.mod_data.search' | translate}}</ion-label> | ||||
|                 <ion-input type="text" placeholder="{{ 'addon.mod_data.search' | translate}}" | ||||
|                     [(ngModel)]="search.text" name="text" formControlName="text"> | ||||
|                 <ion-input type="text" placeholder="{{ 'addon.mod_data.search' | translate}}" [(ngModel)]="search.text" name="text" | ||||
|                     formControlName="text"> | ||||
|                 </ion-input> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label position="stacked">{{ 'core.sortby' | translate }}</ion-label> | ||||
|                 <ion-select interface="action-sheet" name="sortBy" formControlName="sortBy" | ||||
|                     [placeholder]="'core.sortby' | translate" [interfaceOptions]="{header: 'core.sortby' | translate}"> | ||||
|                 <ion-select interface="action-sheet" name="sortBy" formControlName="sortBy" [placeholder]="'core.sortby' | translate" | ||||
|                     [interfaceOptions]="{header: 'core.sortby' | translate}"> | ||||
|                     <optgroup *ngIf="fieldsArray.length" label="{{ 'addon.mod_data.fields' | translate }}"> | ||||
|                         <ion-select-option *ngFor="let field of fieldsArray" [value]="field.id">{{field.name}}</ion-select-option> | ||||
|                     </optgroup> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button *ngIf="entry" fill="clear" (click)="save($event)"> | ||||
|                 {{ 'core.save' | translate }} | ||||
|  | ||||
| @ -3,15 +3,16 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" | ||||
|         [disabled]="!entryLoaded || !(isPullingToRefresh || !renderingEntry && !loadingRating && !loadingComments)" | ||||
|     <ion-refresher slot="fixed" [disabled]="!entryLoaded || !(isPullingToRefresh || !renderingEntry && !loadingRating && !loadingComments)" | ||||
|         (ionRefresh)="refreshDatabase($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
| @ -40,23 +41,23 @@ | ||||
|         <div class="addon-data-contents addon-data-entry addon-data-entries-{{database.id}}" *ngIf="database && entry"> | ||||
|             <core-style [css]="database.csstemplate" prefix=".addon-data-entries-{{database.id}}"></core-style> | ||||
| 
 | ||||
|             <core-compile-html [text]="entryHtml" [jsData]="jsData" [extraImports]="extraImports" | ||||
|                 (compiling)="setRenderingEntry($event)"></core-compile-html> | ||||
|             <core-compile-html [text]="entryHtml" [jsData]="jsData" [extraImports]="extraImports" (compiling)="setRenderingEntry($event)"> | ||||
|             </core-compile-html> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-rating-rate *ngIf="database && entry && ratingInfo && (!database.approval || entry.approved)" | ||||
|             [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="database.coursemodule" [itemId]="entry.id" [itemSetId]="0" | ||||
|             [courseId]="courseId" [aggregateMethod]="database.assessed" [scaleId]="database.scale" [userId]="entry.userid" | ||||
|             (onLoading)="setLoadingRating($event)" (onUpdate)="ratingUpdated()"> | ||||
|         <core-rating-rate *ngIf="database && entry && ratingInfo && (!database.approval || entry.approved)" [ratingInfo]="ratingInfo" | ||||
|             contextLevel="module" [instanceId]="database.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="courseId" | ||||
|             [aggregateMethod]="database.assessed" [scaleId]="database.scale" [userId]="entry.userid" (onLoading)="setLoadingRating($event)" | ||||
|             (onUpdate)="ratingUpdated()"> | ||||
|         </core-rating-rate> | ||||
|         <core-rating-aggregate *ngIf="database && entry && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|             [instanceId]="database.coursemodule" [itemId]="entry.id" [courseId]="courseId" [aggregateMethod]="database.assessed" | ||||
|             [scaleId]="database.scale"> | ||||
|         </core-rating-aggregate> | ||||
| 
 | ||||
|         <core-comments *ngIf="database && database.comments && entry && entry.id > 0 && commentsEnabled" | ||||
|             contextLevel="module" [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" | ||||
|             area="database_entry" [courseId]="courseId" (onLoading)="setLoadingComments($event)" [showItem]="true"> | ||||
|         <core-comments *ngIf="database && database.comments && entry && entry.id > 0 && commentsEnabled" contextLevel="module" | ||||
|             [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="courseId" | ||||
|             (onLoading)="setLoadingComments($event)" [showItem]="true"> | ||||
|         </core-comments> | ||||
| 
 | ||||
|         <ion-grid *ngIf="hasPrevious || hasNext"> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -29,22 +29,18 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <core-tabs [hideUntil]="tabsReady" [selectedIndex]="firstSelectedTab"> | ||||
|         <core-tab [title]="'addon.mod_feedback.overview' | translate" id="overview" (ionSelect)="tabChanged('overview')"> | ||||
|             <ng-template> | ||||
|                 <ng-container *ngTemplateOutlet="tabOverview"></ng-container> | ||||
|             </ng-template> | ||||
|         </core-tab> | ||||
|         <core-tab *ngIf="showAnalysis && access && access.canviewreports" id="analysis" | ||||
|             [title]="'addon.mod_feedback.analysis' | translate" (ionSelect)="tabChanged('analysis')"> | ||||
|         <core-tab *ngIf="showAnalysis && access && access.canviewreports" id="analysis" [title]="'addon.mod_feedback.analysis' | translate" | ||||
|             (ionSelect)="tabChanged('analysis')"> | ||||
|             <ng-template> | ||||
|                 <ng-container *ngTemplateOutlet="tabAnalysis"></ng-container> | ||||
|             </ng-template> | ||||
| @ -73,10 +69,8 @@ | ||||
|                 </ion-select-option> | ||||
|             </ion-select> | ||||
|         </ion-item> | ||||
|         <ion-item class="ion-text-wrap" (click)="openRespondents()" | ||||
|             [class.hide-detail]="!(access.canviewreports && completedCount > 0)" | ||||
|             detail="true" | ||||
|             [button]="access.canviewreports && completedCount > 0"> | ||||
|         <ion-item class="ion-text-wrap" (click)="openRespondents()" [class.hide-detail]="!(access.canviewreports && completedCount > 0)" | ||||
|             detail="true" [button]="access.canviewreports && completedCount > 0"> | ||||
|             <ion-label> | ||||
|                 <h2>{{ 'addon.mod_feedback.completed_feedbacks' | translate }}</h2> | ||||
|             </ion-label> | ||||
| @ -87,8 +81,8 @@ | ||||
|                 </span> | ||||
|             </ion-badge> | ||||
|         </ion-item> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="!access.isanonymous && access.canviewreports" (click)="openNonRespondents()" | ||||
|             detail="true" button> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="!access.isanonymous && access.canviewreports" (click)="openNonRespondents()" detail="true" | ||||
|             button> | ||||
|             <ion-label> | ||||
|                 <h2>{{ 'addon.mod_feedback.show_nonrespondents' | translate }}</h2> | ||||
|             </ion-label> | ||||
| @ -112,14 +106,6 @@ | ||||
|     <core-loading [hideUntil]="tabsLoaded.overview"> | ||||
|         <ng-container *ngTemplateOutlet="basicInfo"></ng-container> | ||||
| 
 | ||||
|         <!-- Feedback done in offline but not synchronized --> | ||||
|         <ion-card class="core-warning-card" *ngIf="hasOffline"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ion-card class="core-info-card" *ngIf="access && access.cancomplete && !access.isopen"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-question-circle" slot="start" aria-hidden="true"></ion-icon> | ||||
| @ -212,8 +198,8 @@ | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                         <p> | ||||
|                             <core-format-text [component]="component" [componentId]="componentId" [text]="item.label" | ||||
|                                 contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                             <core-format-text [component]="component" [componentId]="componentId" [text]="item.label" contextLevel="module" | ||||
|                                 [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                         <ng-container [ngSwitch]="item.templateName"> | ||||
| @ -232,8 +218,7 @@ | ||||
|                             </ng-container> | ||||
|                             <ng-container *ngSwitchCase="'chart'"> | ||||
|                                 <core-chart [type]="item.chartType" [data]="item.chartData" [labels]="item.labels" height="300" | ||||
|                                     contextLevel="module" [contextInstanceId]="module.id" [wsNotFiltered]="true" | ||||
|                                     [courseId]="courseId"> | ||||
|                                     contextLevel="module" [contextInstanceId]="module.id" [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                 </core-chart> | ||||
|                                 <p *ngIf="item.average"> | ||||
|                                     {{ 'addon.mod_feedback.average' | translate }}: {{item.average | number : '1.2-2'}} | ||||
|  | ||||
| @ -3,12 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <h1> | ||||
|             <ng-container *ngIf="attempt">{{ attempt.fullname }}</ng-container> | ||||
|             <ng-container *ngIf="anonAttempt"> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="attempt">{{ attempt.fullname }}</h1> | ||||
|             <h1 *ngIf="anonAttempt"> | ||||
|                 {{ 'addon.mod_feedback.response_nr' |translate }}: {{anonAttempt.number}} | ||||
|             </ng-container> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -38,8 +38,8 @@ | ||||
|                         <ion-label> | ||||
|                             <h2 *ngIf="item.name" [core-mark-required]="item.required"> | ||||
|                                 <span *ngIf="feedback!.autonumbering && item.itemnumber">{{item.itemnumber}}. </span> | ||||
|                                 <core-format-text [component]="component" [componentId]="cmId" [text]="item.name" | ||||
|                                     contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                 <core-format-text [component]="component" [componentId]="cmId" [text]="item.name" contextLevel="module" | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                 </core-format-text> | ||||
|                             </h2> | ||||
|                             <p *ngIf="item.submittedValue"> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -28,22 +30,20 @@ | ||||
|                             <ion-label [position]="item.hasTextInput ? 'stacked' : undefined"> | ||||
|                                 <p *ngIf="item.name" [core-mark-required]="item.required"> | ||||
|                                     <span *ngIf="feedback!.autonumbering && item.itemnumber">{{item.itemnumber}}. </span> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="item.name" | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" [wsNotFiltered]="true"> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="item.name" contextLevel="module" | ||||
|                                         [contextInstanceId]="cmId" [courseId]="courseId" [wsNotFiltered]="true"> | ||||
|                                     </core-format-text> | ||||
|                                     <span *ngIf="item.postfix" class="addon-mod_feedback-postfix">{{item.postfix}}</span> | ||||
|                                 </p> | ||||
|                                 <p *ngIf="item.templateName == 'label'"> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" | ||||
|                                         [text]="item.presentation" contextLevel="module" [contextInstanceId]="cmId" | ||||
|                                         [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="item.presentation" | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </p> | ||||
|                             </ion-label> | ||||
| 
 | ||||
|                             <ion-input *ngIf="item.templateName == 'textfield'" type="text" [(ngModel)]="item.value" | ||||
|                                 autocorrect="off" name="{{item.typ}}_{{item.id}}" maxlength="{{item.length}}" | ||||
|                                 [required]="item.required"> | ||||
|                             <ion-input *ngIf="item.templateName == 'textfield'" type="text" [(ngModel)]="item.value" autocorrect="off" | ||||
|                                 name="{{item.typ}}_{{item.id}}" maxlength="{{item.length}}" [required]="item.required"> | ||||
|                             </ion-input> | ||||
| 
 | ||||
|                             <ng-container *ngIf="item.templateName == 'numeric'"> | ||||
| @ -56,8 +56,8 @@ | ||||
|                                 </ion-text> | ||||
|                             </ng-container> | ||||
| 
 | ||||
|                             <ion-textarea *ngIf="item.templateName == 'textarea'" [required]="item.required" | ||||
|                                 name="{{item.typ}}_{{item.id}}" [(ngModel)]="item.value"> | ||||
|                             <ion-textarea *ngIf="item.templateName == 'textarea'" [required]="item.required" name="{{item.typ}}_{{item.id}}" | ||||
|                                 [(ngModel)]="item.value"> | ||||
|                             </ion-textarea> | ||||
| 
 | ||||
|                             <ion-select *ngIf="item.templateName == 'multichoice-d'" [required]="item.required" | ||||
| @ -65,20 +65,18 @@ | ||||
|                                 [interfaceOptions]="{header: item.name}"> | ||||
|                                 <ion-select-option *ngFor="let option of item.choices" [value]="option.value"> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="option.label" | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" | ||||
|                                         [courseId]="courseId"> | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </ion-select-option> | ||||
|                             </ion-select> | ||||
|                         </ion-item> | ||||
| 
 | ||||
|                         <ion-radio-group *ngIf="item.templateName == 'multichoice-r'" [(ngModel)]="item.value" | ||||
|                             [required]="item.required" name="{{item.typ}}_{{item.id}}"> | ||||
|                         <ion-radio-group *ngIf="item.templateName == 'multichoice-r'" [(ngModel)]="item.value" [required]="item.required" | ||||
|                             name="{{item.typ}}_{{item.id}}"> | ||||
|                             <ion-item *ngFor="let option of item.choices"> | ||||
|                                 <ion-label> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" | ||||
|                                         [text]="option.label" contextLevel="module" [contextInstanceId]="cmId" | ||||
|                                         [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="option.label" | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </ion-label> | ||||
|                                 <ion-radio slot="start" [value]="option.value"></ion-radio> | ||||
| @ -89,19 +87,18 @@ | ||||
|                             <ion-item *ngFor="let option of item.choices"> | ||||
|                                 <ion-label> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="option.label" | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" | ||||
|                                         [courseId]="courseId"> | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </ion-label> | ||||
|                                 <ion-checkbox [required]="item.required" name="{{item.typ}}_{{item.id}}" | ||||
|                                     [(ngModel)]="option.checked" value="option.value"> | ||||
|                                 <ion-checkbox [required]="item.required" name="{{item.typ}}_{{item.id}}" [(ngModel)]="option.checked" | ||||
|                                     value="option.value"> | ||||
|                                 </ion-checkbox> | ||||
|                             </ion-item> | ||||
|                         </ng-container> | ||||
| 
 | ||||
|                         <ng-container *ngIf="item.templateName == 'captcha'"> | ||||
|                             <core-recaptcha *ngIf="!preview && !offline" [publicKey]="item.captcha.recaptchapublickey" | ||||
|                                 [model]="item" modelValueName="value"> | ||||
|                             <core-recaptcha *ngIf="!preview && !offline" [publicKey]="item.captcha.recaptchapublickey" [model]="item" | ||||
|                                 modelValueName="value"> | ||||
|                             </core-recaptcha> | ||||
|                             <div *ngIf="!preview && (!item.captcha || offline)" class="core-warning-card"> | ||||
|                                 <ion-item> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_feedback.responses' |translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -27,7 +29,9 @@ | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-item-divider> | ||||
|                 <ion-label><h2>{{ 'addon.mod_feedback.non_respondents_students' | translate : {$a: total } }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_feedback.non_respondents_students' | translate : {$a: total } }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <ng-container *ngIf="total > 0"> | ||||
|                 <ion-item *ngFor="let user of users" class="ion-text-wrap"> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_feedback.responses' |translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -48,7 +50,9 @@ | ||||
|                         {{ 'core.loadmore' | translate }} | ||||
|                     </ion-button> | ||||
|                     <ion-item *ngIf="responses.responses.canLoadMore && loadingMore" class="ion-text-center"> | ||||
|                         <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                         <ion-label> | ||||
|                             <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ng-container> | ||||
| 
 | ||||
| @ -71,7 +75,9 @@ | ||||
|                         {{ 'core.loadmore' | translate }} | ||||
|                     </ion-button> | ||||
|                     <ion-item *ngIf="responses.anonResponses.canLoadMore && loadingMore" class="ion-text-center"> | ||||
|                         <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                         <ion-label> | ||||
|                             <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ng-container> | ||||
|             </ion-list> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|              iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="!subfolder" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -26,14 +26,10 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info *ngIf="!subfolder" [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <ion-list *ngIf="contents && (contents.files.length + contents.folders.length > 0)"> | ||||
|         <ng-container *ngFor="let folder of contents.folders"> | ||||
|             <ion-item class="item-file" (click)="openFolder(folder)" detail="true" button> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -1,38 +1,30 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" | ||||
|             [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" iconAction="fas-external-link-alt" | ||||
|             [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" | ||||
|             [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item | ||||
|             *ngIf="discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline" | ||||
|             [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" [iconAction]="refreshIcon" [closeOnClick]="false" | ||||
|         <core-context-menu-item *ngIf="discussions.loaded && !(hasOffline || hasOfflineRatings) && isOnline" [priority]="700" | ||||
|             [content]="'addon.mod_forum.refreshdiscussions' | translate" [iconAction]="refreshIcon" [closeOnClick]="false" | ||||
|             (action)="doRefresh(null, $event)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item | ||||
|             *ngIf="discussions.loaded && (hasOffline || hasOfflineRatings) && isOnline" | ||||
|             [priority]="600" [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" [closeOnClick]="false" | ||||
|         <core-context-menu-item *ngIf="discussions.loaded && (hasOffline || hasOfflineRatings) && isOnline" [priority]="600" | ||||
|             [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" [closeOnClick]="false" | ||||
|             (action)="doRefresh(null, $event, true)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" | ||||
|             [priority]="500" [content]="prefetchText" [iconAction]="prefetchStatusIcon" [closeOnClick]="false" | ||||
|             (action)="prefetch($event)"> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" [iconAction]="prefetchStatusIcon" | ||||
|             [closeOnClick]="false" (action)="prefetch($event)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="size" | ||||
|             iconDescription="fas-archive" iconAction="fas-trash" | ||||
|             [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [closeOnClick]="false" | ||||
|             (action)="removeFiles($event)"> | ||||
|         <core-context-menu-item *ngIf="size" iconDescription="fas-archive" iconAction="fas-trash" [priority]="400" | ||||
|             [content]="'core.clearstoreddata' | translate:{$a: size}" [closeOnClick]="false" (action)="removeFiles($event)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="sortingAvailable" | ||||
|             iconAction="fas-sort" | ||||
|             [priority]="300" [content]="'core.sort' | translate" | ||||
|         <core-context-menu-item *ngIf="sortingAvailable" iconAction="fas-sort" [priority]="300" [content]="'core.sort' | translate" | ||||
|             (action)="showSortOrderSelector()"> | ||||
|         </core-context-menu-item> | ||||
|     </core-context-menu> | ||||
| @ -46,22 +38,15 @@ | ||||
| 
 | ||||
|     <core-loading [hideUntil]="discussions.loaded"> | ||||
|         <!-- Activity info. --> | ||||
|         <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|             (completionChanged)="onCompletionChange()"> | ||||
|         </core-course-module-info> | ||||
| 
 | ||||
|         <core-course-module-description *ngIf="forum && forum.type != 'single'" | ||||
|             [description]="description" [component]="component" [componentId]="componentId" [note]="descriptionNote" | ||||
|             contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId"> | ||||
|         </core-course-module-description> | ||||
| 
 | ||||
|         <!-- Forum discussions found to be synchronized --> | ||||
|         <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings"> | ||||
|         <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" | ||||
|             [description]="forum && forum.type != 'single' && description" [component]="component" [componentId]="componentId" | ||||
|             [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> | ||||
|                 <ion-label> | ||||
|                     {{descriptionNote}} | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|         </core-course-module-info> | ||||
| 
 | ||||
|         <!-- Cut-off date or due date message --> | ||||
|         <ion-card class="core-info-card" *ngIf="availabilityMessage"> | ||||
| @ -72,23 +57,17 @@ | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ng-container *ngIf="forum"> | ||||
|             <core-empty-box *ngIf="discussions.empty" icon="far-comments" | ||||
|                 [message]="'addon.mod_forum.forumnodiscussionsyet' | translate"> | ||||
|             <core-empty-box *ngIf="discussions.empty" icon="far-comments" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate"> | ||||
|             </core-empty-box> | ||||
| 
 | ||||
|             <div *ngIf="!discussions.empty && sortingAvailable && selectedSortOrder" class="ion-text-wrap"> | ||||
|                 <core-combobox | ||||
|                     [modalOptions]="sortOrderSelectorModalOptions" | ||||
|                     listboxId="addon-mod-forum-sort-selector" | ||||
|                     [label]="('core.sort' | translate)" | ||||
|                     (onChange)="setSortOrder($event)" | ||||
|                     [selection]="selectedSortOrder.label | translate" | ||||
|                 <core-combobox [modalOptions]="sortOrderSelectorModalOptions" listboxId="addon-mod-forum-sort-selector" | ||||
|                     [label]="('core.sort' | translate)" (onChange)="setSortOrder($event)" [selection]="selectedSortOrder.label | translate" | ||||
|                     interface="modal"> | ||||
|                 </core-combobox> | ||||
|             </div> | ||||
| 
 | ||||
|             <ion-item *ngFor="let discussion of discussions.items" | ||||
|                 class="addon-mod-forum-discussion" detail="true" | ||||
|             <ion-item *ngFor="let discussion of discussions.items" class="addon-mod-forum-discussion" detail="true" | ||||
|                 [lines]="discussion.groupname && 'none'" [attr.aria-current]="discussions.getItemAriaCurrent(discussion)" | ||||
|                 (click)="discussions.select(discussion)" button> | ||||
|                 <ion-label> | ||||
| @ -98,15 +77,12 @@ | ||||
|                                 [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"></ion-icon> | ||||
|                             <ion-icon name="fas-star" class="addon-forum-star" *ngIf="!discussion.pinned && discussion.starred" | ||||
|                                 [attr.aria-label]="'addon.mod_forum.favourites' | translate"></ion-icon> | ||||
|                             <core-format-text | ||||
|                                 [text]="discussion.subject" | ||||
|                                 contextLevel="module" [contextInstanceId]="module && module.id" [courseId]="courseId"> | ||||
|                             <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" | ||||
|                                 [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                         <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" | ||||
|                             fill="clear" color="dark" | ||||
|                             [attr.aria-label]="('core.displayoptions' | translate)" | ||||
|                             (click)="showOptionsMenu($event, discussion)"> | ||||
|                         <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear" color="dark" | ||||
|                             [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)"> | ||||
|                             <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> | ||||
|                             </ion-icon> | ||||
|                         </ion-button> | ||||
| @ -158,8 +134,7 @@ | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <core-infinite-loading | ||||
|                 [enabled]="discussions.onlineLoaded && !discussions.completed" [error]="discussions.fetchFailed" | ||||
|             <core-infinite-loading [enabled]="discussions.onlineLoaded && !discussions.completed" [error]="discussions.fetchFailed" | ||||
|                 (action)="fetchMoreDiscussions($event)"> | ||||
|             </core-infinite-loading> | ||||
|         </ng-container> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2 id="addon-mod-forum-sort-order-label">{{ 'core.sort' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-times" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="startingPost"> | ||||
|                 <core-format-text contextLevel="module" [text]="startingPost.subject" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The context menu will be added in here. --> | ||||
|         </ion-buttons> | ||||
| @ -14,48 +16,41 @@ | ||||
| </ion-header> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="discussionLoaded && !postHasOffline && isOnline" | ||||
|             [priority]="650" [content]="'addon.mod_forum.refreshposts' | translate" [iconAction]="refreshIcon" [closeOnClick]="false" | ||||
|         <core-context-menu-item *ngIf="discussionLoaded && !postHasOffline && isOnline" [priority]="650" | ||||
|             [content]="'addon.mod_forum.refreshposts' | translate" [iconAction]="refreshIcon" [closeOnClick]="false" | ||||
|             (action)="doRefresh(null, $event)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="discussionLoaded && isMobile && postHasOffline && isOnline" | ||||
|             [priority]="550" [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" [closeOnClick]="false" | ||||
|         <core-context-menu-item *ngIf="discussionLoaded && isMobile && postHasOffline && isOnline" [priority]="550" | ||||
|             [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" [closeOnClick]="false" | ||||
|             (action)="doRefresh(null, $event, true)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="sort == 'flat-oldest'" | ||||
|             [priority]="500" [content]="'addon.mod_forum.modeflatoldestfirst' | translate" iconAction="fas-arrow-down" | ||||
|             (action)="changeSort('flat-oldest')"> | ||||
|         <core-context-menu-item [hidden]="sort == 'flat-oldest'" [priority]="500" | ||||
|             [content]="'addon.mod_forum.modeflatoldestfirst' | translate" iconAction="fas-arrow-down" (action)="changeSort('flat-oldest')"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="sort == 'flat-newest'" | ||||
|             [priority]="450" [content]="'addon.mod_forum.modeflatnewestfirst' | translate" iconAction="fas-arrow-up" | ||||
|             (action)="changeSort('flat-newest')"> | ||||
|         <core-context-menu-item [hidden]="sort == 'flat-newest'" [priority]="450" | ||||
|             [content]="'addon.mod_forum.modeflatnewestfirst' | translate" iconAction="fas-arrow-up" (action)="changeSort('flat-newest')"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="sort == 'nested'" | ||||
|             [priority]="400" [content]="'addon.mod_forum.modenested' | translate" iconAction="fas-exchange-alt" | ||||
|             (action)="changeSort('nested')"> | ||||
|         <core-context-menu-item [hidden]="sort == 'nested'" [priority]="400" [content]="'addon.mod_forum.modenested' | translate" | ||||
|             iconAction="fas-exchange-alt" (action)="changeSort('nested')"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canlock || discussion.locked" | ||||
|             [priority]="300" [content]="'addon.mod_forum.lockdiscussion' | translate" iconAction="fas-lock" | ||||
|             (action)="setLockState(true)"> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canlock || discussion.locked" [priority]="300" | ||||
|             [content]="'addon.mod_forum.lockdiscussion' | translate" iconAction="fas-lock" (action)="setLockState(true)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canlock || !discussion.locked" | ||||
|             [priority]="300" [content]="'addon.mod_forum.unlockdiscussion' | translate" iconAction="fas-unlock" | ||||
|             (action)="setLockState(false)"> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canlock || !discussion.locked" [priority]="300" | ||||
|             [content]="'addon.mod_forum.unlockdiscussion' | translate" iconAction="fas-unlock" (action)="setLockState(false)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!discussion || !canPin || discussion.pinned" | ||||
|             [priority]="250" [content]="'addon.mod_forum.pindiscussion' | translate" iconAction="fas-map-pin" | ||||
|             (action)="setPinState(true)"> | ||||
|         <core-context-menu-item [hidden]="!discussion || !canPin || discussion.pinned" [priority]="250" | ||||
|             [content]="'addon.mod_forum.pindiscussion' | translate" iconAction="fas-map-pin" (action)="setPinState(true)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!discussion || !canPin || !discussion.pinned" | ||||
|             [priority]="250" [content]="'addon.mod_forum.unpindiscussion' | translate" [iconSlash]="true" iconAction="fas-map-pin" | ||||
|         <core-context-menu-item [hidden]="!discussion || !canPin || !discussion.pinned" [priority]="250" | ||||
|             [content]="'addon.mod_forum.unpindiscussion' | translate" [iconSlash]="true" iconAction="fas-map-pin" | ||||
|             (action)="setPinState(false)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canfavourite || discussion.starred" | ||||
|             [priority]="200" [content]="'addon.mod_forum.addtofavourites' | translate" iconAction="fas-star" | ||||
|             (action)="toggleFavouriteState(true)"> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canfavourite || discussion.starred" [priority]="200" | ||||
|             [content]="'addon.mod_forum.addtofavourites' | translate" iconAction="fas-star" (action)="toggleFavouriteState(true)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canfavourite || !discussion.starred" | ||||
|             [priority]="200" [content]="'addon.mod_forum.removefromfavourites' | translate" iconAction="fas-star" [iconSlash]="true" | ||||
|         <core-context-menu-item [hidden]="!discussion || !discussion.canfavourite || !discussion.starred" [priority]="200" | ||||
|             [content]="'addon.mod_forum.removefromfavourites' | translate" iconAction="fas-star" [iconSlash]="true" | ||||
|             (action)="toggleFavouriteState(false)"> | ||||
|         </core-context-menu-item> | ||||
|     </core-context-menu> | ||||
| @ -90,25 +85,20 @@ | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <div *ngIf="startingPost" class="ion-margin-bottom"> | ||||
|             <addon-mod-forum-post | ||||
|                 [post]="startingPost" [discussion]="discussion" [courseId]="courseId" [highlight]="true" | ||||
|                 [discussionId]="discussionId" [component]="component" [componentId]="cmId" | ||||
|                 [formData]="formData" [originalData]="originalData" [forum]="forum" [accessInfo]="accessInfo" | ||||
|                 [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" [leavingPage]="leavingPage" | ||||
|                 (onPostChange)="postListChanged()"> | ||||
|             <addon-mod-forum-post [post]="startingPost" [discussion]="discussion" [courseId]="courseId" [highlight]="true" | ||||
|                 [discussionId]="discussionId" [component]="component" [componentId]="cmId" [formData]="formData" | ||||
|                 [originalData]="originalData" [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" | ||||
|                 [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|             </addon-mod-forum-post> | ||||
|         </div> | ||||
| 
 | ||||
|         <ion-card *ngIf="sort != 'nested'"> | ||||
|             <ng-container *ngFor="let post of posts; first as first"> | ||||
|                 <core-spacer *ngIf="!first"></core-spacer> | ||||
|                 <addon-mod-forum-post | ||||
|                     [post]="post" [courseId]="courseId" [discussionId]="discussionId" | ||||
|                     [component]="component" [componentId]="cmId" [formData]="formData" | ||||
|                     [originalData]="originalData" [parentSubject]="postSubjects[post.parentid]" | ||||
|                 <addon-mod-forum-post [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                     [componentId]="cmId" [formData]="formData" [originalData]="originalData" [parentSubject]="postSubjects[post.parentid]" | ||||
|                     [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" | ||||
|                     [leavingPage]="leavingPage" | ||||
|                     (onPostChange)="postListChanged()"> | ||||
|                     [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|                 </addon-mod-forum-post> | ||||
|             </ng-container> | ||||
|         </ion-card> | ||||
| @ -121,12 +111,10 @@ | ||||
| 
 | ||||
|         <ng-template #nestedPosts let-post="post"> | ||||
|             <ion-card> | ||||
|                 <addon-mod-forum-post | ||||
|                     [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                     [componentId]="cmId" [formData]="formData" [originalData]="originalData" | ||||
|                     [parentSubject]="postSubjects[post.parentid]" [forum]="forum" [accessInfo]="accessInfo" | ||||
|                     [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" [leavingPage]="leavingPage" | ||||
|                     (onPostChange)="postListChanged()"> | ||||
|                 <addon-mod-forum-post [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                     [componentId]="cmId" [formData]="formData" [originalData]="originalData" [parentSubject]="postSubjects[post.parentid]" | ||||
|                     [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" | ||||
|                     [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|                 </addon-mod-forum-post> | ||||
|             </ion-card> | ||||
|             <div class="ion-padding-start" *ngIf="post.children && post.children.length && post.children[0].subject"> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_forum.addanewdiscussion' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The context menu will be added in here. --> | ||||
|         </ion-buttons> | ||||
| @ -18,9 +20,8 @@ | ||||
|         <form *ngIf="showForm" #newDiscFormEl> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label> | ||||
|                 <ion-input | ||||
|                     [(ngModel)]="newDiscussion.subject" | ||||
|                     type="text" [placeholder]="'addon.mod_forum.subject' | translate" name="subject"> | ||||
|                 <ion-input [(ngModel)]="newDiscussion.subject" type="text" [placeholder]="'addon.mod_forum.subject' | translate" | ||||
|                     name="subject"> | ||||
|                 </ion-input> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
| @ -31,19 +32,14 @@ | ||||
|                     (contentChanged)="onMessageChange($event)"> | ||||
|                 </core-rich-text-editor> | ||||
|             </ion-item> | ||||
|             <ion-item | ||||
|                 button | ||||
|                 class="divider ion-text-wrap" | ||||
|                 (click)="toggleAdvanced()" | ||||
|                 detail="false" | ||||
|                 [attr.aria-expanded]="advanced" | ||||
|                 [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate" | ||||
|                 role="heading" | ||||
|                 aria-controls="addon-mod-forum-new-discussion-advanced" | ||||
|             > | ||||
|             <ion-item button class="divider ion-text-wrap" (click)="toggleAdvanced()" detail="false" [attr.aria-expanded]="advanced" | ||||
|                 [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate" role="heading" | ||||
|                 aria-controls="addon-mod-forum-new-discussion-advanced"> | ||||
|                 <ion-icon *ngIf="!advanced" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon *ngIf="advanced" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label><h2>{{ 'addon.mod_forum.advanced' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_forum.advanced' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <div *ngIf="advanced" id="addon-mod-forum-new-discussion-advanced"> | ||||
|                 <ion-item *ngIf="showGroups && groupIds.length > 1 && accessInfo.cancanposttomygroups"> | ||||
| @ -66,17 +62,16 @@ | ||||
|                     <ion-label>{{ 'addon.mod_forum.discussionpinned' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.pin" name="pin"></ion-toggle> | ||||
|                 </ion-item> | ||||
|                 <core-attachments *ngIf="canCreateAttachments && forum && forum.maxattachments > 0" | ||||
|                     [files]="newDiscussion.files" [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments" | ||||
|                     [component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId"> | ||||
|                 <core-attachments *ngIf="canCreateAttachments && forum && forum.maxattachments > 0" [files]="newDiscussion.files" | ||||
|                     [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments" [component]="component" [componentId]="forum.cmid" | ||||
|                     [allowOffline]="true" [courseId]="courseId"> | ||||
|                 </core-attachments> | ||||
|             </div> | ||||
|             <ion-item> | ||||
|                 <ion-label> | ||||
|                     <ion-row> | ||||
|                         <ion-col> | ||||
|                             <ion-button | ||||
|                                 expand="block" [disabled]="newDiscussion.subject == '' || newDiscussion.message == null" | ||||
|                             <ion-button expand="block" [disabled]="newDiscussion.subject == '' || newDiscussion.message == null" | ||||
|                                 (click)="add()"> | ||||
|                                 {{ 'addon.mod_forum.posttoforum' | translate }} | ||||
|                             </ion-button> | ||||
|  | ||||
| @ -10,18 +10,17 @@ | ||||
|     </ion-button> | ||||
| 
 | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !(hasOffline || hasOfflineRatings) && isOnline" [priority]="700" | ||||
|             [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" | ||||
|             [closeOnClick]="false"> | ||||
|             [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && (hasOffline || hasOfflineRatings) && isOnline" [priority]="600" | ||||
|             (action)="doRefresh(null, $event, true)" [content]="'core.settings.synchronizenow' | translate" [iconAction]="syncIcon" | ||||
| @ -51,25 +50,15 @@ | ||||
| 
 | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <!-- Activity info. --> | ||||
|         <core-course-module-info *ngIf="showCompletion && !isSearch" [module]="module" [showManualCompletion]="true" | ||||
|             (completionChanged)="onCompletionChange()"> | ||||
|         <core-course-module-info *ngIf="!isSearch" [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|             [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> | ||||
|         </core-course-module-info> | ||||
| 
 | ||||
|         <core-course-module-description *ngIf="!isSearch" [description]="description" [component]="component" [componentId]="componentId" | ||||
|             contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|         </core-course-module-description> | ||||
| 
 | ||||
|         <!-- Has offline data to be synchronized --> | ||||
|         <ion-card class="core-warning-card" *ngIf="hasOffline || hasOfflineRatings"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate:{$a: moduleName} }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ion-list *ngIf="!isSearch && entries.offlineEntries.length > 0"> | ||||
|             <ion-item-divider> | ||||
|                 <ion-label><h2>{{ 'addon.mod_glossary.entriestobesynced' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_glossary.entriestobesynced' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <ion-item *ngFor="let entry of entries.offlineEntries" (click)="entries.select(entry)" detail="false" button | ||||
|                 [attr.aria-current]="entries.getItemAriaCurrent(entry)"> | ||||
| @ -84,11 +73,12 @@ | ||||
|         <ion-list *ngIf="entries.onlineEntries.length > 0"> | ||||
|             <ng-container *ngFor="let entry of entries.onlineEntries; let index = index"> | ||||
|                 <ion-item-divider *ngIf="getDivider && showDivider(entry, entries.onlineEntries[index - 1])"> | ||||
|                     <ion-label><h2>{{ getDivider!(entry) }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ getDivider!(entry) }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
| 
 | ||||
|                 <ion-item button (click)="entries.select(entry)" [attr.aria-current]="entries.getItemAriaCurrent(entry)" | ||||
|                     detail="false"> | ||||
|                 <ion-item button (click)="entries.select(entry)" [attr.aria-current]="entries.getItemAriaCurrent(entry)" detail="false"> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="glossary!.coursemodule" | ||||
|                             [courseId]="courseId"> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="glossary"> | ||||
|                 <core-format-text [text]="glossary.name" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -14,16 +16,15 @@ | ||||
|         <form #editFormEl *ngIf="glossary"> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_glossary.concept' | translate }}</ion-label> | ||||
|                 <ion-input type="text" [placeholder]="'addon.mod_glossary.concept' | translate" [(ngModel)]="entry.concept" | ||||
|                     name="concept"> | ||||
|                 <ion-input type="text" [placeholder]="'addon.mod_glossary.concept' | translate" [(ngModel)]="entry.concept" name="concept"> | ||||
|                 </ion-input> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_glossary.definition' | translate }}</ion-label> | ||||
|                 <core-rich-text-editor [control]="definitionControl" (contentChanged)="onDefinitionChange($event)" | ||||
|                     [placeholder]="'addon.mod_glossary.definition' | translate" name="addon_mod_glossary_edit" | ||||
|                     [component]="component" [componentId]="cmId" [autoSave]="true" contextLevel="module" | ||||
|                     [contextInstanceId]="cmId" elementId="definition_editor" [draftExtraParams]="editorExtraParams"> | ||||
|                     [placeholder]="'addon.mod_glossary.definition' | translate" name="addon_mod_glossary_edit" [component]="component" | ||||
|                     [componentId]="cmId" [autoSave]="true" contextLevel="module" [contextInstanceId]="cmId" elementId="definition_editor" | ||||
|                     [draftExtraParams]="editorExtraParams"> | ||||
|                 </core-rich-text-editor> | ||||
|             </ion-item> | ||||
|             <ion-item *ngIf="categories.length > 0"> | ||||
| @ -47,14 +48,18 @@ | ||||
|                 </ion-textarea> | ||||
|             </ion-item> | ||||
|             <ion-item-divider> | ||||
|                 <ion-label><h2>{{ 'addon.mod_glossary.attachment' | translate }}</h2></ion-label> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_glossary.attachment' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <core-attachments [files]="attachments" [component]="component" [componentId]="glossary.coursemodule" | ||||
|                 [allowOffline]="true" [courseId]="courseId"> | ||||
|             <core-attachments [files]="attachments" [component]="component" [componentId]="glossary.coursemodule" [allowOffline]="true" | ||||
|                 [courseId]="courseId"> | ||||
|             </core-attachments> | ||||
|             <ng-container *ngIf="glossary.usedynalink"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label><h2>{{ 'addon.mod_glossary.linking' | translate }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.mod_glossary.linking' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label>{{ 'addon.mod_glossary.entryusedynalink' | translate }}</ion-label> | ||||
|  | ||||
| @ -3,10 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="entry"> | ||||
|                 <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -39,14 +41,13 @@ | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <core-format-text [component]="component" [componentId]="componentId" [text]="entry.definition" | ||||
|                         contextLevel="module" [contextInstanceId]="componentId" [courseId]="courseId"> | ||||
|                     <core-format-text [component]="component" [componentId]="componentId" [text]="entry.definition" contextLevel="module" | ||||
|                         [contextInstanceId]="componentId" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <div *ngIf="entry.attachment" lines="none"> | ||||
|                 <core-file *ngFor="let file of entry.attachments" [file]="file" [component]="component" | ||||
|                     [componentId]="componentId"> | ||||
|                 <core-file *ngFor="let file of entry.attachments" [file]="file" [component]="component" [componentId]="componentId"> | ||||
|                 </core-file> | ||||
|             </div> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="tagsEnabled && entry && entry.tags && entry.tags.length > 0"> | ||||
| @ -56,20 +57,21 @@ | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="!entry.approved"> | ||||
|                 <ion-label><p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p></ion-label> | ||||
|                 <ion-label> | ||||
|                     <p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <core-comments *ngIf="glossary && glossary.allowcomments && entry && entry.id > 0 && commentsEnabled" | ||||
|                 contextLevel="module" [instanceId]="glossary.coursemodule" component="mod_glossary" | ||||
|                 [itemId]="entry.id" area="glossary_entry" [courseId]="glossary.course" [showItem]="true"> | ||||
|             <core-comments *ngIf="glossary && glossary.allowcomments && entry && entry.id > 0 && commentsEnabled" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" component="mod_glossary" [itemId]="entry.id" area="glossary_entry" | ||||
|                 [courseId]="glossary.course" [showItem]="true"> | ||||
|             </core-comments> | ||||
|             <core-rating-rate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="glossary.course" | ||||
|                 [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale" [userId]="entry.userid" | ||||
|                 (onUpdate)="ratingUpdated()"> | ||||
|                 [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale" [userId]="entry.userid" (onUpdate)="ratingUpdated()"> | ||||
|             </core-rating-rate> | ||||
|             <core-rating-aggregate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" [itemId]="entry.id" [courseId]="glossary.course" | ||||
|                 [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale"> | ||||
|                 [instanceId]="glossary.coursemodule" [itemId]="entry.id" [courseId]="glossary.course" [aggregateMethod]="glossary.assessed" | ||||
|                 [scaleId]="glossary.scale"> | ||||
|             </core-rating-aggregate> | ||||
|         </ng-container> | ||||
| 
 | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -5,18 +5,17 @@ | ||||
|             [priority]="1000" [content]="'addon.mod_h5pactivity.review_my_attempts' | translate" (action)="viewMyAttempts()" | ||||
|             iconAction="stats-chart"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="canViewAllAttempts" | ||||
|             [priority]="1000" [content]="'addon.mod_h5pactivity.review_attempts' | translate" (action)="viewAllAttempts()" | ||||
|             iconAction="stats-chart"> | ||||
|         <core-context-menu-item *ngIf="canViewAllAttempts" [priority]="1000" [content]="'addon.mod_h5pactivity.review_attempts' | translate" | ||||
|             (action)="viewAllAttempts()" iconAction="stats-chart"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -37,22 +36,10 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <!-- Offline data stored. --> | ||||
|     <ion-card class="core-warning-card" *ngIf="hasOffline"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <!-- Offline disabled. --> | ||||
|     <ion-card class="core-warning-card" *ngIf="!siteCanDownload && playing"> | ||||
|         <ion-item> | ||||
| @ -79,8 +66,7 @@ | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <!-- Button to download the package. --> | ||||
|         <ion-button *ngIf="!downloading && needsDownload" class="ion-text-wrap ion-margin" expand="block" | ||||
|             (click)="downloadAndPlay($event)"> | ||||
|         <ion-button *ngIf="!downloading && needsDownload" class="ion-text-wrap ion-margin" expand="block" (click)="downloadAndPlay($event)"> | ||||
|             {{ 'addon.mod_h5pactivity.downloadh5pfile' | translate }} | ||||
|         </ion-button> | ||||
| 
 | ||||
|  | ||||
| @ -3,11 +3,13 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module" | ||||
|                     [contextInstanceId]="h5pActivity.coursemodule" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -89,15 +91,15 @@ | ||||
|                 <ion-card *ngFor="let result of attempt.results"> | ||||
|                     <ion-card-header class="ion-text-wrap"> | ||||
|                         <ion-card-title> | ||||
|                             <core-format-text [text]="result.description" [component]="component" [componentId]="cmId" | ||||
|                                 contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                             <core-format-text [text]="result.description" [component]="component" [componentId]="cmId" contextLevel="module" | ||||
|                                 [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </ion-card-title> | ||||
|                     </ion-card-header> | ||||
|                     <ion-item *ngIf="result.content" class="ion-text-wrap"> | ||||
|                         <ion-label> | ||||
|                             <core-format-text [text]="result.content" [component]="component" [componentId]="cmId" | ||||
|                                 contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                             <core-format-text [text]="result.content" [component]="component" [componentId]="cmId" contextLevel="module" | ||||
|                                 [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
| @ -113,8 +115,7 @@ | ||||
|                                 </ion-row> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
|                         <ion-item *ngFor="let option of result.options" | ||||
|                             class="ion-text-wrap addon-mod_h5pactivity-result-table-row"> | ||||
|                         <ion-item *ngFor="let option of result.options" class="ion-text-wrap addon-mod_h5pactivity-result-table-row"> | ||||
|                             <ion-label> | ||||
|                                 <ion-row class="ion-align-items-center"> | ||||
|                                     <ion-col class="ion-text-center"> | ||||
| @ -124,8 +125,7 @@ | ||||
|                                     </ion-col> | ||||
|                                     <ion-col class="ion-text-center"> | ||||
|                                         <ng-container *ngIf="option.correctanswer"> | ||||
|                                             <ng-container | ||||
|                                                 *ngTemplateOutlet="answerTemplate; context: {answer: option.correctanswer}"> | ||||
|                                             <ng-container *ngTemplateOutlet="answerTemplate; context: {answer: option.correctanswer}"> | ||||
|                                             </ng-container> | ||||
|                                         </ng-container> | ||||
|                                     </ion-col> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -3,11 +3,13 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module" | ||||
|                     [contextInstanceId]="h5pActivity.coursemodule" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
| @ -3,11 +3,13 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text *ngIf="h5pActivity" [text]="h5pActivity.name" contextLevel="module" | ||||
|                     [contextInstanceId]="h5pActivity.coursemodule" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|  | ||||
| @ -4,14 +4,14 @@ | ||||
|         <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" | ||||
|             [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -29,8 +29,7 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <h1>{{ 'addon.mod_imscp.toc' | translate }}</h1> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.mod_imscp.toc' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-times" slot="icon-only" aria-hidden=true></ion-icon> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -33,14 +33,10 @@ | ||||
|             <ng-template> | ||||
| 
 | ||||
|                 <!-- Activity info. --> | ||||
|                 <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|                     (completionChanged)="onCompletionChange()"> | ||||
|                 <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|                     [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> | ||||
|                 </core-course-module-info> | ||||
| 
 | ||||
|                 <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|                     contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-course-module-description> | ||||
| 
 | ||||
|                 <!-- Prevent access messages. Only show the first one. --> | ||||
|                 <ion-card class="core-info-card" *ngIf="lesson && preventReasons.length"> | ||||
|                     <ion-item> | ||||
| @ -49,14 +45,6 @@ | ||||
|                     </ion-item> | ||||
|                 </ion-card> | ||||
| 
 | ||||
|                 <!-- Lesson has data to be synchronized --> | ||||
|                 <ion-card class="core-warning-card" *ngIf="hasOffline"> | ||||
|                     <ion-item> | ||||
|                         <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                         <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-card> | ||||
| 
 | ||||
|                 <!-- Input password for protected lessons. --> | ||||
|                 <ion-card *ngIf="askPassword"> | ||||
|                     <form (ngSubmit)="submitPassword($event, passwordinput)" #passwordForm> | ||||
| @ -132,13 +120,11 @@ | ||||
| 
 | ||||
|                             <ng-container *ngIf="!leftDuringTimed && !finishedOffline"> | ||||
|                                 <!-- User hasn't left during the session, show a start button. --> | ||||
|                                 <ion-button class="ion-text-wrap ion-margin" expand="block" *ngIf="!canManage" | ||||
|                                     (click)="start(false)"> | ||||
|                                 <ion-button class="ion-text-wrap ion-margin" expand="block" *ngIf="!canManage" (click)="start(false)"> | ||||
|                                     {{ 'core.start' | translate }} | ||||
|                                     <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon> | ||||
|                                 </ion-button> | ||||
|                                 <ion-button class="ion-text-wrap ion-margin" expand="block" *ngIf="canManage" | ||||
|                                     (click)="start(false)"> | ||||
|                                 <ion-button class="ion-text-wrap ion-margin" expand="block" *ngIf="canManage" (click)="start(false)"> | ||||
|                                     {{ 'addon.mod_lesson.preview' | translate }} | ||||
|                                     <ion-icon name="fas-search" slot="end" aria-hidden="true"></ion-icon> | ||||
|                                 </ion-button> | ||||
| @ -295,8 +281,8 @@ | ||||
|                             <ion-card-title>{{ 'addon.mod_lesson.overview' | translate }}</ion-card-title> | ||||
|                         </ion-card-header> | ||||
| 
 | ||||
|                         <ion-item class="ion-text-wrap" *ngFor="let student of overview.students" button | ||||
|                             (click)="openRetake(student.id)" detail="true"> | ||||
|                         <ion-item class="ion-text-wrap" *ngFor="let student of overview.students" button (click)="openRetake(student.id)" | ||||
|                             detail="true"> | ||||
|                             <core-user-avatar [user]="student" slot="start" [userId]="student.id" [courseId]="courseId"> | ||||
|                             </core-user-avatar> | ||||
|                             <ion-label> | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ pageInstance?.lesson?.name }}</h2> | ||||
| 
 | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -15,7 +16,9 @@ | ||||
|             <!-- Media file. --> | ||||
|             <ng-container *ngIf="pageInstance.mediaFile"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label><h2>{{ 'addon.mod_lesson.linkedmedia' | translate }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.mod_lesson.linkedmedia' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <core-file [file]="pageInstance.mediaFile" [component]="pageInstance.component" | ||||
|                     [componentId]="pageInstance.lesson?.coursemodule"> | ||||
| @ -25,16 +28,20 @@ | ||||
|             <!-- Lesson menu. --> | ||||
|             <ng-container *ngIf="pageInstance.displayMenu"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label><h2>{{ 'addon.mod_lesson.lessonmenu' | translate }}</h2></ion-label> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.mod_lesson.lessonmenu' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-center" *ngIf="pageInstance.loadingMenu"> | ||||
|                     <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <div *ngIf="!pageInstance.loadingMenu"> | ||||
|                     <ng-container *ngFor="let page of pageInstance.lessonPages"> | ||||
|                         <ion-item class="ion-text-wrap" *ngIf="page.display && page.displayinmenublock" (click)="loadPage(page.id)" | ||||
|                             [attr.aria-current]="!pageInstance.eolData && pageInstance.currentPage == page.id ? 'page' : 'false'" | ||||
|                             button detail="true"> | ||||
|                             [attr.aria-current]="!pageInstance.eolData && pageInstance.currentPage == page.id ? 'page' : 'false'" button | ||||
|                             detail="true"> | ||||
|                             <ion-label> | ||||
|                                 <core-format-text [text]="page.title" contextLevel="module" [courseId]="pageInstance.courseId" | ||||
|                                     [contextInstanceId]="pageInstance.lesson?.coursemodule"> | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'core.login.password' | translate }}</h2> | ||||
| 
 | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -14,8 +15,8 @@ | ||||
|         <ion-item> | ||||
|             <ion-label>{{ 'addon.mod_lesson.enterpassword' | translate }}</ion-label> | ||||
|             <core-show-password name="password"> | ||||
|                 <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" | ||||
|                     core-auto-focus #passwordinput [clearOnEdit]="false"> | ||||
|                 <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" core-auto-focus | ||||
|                     #passwordinput [clearOnEdit]="false"> | ||||
|                 </ion-input> | ||||
|             </core-show-password> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
| @ -17,7 +19,6 @@ | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-lesson-index [module]="module" [courseId]="courseId" [group]="group" [action]="action" | ||||
|         (dataRetrieved)="updateData($event)"> | ||||
|     <addon-mod-lesson-index [module]="module" [courseId]="courseId" [group]="group" [action]="action" (dataRetrieved)="updateData($event)"> | ||||
|     </addon-mod-lesson-index> | ||||
| </ion-content> | ||||
|  | ||||
| @ -3,11 +3,12 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|             <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                 [courseId]="courseId"> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" *ngIf="displayMenu || mediaFile" [attr.aria-label]="'addon.mod_lesson.lessonmenu' | translate" | ||||
|                 (click)="showMenu()"> | ||||
| @ -46,15 +47,14 @@ | ||||
|             <ion-card *ngIf="!eolData && !processData"> | ||||
|                 <!-- Content page. --> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!question && pageContent"> | ||||
|                     <core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="pageContent" | ||||
|                         contextLevel="module" [contextInstanceId]="lesson.coursemodule" [courseId]="courseId"> | ||||
|                     <core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="pageContent" contextLevel="module" | ||||
|                         [contextInstanceId]="lesson.coursemodule" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <!-- Question page. --> | ||||
|                 <!-- We need to set ngIf loaded to make formGroup directive restart every time a page changes, see MOBILE-2540. --> | ||||
|                 <form *ngIf="question && loaded" [formGroup]="questionForm" #questionFormEl | ||||
|                     (ngSubmit)="submitQuestion($event)"> | ||||
|                 <form *ngIf="question && loaded" [formGroup]="questionForm" #questionFormEl (ngSubmit)="submitQuestion($event)"> | ||||
| 
 | ||||
|                     <ion-item-divider class="ion-text-wrap" *ngIf="pageContent"> | ||||
|                         <ion-label> | ||||
| @ -91,8 +91,8 @@ | ||||
|                                     <h3 class="item-heading">{{ 'addon.mod_lesson.youranswer' | translate }}</h3> | ||||
|                                     <p> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                             [text]="question.useranswer" contextLevel="module" | ||||
|                                             [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                             [text]="question.useranswer" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                             [courseId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                     </p> | ||||
|                                 </ion-label> | ||||
| @ -105,9 +105,8 @@ | ||||
|                             <ion-radio-group *ngIf="!question.multi" [formControlName]="question.controlName"> | ||||
|                                 <ion-item class="ion-text-wrap" *ngFor="let option of question.options"> | ||||
|                                     <ion-label> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson.coursemodule" | ||||
|                                             [text]="option.text" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                             [courseId]="courseId"> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson.coursemodule" [text]="option.text" | ||||
|                                             contextLevel="module" [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                     </ion-label> | ||||
|                                     <ion-radio slot="end" [id]="option.id" [value]="option.value" [disabled]="option.disabled"> | ||||
| @ -119,9 +118,8 @@ | ||||
|                             <ng-container *ngIf="question.multi"> | ||||
|                                 <ion-item class="ion-text-wrap" *ngFor="let option of question.options"> | ||||
|                                     <ion-label> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                             [text]="option.text" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                             [courseId]="courseId"> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" [text]="option.text" | ||||
|                                             contextLevel="module" [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                     </ion-label> | ||||
|                                     <ion-checkbox [id]="option.id" [formControlName]="option.name" slot="end"></ion-checkbox> | ||||
| @ -133,10 +131,12 @@ | ||||
|                         <ng-container *ngSwitchCase="'matching'"> | ||||
|                             <ion-item class="ion-text-wrap" *ngFor="let row of question.rows"> | ||||
|                                 <ion-label> | ||||
|                                     <p><core-format-text id="addon-mod_lesson-matching-{{row.id}}" [component]="component" | ||||
|                                     <p> | ||||
|                                         <core-format-text id="addon-mod_lesson-matching-{{row.id}}" [component]="component" | ||||
|                                             [componentId]="lesson?.coursemodule" [text]="row.text" contextLevel="module" | ||||
|                                             [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                     </core-format-text></p> | ||||
|                                         </core-format-text> | ||||
|                                     </p> | ||||
|                                 </ion-label> | ||||
|                                 <ion-select [id]="row.id" [formControlName]="row.name" interface="action-sheet" | ||||
|                                     [attr.aria-labelledby]="'addon-mod_lesson-matching-' + row.id"> | ||||
| @ -161,8 +161,8 @@ | ||||
|                 <ion-grid *ngIf="pageButtons?.length" class="ion-text-wrap addon-mod_lesson-pagebuttons"> | ||||
|                     <ion-row class="ion-align-items-center"> | ||||
|                         <ion-col *ngFor="let button of pageButtons" size="12" size-md="6" size-lg="3" col-xl> | ||||
|                             <ion-button expand="block" fill="outline" [id]="button.id" | ||||
|                                 (click)="buttonClicked(button.data)" class="ion-text-wrap button-no-uppercase"> | ||||
|                             <ion-button expand="block" fill="outline" [id]="button.id" (click)="buttonClicked(button.data)" | ||||
|                                 class="ion-text-wrap button-no-uppercase"> | ||||
|                                 {{ button.content }} | ||||
|                             </ion-button> | ||||
|                         </ion-col> | ||||
| @ -213,8 +213,7 @@ | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="eolData.displayscorewithessays" lines="none"> | ||||
|                     <ion-label [innerHTML]="eolData.displayscorewithessays.message"></ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!eolData.displayscorewithessays && eolData.displayscorewithoutessays" | ||||
|                     lines="none"> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!eolData.displayscorewithessays && eolData.displayscorewithoutessays" lines="none"> | ||||
|                     <ion-label>{{ eolData.displayscorewithoutessays.message }}</ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="eolData.yourcurrentgradeisoutof" lines="none"> | ||||
| @ -247,19 +246,17 @@ | ||||
|                     <ion-label>{{ eolData.modattemptsnoteacher.message }}</ion-label> | ||||
|                 </ion-item> | ||||
|                 <!-- If activity link was successfully formatted, render the button. --> | ||||
|                 <ion-button *ngIf="activityLink && activityLink.formatted" | ||||
|                     expand="block" color="light" [href]="activityLink.href" core-link [capture]="true" | ||||
|                     class="ion-text-wrap ion-margin button-no-uppercase"> | ||||
|                     <core-format-text [text]="activityLink.label" contextLevel="module" | ||||
|                         [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                 <ion-button *ngIf="activityLink && activityLink.formatted" expand="block" color="light" [href]="activityLink.href" core-link | ||||
|                     [capture]="true" class="ion-text-wrap ion-margin button-no-uppercase"> | ||||
|                     <core-format-text [text]="activityLink.label" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                         [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                 </ion-button> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="activityLink && !activityLink.formatted" | ||||
|                     lines="none"> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="activityLink && !activityLink.formatted" lines="none"> | ||||
|                     <!-- Activity link wasn't formatted, render the original link. --> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="activityLink.label" contextLevel="module" | ||||
|                             [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                         <core-format-text [text]="activityLink.label" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                             [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| @ -273,9 +270,8 @@ | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!processData.reviewmode || review"> | ||||
|                     <ion-label> | ||||
|                         <div *ngIf="!processData.reviewmode"> | ||||
|                             <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                 [text]="processData.feedback" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                 [courseId]="courseId"> | ||||
|                             <core-format-text [component]="component" [componentId]="lesson?.coursemodule" [text]="processData.feedback" | ||||
|                                 contextLevel="module" [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </div> | ||||
|                         <div *ngIf="review"> | ||||
| @ -286,8 +282,7 @@ | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <ion-button expand="block" class="ion-text-wrap ion-margin" color="light" *ngIf="review" | ||||
|                     (click)="changePage(LESSON_EOL)"> | ||||
|                 <ion-button expand="block" class="ion-text-wrap ion-margin" color="light" *ngIf="review" (click)="changePage(LESSON_EOL)"> | ||||
|                     {{ 'addon.mod_lesson.finish' | translate }} | ||||
|                 </ion-button> | ||||
|                 <ion-button expand="block" class="ion-text-wrap ion-margin" color="light" *ngFor="let button of processDataButtons" | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_lesson.detailedstats' | translate }}</h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -133,8 +135,8 @@ | ||||
|                                     <ion-label> | ||||
|                                         <p> | ||||
|                                             <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                                 [text]="answer[0].content" contextLevel="module" | ||||
|                                                 [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                                 [text]="answer[0].content" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                                 [courseId]="courseId"> | ||||
|                                             </core-format-text> | ||||
|                                         </p> | ||||
|                                         <ion-badge *ngIf="answer[1]" color="dark"> | ||||
| @ -144,8 +146,7 @@ | ||||
|                                             </core-format-text> | ||||
|                                         </ion-badge> | ||||
|                                     </ion-label> | ||||
|                                     <ion-checkbox [attr.name]="answer[0].name" [ngModel]="answer[0].checked" [disabled]="true" | ||||
|                                         slot="end"> | ||||
|                                     <ion-checkbox [attr.name]="answer[0].name" [ngModel]="answer[0].checked" [disabled]="true" slot="end"> | ||||
|                                     </ion-checkbox> | ||||
|                                 </ion-item> | ||||
| 
 | ||||
| @ -213,15 +214,13 @@ | ||||
|                                 <!-- Another page (end of branch, ...). --> | ||||
|                                 <ion-label> | ||||
|                                     <p> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                             [text]="answer[0]" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                             [courseId]="courseId"> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" [text]="answer[0]" | ||||
|                                             contextLevel="module" [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                     </p> | ||||
|                                     <ion-badge *ngIf="answer[1]" color="dark"> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                             [text]="answer[1]" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                             [courseId]="courseId"> | ||||
|                                         <core-format-text [component]="component" [componentId]="lesson?.coursemodule" [text]="answer[1]" | ||||
|                                             contextLevel="module" [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                     </ion-badge> | ||||
|                                 </ion-label> | ||||
| @ -233,14 +232,16 @@ | ||||
|                                 <h3 class="item-heading">{{ 'addon.mod_lesson.response' | translate }}</h3> | ||||
|                                 <p> | ||||
|                                     <core-format-text [component]="component" [componentId]="lesson?.coursemodule" | ||||
|                                         [text]="page.answerdata.response" contextLevel="module" | ||||
|                                         [contextInstanceId]="lesson?.coursemodule" [courseId]="courseId"> | ||||
|                                         [text]="page.answerdata.response" contextLevel="module" [contextInstanceId]="lesson?.coursemodule" | ||||
|                                         [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </p> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
|                         <ion-item class="ion-text-wrap" *ngIf="page.answerdata.score"> | ||||
|                             <ion-label><p>{{page.answerdata.score}}</p></ion-label> | ||||
|                             <ion-label> | ||||
|                                 <p>{{page.answerdata.score}}</p> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
|                     </div> | ||||
|                 </ion-card> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -20,14 +20,11 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" | ||||
|         [description]="lti && lti.showdescriptionlaunch && description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description *ngIf="lti && lti.showdescriptionlaunch" [description]="description" [component]="component" | ||||
|         [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <div class="ion-padding"> | ||||
|         <ion-button expand="block" (click)="launch()"> | ||||
|             <ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" | ||||
|             [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -26,14 +26,10 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="displayDescription && description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description *ngIf="displayDescription" [description]="description" [component]="component" | ||||
|         [componentId]="componentId" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             [iconAction]="'far-newspaper'" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'far-newspaper'" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -29,19 +29,18 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" | ||||
|         [hasDataToSync]="buttonText && hasOffline && !showStatusSpinner"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <!-- Access rules description messages. --> | ||||
|     <ion-card *ngIf="gradeMethodReadable || accessRules.length || syncTime"> | ||||
|         <ion-list> | ||||
|             <ion-item class="ion-text-wrap" *ngFor="let rule of accessRules"> | ||||
|                 <ion-label><p>{{ rule }}</p></ion-label> | ||||
|                 <ion-label> | ||||
|                     <p>{{ rule }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="gradeMethodReadable"> | ||||
|                 <ion-label> | ||||
| @ -96,15 +95,9 @@ | ||||
|             </ion-item> | ||||
|             <div role="rowgroup"> | ||||
|                 <!-- List of attempts. --> | ||||
|                 <ion-item | ||||
|                     button | ||||
|                     detail="true" | ||||
|                     *ngFor="let attempt of attempts" | ||||
|                     class="ion-text-wrap" | ||||
|                     [ngClass]='{"addon-mod_quiz-highlighted": attempt.highlightGrade}' | ||||
|                     [attr.aria-label]="'core.seemoredetail' | translate" | ||||
|                     (click)="viewAttempt(attempt.id)" | ||||
|                 > | ||||
|                 <ion-item button detail="true" *ngFor="let attempt of attempts" class="ion-text-wrap" | ||||
|                     [ngClass]='{"addon-mod_quiz-highlighted": attempt.highlightGrade}' [attr.aria-label]="'core.seemoredetail' | translate" | ||||
|                     (click)="viewAttempt(attempt.id)"> | ||||
|                     <ion-label> | ||||
|                         <ion-row class="ion-align-items-center" role="row"> | ||||
|                             <ion-col class="ion-text-center" *ngIf="quiz.showAttemptColumn && attempt.preview" role="cell"> | ||||
| @ -142,17 +135,21 @@ | ||||
|             <ion-item class="ion-text-wrap" *ngIf="gradebookFeedback"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.mod_quiz.comment' | translate }}</p> | ||||
|                     <p><core-format-text [component]="component" [componentId]="componentId" [text]="gradebookFeedback" | ||||
|                     <p> | ||||
|                         <core-format-text [component]="component" [componentId]="componentId" [text]="gradebookFeedback" | ||||
|                             contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                     </core-format-text></p> | ||||
|                         </core-format-text> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="quiz.showFeedbackColumn && overallFeedback"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.mod_quiz.overallfeedback' | translate }}</p> | ||||
|                     <p><core-format-text [component]="component" [componentId]="componentId" [text]="overallFeedback" | ||||
|                         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                     </core-format-text></p> | ||||
|                     <p> | ||||
|                         <core-format-text [component]="component" [componentId]="componentId" [text]="overallFeedback" contextLevel="module" | ||||
|                             [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-list> | ||||
| @ -163,10 +160,14 @@ | ||||
|         <ion-list> | ||||
|             <!-- Error messages. --> | ||||
|             <ion-item class="ion-text-wrap core-danger-item addon-mod_quiz-prevent-messages" *ngFor="let message of preventMessages"> | ||||
|                 <ion-label><p>{{ message }}</p></ion-label> | ||||
|                 <ion-label> | ||||
|                     <p>{{ message }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap core-danger-item addon-mod_quiz-no-questions" *ngIf="quiz.hasquestions === 0"> | ||||
|                 <ion-label><p>{{ 'addon.mod_quiz.noquestions' | translate }}</p></ion-label> | ||||
|                 <ion-label> | ||||
|                     <p>{{ 'addon.mod_quiz.noquestions' | translate }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap core-danger-item addon-mod_quiz-unsupported-questions" | ||||
|                 *ngIf="!hasSupportedQuestions && unsupportedQuestions.length"> | ||||
| @ -194,14 +195,6 @@ | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Quiz has data to be synchronized --> | ||||
|             <ion-card class="core-warning-card" *ngIf="buttonText && hasOffline && !showStatusSpinner"> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
| 
 | ||||
|             <!-- Other warnings. --> | ||||
|             <ion-item class="core-warning-item ion-text-wrap" *ngIf="hasSupportedQuestions && unsupportedQuestions.length"> | ||||
|                 <ion-label> | ||||
| @ -226,7 +219,9 @@ | ||||
| 
 | ||||
|             <!-- Spinner shown while downloading or calculating. --> | ||||
|             <ion-item class="ion-text-center" *ngIf="showStatusSpinner"> | ||||
|                 <ion-label><ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner></ion-label> | ||||
|                 <ion-label> | ||||
|                     <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-list> | ||||
|     </ion-card> | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.mod_quiz.quiznavigation' | translate }}</h2> | ||||
| 
 | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -41,12 +42,12 @@ | ||||
|                 <ion-icon *ngIf="question.stateClass == 'core-question-correct'" name="fas-check" color="success" | ||||
|                     [attr.aria-label]="question.status" slot="end"> | ||||
|                 </ion-icon> | ||||
|                 <ion-icon *ngIf="question.stateClass == 'core-question-partiallycorrect'" name="fas-check-square" | ||||
|                     color="warning" [attr.aria-label]="question.status" slot="end"> | ||||
|                 <ion-icon *ngIf="question.stateClass == 'core-question-partiallycorrect'" name="fas-check-square" color="warning" | ||||
|                     [attr.aria-label]="question.status" slot="end"> | ||||
|                 </ion-icon> | ||||
|                 <ion-icon *ngIf="question.stateClass == 'core-question-incorrect' || | ||||
|                     question.stateClass == 'core-question-notanswered'" name="fas-times" color="danger" | ||||
|                     [attr.aria-label]="question.status" slot="end"> | ||||
|                     question.stateClass == 'core-question-notanswered'" name="fas-times" color="danger" [attr.aria-label]="question.status" | ||||
|                     slot="end"> | ||||
|                 </ion-icon> | ||||
|             </ion-item> | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-title> | ||||
|             <h2>{{ title | translate }}</h2> | ||||
| 
 | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -3,11 +3,13 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text *ngIf="quiz" [text]="quiz.name" contextLevel="module" [contextInstanceId]="quiz.coursemodule" | ||||
|                     [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
| @ -45,8 +47,8 @@ | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_quiz.feedback' | translate }}</h2> | ||||
|                     <p> | ||||
|                         <core-format-text [component]="component" [componentId]="componentId" [text]="feedback" | ||||
|                             contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                         <core-format-text [component]="component" [componentId]="componentId" [text]="feedback" contextLevel="module" | ||||
|                             [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|  | ||||
| @ -3,11 +3,13 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text *ngIf="quiz" [text]="quiz.name" contextLevel="module" [contextInstanceId]="quiz.coursemodule" | ||||
|                     [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" id="addon-mod_quiz-connection-error-button" [hidden]="!autoSaveError" | ||||
| @ -15,8 +17,7 @@ | ||||
|                 aria-haspopup="dialog"> | ||||
|                 <ion-icon name="fas-exclamation-circle" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|             <ion-button *ngIf="navigation.length" [attr.aria-label]="'addon.mod_quiz.opentoc' | translate" | ||||
|                 (click)="openNavigation()"> | ||||
|             <ion-button *ngIf="navigation.length" [attr.aria-label]="'addon.mod_quiz.opentoc' | translate" (click)="openNavigation()"> | ||||
|                 <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
| @ -24,8 +25,7 @@ | ||||
|     <!-- Navigation arrows and time left. --> | ||||
|     <ion-toolbar *ngIf="loaded && endTime && questions.length && !quizAborted && !showSummary" color="light"> | ||||
|         <ion-title> | ||||
|             <core-timer [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate" | ||||
|                 [align]="'center'"> | ||||
|             <core-timer [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate" [align]="'center'"> | ||||
|             </core-timer> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
| @ -79,10 +79,9 @@ | ||||
|                     </ion-item-divider> | ||||
| 
 | ||||
|                     <!-- Body of the question. --> | ||||
|                     <core-question class="ion-text-wrap" [question]="question" [component]="component" | ||||
|                         [componentId]="cmId" [attemptId]="attempt!.id" [usageId]="attempt!.uniqueid" | ||||
|                         [offlineEnabled]="offline" contextLevel="module" [contextInstanceId]="cmId" | ||||
|                         [courseId]="courseId" [preferredBehaviour]="quiz!.preferredbehaviour" [review]="false" | ||||
|                     <core-question class="ion-text-wrap" [question]="question" [component]="component" [componentId]="cmId" | ||||
|                         [attemptId]="attempt!.id" [usageId]="attempt!.uniqueid" [offlineEnabled]="offline" contextLevel="module" | ||||
|                         [contextInstanceId]="cmId" [courseId]="courseId" [preferredBehaviour]="quiz!.preferredbehaviour" [review]="false" | ||||
|                         (onAbort)="abortQuiz()" (buttonClicked)="behaviourButtonClicked($event)"> | ||||
|                     </core-question> | ||||
|                 </ion-card> | ||||
| @ -131,8 +130,8 @@ | ||||
|             <!-- List of questions of the summary table. --> | ||||
|             <ng-container *ngFor="let question of summaryQuestions"> | ||||
|                 <ion-item *ngIf="question.number" (click)="changePage(question.page, false, question.slot)" | ||||
|                     [attr.aria-label]="'core.question.questionno' | translate:{$a: question.number}" | ||||
|                     [detail]="!isSequential && canReturn" [button]="!isSequential && canReturn"> | ||||
|                     [attr.aria-label]="'core.question.questionno' | translate:{$a: question.number}" [detail]="!isSequential && canReturn" | ||||
|                     [button]="!isSequential && canReturn"> | ||||
|                     <ion-label> | ||||
|                         <ion-row class="ion-align-items-center"> | ||||
|                             <ion-col size="3" class="ion-text-center">{{ question.number }}</ion-col> | ||||
| @ -153,8 +152,7 @@ | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Time left (if quiz is timed). --> | ||||
|             <core-timer *ngIf="endTime" [endTime]="endTime" (finished)="timeUp()" | ||||
|                 [timerText]="'addon.mod_quiz.timeleft' | translate"> | ||||
|             <core-timer *ngIf="endTime" [endTime]="endTime" (finished)="timeUp()" [timerText]="'addon.mod_quiz.timeleft' | translate"> | ||||
|             </core-timer> | ||||
| 
 | ||||
|             <!-- List of messages explaining why the quiz cannot be submitted. --> | ||||
| @ -165,15 +163,14 @@ | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-button *ngIf="preventSubmitMessages.length" expand="block" [href]="moduleUrl" core-link | ||||
|                 [showBrowserWarning]="false"> | ||||
|             <ion-button *ngIf="preventSubmitMessages.length" expand="block" [href]="moduleUrl" core-link [showBrowserWarning]="false"> | ||||
|                 {{ 'core.openinbrowser' | translate }} | ||||
|                 <ion-icon name="fas-external-link-alt" slot="end" aria-hidden="true"></ion-icon> | ||||
|             </ion-button> | ||||
| 
 | ||||
|             <!-- Button to submit the quiz. --> | ||||
|             <ion-button *ngIf="!attempt!.finishedOffline && !preventSubmitMessages.length" expand="block" | ||||
|                 class="ion-margin" (click)="finishAttempt(true)"> | ||||
|             <ion-button *ngIf="!attempt!.finishedOffline && !preventSubmitMessages.length" expand="block" class="ion-margin" | ||||
|                 (click)="finishAttempt(true)"> | ||||
|                 {{ 'addon.mod_quiz.submitallandfinish' | translate }} | ||||
|             </ion-button> | ||||
|         </ion-card> | ||||
|  | ||||
| @ -3,7 +3,9 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_quiz.review' | translate }}</h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" *ngIf="navigation.length" [attr.aria-label]="'addon.mod_quiz.opentoc' | translate" | ||||
| @ -75,8 +77,8 @@ | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let data of additionalData"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ data.title }}</p> | ||||
|                         <core-format-text [component]="component" [componentId]="cmId" [text]="data.content" | ||||
|                             contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                         <core-format-text [component]="component" [componentId]="cmId" [text]="data.content" contextLevel="module" | ||||
|                             [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| @ -107,8 +109,7 @@ | ||||
|                     <!-- Body of the question. --> | ||||
|                     <core-question class="ion-text-wrap" [question]="question" [component]="component" [componentId]="cmId" | ||||
|                         [attemptId]="attempt.id" [usageId]="attempt.uniqueid" [offlineEnabled]="false" contextLevel="module" | ||||
|                         [contextInstanceId]="cmId" [courseId]="courseId" [review]="true" | ||||
|                         [preferredBehaviour]="quiz?.preferredbehaviour"> | ||||
|                         [contextInstanceId]="cmId" [courseId]="courseId" [review]="true" [preferredBehaviour]="quiz?.preferredbehaviour"> | ||||
|                     </core-question> | ||||
|                 </ion-card> | ||||
|             </div> | ||||
| @ -130,8 +131,7 @@ | ||||
|                 </ion-button> | ||||
|             </ion-col> | ||||
|             <ion-col class="ion-text-end"> | ||||
|                 <ion-button color="light" *ngIf="nextPage >= -1" (click)="changePage(nextPage)" | ||||
|                     [attr.aria-label]="'core.next' | translate"> | ||||
|                 <ion-button color="light" *ngIf="nextPage >= -1" (click)="changePage(nextPage)" [attr.aria-label]="'core.next' | translate"> | ||||
|                     <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 </ion-button> | ||||
|             </ion-col> | ||||
|  | ||||
| @ -1,12 +1,12 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"></core-context-menu-item> | ||||
|         <core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" | ||||
|             [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" | ||||
| @ -21,15 +21,11 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding core-loading-fullheight"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" [courseId]="courseId" (completionChanged)="onCompletionChange()" | ||||
|         [description]="mode != 'iframe' && (mode != 'embedded' || displayDescription) && description" [component]="component" | ||||
|         [componentId]="componentId"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description *ngIf="mode != 'iframe' && (mode != 'embedded' || displayDescription)" | ||||
|         [description]="description" [component]="component" [componentId]="componentId" contextLevel="module" | ||||
|         [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
| @ -14,8 +16,7 @@ | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" | ||||
|         [disabled]="!activityComponent?.loaded || activityComponent?.mode == 'iframe'" | ||||
|     <ion-refresher slot="fixed" [disabled]="!activityComponent?.loaded || activityComponent?.mode == 'iframe'" | ||||
|         (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
|  | ||||
| @ -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<string | undefined> { | ||||
|         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 | ||||
|      */ | ||||
|  | ||||
| @ -1,14 +1,14 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" | ||||
|             [href]="externalUrl" iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-external-link-alt" [showBrowserWarning]="false"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" | ||||
|             (action)="expandDescription()" iconAction="fas-arrow-right"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" | ||||
|             iconAction="far-newspaper" (action)="gotoBlog()"> | ||||
|         <core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" iconAction="far-newspaper" | ||||
|             (action)="gotoBlog()"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" | ||||
|             (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"> | ||||
| @ -29,14 +29,10 @@ | ||||
| <core-loading [hideUntil]="loaded" class="safe-area-padding"> | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="showCompletion" [module]="module" [showManualCompletion]="true" | ||||
|         (completionChanged)="onCompletionChange()"> | ||||
|     <core-course-module-info [module]="module" (completionChanged)="onCompletionChange()" [description]="description" | ||||
|         [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="!errorMessage && hasOffline"> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
|     <core-course-module-description [description]="description" [component]="component" [componentId]="componentId" | ||||
|         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|     </core-course-module-description> | ||||
| 
 | ||||
|     <!-- Warning message. --> | ||||
|     <ion-card class="core-info-card" *ngIf="scorm && scorm.warningMessage"> | ||||
|         <ion-item> | ||||
| @ -117,14 +113,6 @@ | ||||
|             </ion-list> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <!-- Synchronization warning. --> | ||||
|         <ion-card class="core-warning-card" *ngIf="!errorMessage && hasOffline"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <!-- TOC. --> | ||||
|         <ion-card *ngIf="scorm && organizations && !skip && | ||||
|             ((scorm.displaycoursestructure && organizations.length) || organizations.length > 1)" class="addon-mod_scorm-toc"> | ||||
| @ -134,8 +122,8 @@ | ||||
|             <ion-list> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="organizations.length > 1"> | ||||
|                     <ion-label>{{ 'addon.mod_scorm.organizations' | translate }}</ion-label> | ||||
|                     <ion-select [(ngModel)]="currentOrganization.identifier" (ionChange)="loadOrganization()" | ||||
|                         interface="action-sheet" [interfaceOptions]="{header: 'addon.mod_scorm.organizations' | translate}"> | ||||
|                     <ion-select [(ngModel)]="currentOrganization.identifier" (ionChange)="loadOrganization()" interface="action-sheet" | ||||
|                         [interfaceOptions]="{header: 'addon.mod_scorm.organizations' | translate}"> | ||||
|                         <ion-select-option *ngFor="let org of organizations" [value]="org.identifier"> | ||||
|                             {{ org.title }} | ||||
|                         </ion-select-option> | ||||
| @ -155,8 +143,7 @@ | ||||
|                         <p>{{ currentOrganization.title }}</p> | ||||
|                         <div *ngFor="let sco of toc" class="core-padding-{{sco.level}} addon-mod_scorm-type-{{sco.scormtype}}"> | ||||
|                             <p *ngIf="sco.isvisible"> | ||||
|                                 <ion-icon *ngIf="sco.icon" [name]="sco.icon.icon" [attr.aria-label]="sco.icon.description" | ||||
|                                     slot="start"> | ||||
|                                 <ion-icon *ngIf="sco.icon" [name]="sco.icon.icon" [attr.aria-label]="sco.icon.description" slot="start"> | ||||
|                                 </ion-icon> | ||||
|                                 <button class="as-link" *ngIf="sco.prereq && sco.launch" (click)="open($event, false, sco.id)"> | ||||
|                                     <core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" | ||||
| @ -205,8 +192,7 @@ | ||||
|             <ion-list> | ||||
|                 <ng-container *ngIf="!downloading && !skip"> | ||||
|                     <!-- Create new attempt --> | ||||
|                     <ion-item class="ion-text-wrap" | ||||
|                         *ngIf="!scorm.forcenewattempt && numAttempts > 0 && !incomplete && attemptsLeft > 0"> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="!scorm.forcenewattempt && numAttempts > 0 && !incomplete && attemptsLeft > 0"> | ||||
|                         <ion-label>{{ 'addon.mod_scorm.newattempt' | translate }}</ion-label> | ||||
|                         <ion-checkbox slot="end" name="newAttempt" [(ngModel)]="startNewAttempt"> | ||||
|                         </ion-checkbox> | ||||
|  | ||||
| @ -1,6 +1,8 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <h1>{{ 'addon.mod_scorm.toc' | translate }}</h1> | ||||
|         <ion-title> | ||||
|             <h2>{{ 'addon.mod_scorm.toc' | translate }}</h2> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-times" aria-hidden="true"></ion-icon> | ||||
| @ -36,8 +38,7 @@ | ||||
|                     <ion-icon *ngIf="sco.icon" [name]="sco.icon.icon" [attr.aria-label]="sco.icon.description" slot="start"> | ||||
|                     </ion-icon> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="moduleId" | ||||
|                             [courseId]="courseId"> | ||||
|                         <core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                         <span *ngIf="accessInfo && accessInfo.canviewscores && sco.scoreraw"> | ||||
|                             ({{ 'addon.mod_scorm.score' | translate }}: {{sco.scoreraw}}) | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| <ion-header> | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module?.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -3,14 +3,16 @@ | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <core-button-with-spinner *ngIf="showToc" [loading]="loadingToc"> | ||||
|                 <ion-button fill="clear" *ngIf="toc.length" (click)="openToc()" | ||||
|                     [attr.aria-label]="'addon.mod_scorm.toc' | translate" aria-haspopup="true"> | ||||
|                 <ion-button fill="clear" *ngIf="toc.length" (click)="openToc()" [attr.aria-label]="'addon.mod_scorm.toc' | translate" | ||||
|                     aria-haspopup="true"> | ||||
|                     <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 </ion-button> | ||||
|             </core-button-with-spinner> | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user