forked from EVOgeek/Vmeda.Online
		
	MOBIE-3947 lint: Fix self closing tags
This commit is contained in:
		
							parent
							
								
									a0cd868179
								
							
						
					
					
						commit
						9dab24fef5
					
				| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="badge">{{ badge.name }}</h1> | ||||
| @ -11,7 +11,7 @@ | ||||
| </ion-header> | ||||
| <ion-content [core-swipe-navigation]="badges" class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!badgeLoaded" (ionRefresh)="refreshBadges($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="badgeLoaded"> | ||||
|         <ion-item-group *ngIf="badge"> | ||||
| @ -122,8 +122,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ 'core.course' | translate}}</p> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                             <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId" /> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.badges.badges' | translate }}</h1> | ||||
| @ -11,11 +11,10 @@ | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!badges.loaded" (ionRefresh)="refreshBadges($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="badges.loaded"> | ||||
|             <core-empty-box *ngIf="badges.empty" icon="fas-trophy" [message]="'addon.badges.nobadges' | translate"> | ||||
|             </core-empty-box> | ||||
|             <core-empty-box *ngIf="badges.empty" icon="fas-trophy" [message]="'addon.badges.nobadges' | translate" /> | ||||
| 
 | ||||
|             <ion-list *ngIf="!badges.empty" class="ion-no-margin"> | ||||
|                 <ion-item button class="ion-text-wrap" *ngFor="let badge of badges.items" [attr.aria-label]="badge.name" | ||||
|  | ||||
| @ -5,8 +5,7 @@ | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded"> | ||||
|     <ion-item class="ion-text-wrap" *ngFor="let entry of entries" [detail]="true" button (click)="gotoCoureListModType(entry)"> | ||||
|         <core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.iconModName" [showAlt]="false"> | ||||
|         </core-mod-icon> | ||||
|         <core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.iconModName" [showAlt]="false" /> | ||||
|         <ion-label>{{ entry.name }}</ion-label> | ||||
|     </ion-item> | ||||
| </core-loading> | ||||
|  | ||||
| @ -7,16 +7,14 @@ | ||||
|         <div *ngIf="downloadCoursesEnabled && filteredCourses.length > 0" class="core-button-spinner"> | ||||
|             <ion-button *ngIf="!prefetchCoursesData.loading" fill="clear" (click)="prefetchCourses()" | ||||
|                 [attr.aria-label]="prefetchCoursesData.statusTranslatable | translate"> | ||||
|                 <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"> | ||||
|                 </ion-icon> | ||||
|                 <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <ion-badge class="core-course-download-courses-progress" *ngIf="prefetchCoursesData.badge" role="progressbar" | ||||
|                 [attr.aria-valuemax]="prefetchCoursesData.total" [attr.aria-valuenow]="prefetchCoursesData.count" | ||||
|                 [attr.aria-valuetext]="prefetchCoursesData.badgeA11yText"> | ||||
|                 {{prefetchCoursesData.badge}} | ||||
|             </ion-badge> | ||||
|             <ion-spinner *ngIf="prefetchCoursesData.loading" [attr.aria-label]="'core.loading' | translate"> | ||||
|             </ion-spinner> | ||||
|             <ion-spinner *ngIf="prefetchCoursesData.loading" [attr.aria-label]="'core.loading' | translate" /> | ||||
|         </div> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| @ -26,8 +24,7 @@ | ||||
|         <ion-col> | ||||
|             <!-- Filter courses. --> | ||||
|             <ion-searchbar [(ngModel)]="textFilter" (ionInput)="filterTextChanged($event.target)" | ||||
|                 (ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate"> | ||||
|             </ion-searchbar> | ||||
|                 (ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate" /> | ||||
|         </ion-col> | ||||
|     </ion-row> | ||||
|     <ion-row class="ion-justify-content-between ion-align-items-center addon-block-myoverview-filter" *ngIf="hasCourses"> | ||||
| @ -70,8 +67,7 @@ | ||||
|         <ion-col> | ||||
|             <!-- Filter courses. --> | ||||
|             <ion-searchbar class="ion-hide-md-down" [(ngModel)]="textFilter" (ionInput)="filterTextChanged($event.target)" | ||||
|                 (ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate"> | ||||
|             </ion-searchbar> | ||||
|                 (ionCancel)="filterTextChanged($event.target)" [placeholder]="'core.courses.filtermycourses' | translate" /> | ||||
|         </ion-col> | ||||
|         <ion-col size="auto" *ngIf="sort.enabled"> | ||||
|             <core-combobox [label]="'core.sortby' | translate" [selection]="sort.selected" (onChange)="sortCourses($event)" | ||||
| @ -90,11 +86,11 @@ | ||||
|         <ion-col size="auto" *ngIf="isLayoutSwitcherAvailable"> | ||||
|             <ion-button *ngIf="layout === 'card'" fill="outline" (click)="toggleLayout('list')" | ||||
|                 [attr.aria-label]="'addon.block_myoverview.aria:list' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-list" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon slot="icon-only" name="fas-list" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <ion-button *ngIf="layout === 'list'" fill="outline" (click)="toggleLayout('card')" | ||||
|                 [attr.aria-label]="'addon.block_myoverview.aria:card' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-table-cells-large" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon slot="icon-only" name="fas-table-cells-large" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-col> | ||||
|     </ion-row> | ||||
| @ -114,8 +110,7 @@ | ||||
|                 {{'addon.block_myoverview.nocoursesenrolleddescription' | translate}} | ||||
|             </p> | ||||
|             <ion-button (click)="openSearch()" fill="outline"> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="start" aria-hidden="true"> | ||||
|                 </ion-icon> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="start" aria-hidden="true" /> | ||||
|                 {{'addon.block_myoverview.browseallcourses' | translate}} | ||||
|             </ion-button> | ||||
|         </ng-container> | ||||
| @ -128,8 +123,7 @@ | ||||
|                 <ion-col *ngFor="let course of filteredCourses" class="ion-no-padding" size="12" size-sm="6" size-md="6" size-lg="4" | ||||
|                     size-xl="3"> | ||||
|                     <core-courses-course-list-item [course]="course" class="core-courseoverview" [showDownload]="downloadCourseEnabled" | ||||
|                         [layout]="layout"> | ||||
|                     </core-courses-course-list-item> | ||||
|                         [layout]="layout" /> | ||||
|                 </ion-col> | ||||
|             </ion-row> | ||||
|         </ion-grid> | ||||
|  | ||||
| @ -3,21 +3,19 @@ | ||||
|         <h2>{{ 'addon.block_recentlyaccessedcourses.pluginname' | translate }}</h2> | ||||
|     </ion-label> | ||||
|     <div slot="end" class="flex-row"> | ||||
|         <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId"> | ||||
|         </core-horizontal-scroll-controls> | ||||
|         <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId" /> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded"> | ||||
|     <core-empty-box *ngIf="courses.length === 0" image="assets/img/icons/courses.svg" | ||||
|         [message]="'addon.block_recentlyaccessedcourses.nocourses' | translate"></core-empty-box> | ||||
|         [message]="'addon.block_recentlyaccessedcourses.nocourses' | translate" /> | ||||
|     <!-- List of courses. --> | ||||
|     <div [hidden]="courses.length === 0" [id]="scrollElementId" class="core-horizontal-scroll" | ||||
|         (scroll)="scrollControls.updateScrollPosition()"> | ||||
|         <div (onResize)="scrollControls.updateScrollPosition()" class="flex-row"> | ||||
|             <div class="safe-area-pseudo-padding-start"></div> | ||||
|             <ng-container *ngFor="let course of courses"> | ||||
|                 <core-courses-course-list-item [course]="course" class="core-recentlyaccessedcourses" layout="summarycard"> | ||||
|                 </core-courses-course-list-item> | ||||
|                 <core-courses-course-list-item [course]="course" class="core-recentlyaccessedcourses" layout="summarycard" /> | ||||
|             </ng-container> | ||||
|             <div class="safe-area-pseudo-padding-end"></div> | ||||
|         </div> | ||||
|  | ||||
| @ -3,8 +3,7 @@ | ||||
|         <h2>{{ 'addon.block_recentlyaccesseditems.pluginname' | translate }}</h2> | ||||
|     </ion-label> | ||||
|     <div slot="end"> | ||||
|         <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId"> | ||||
|         </core-horizontal-scroll-controls> | ||||
|         <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId" /> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded"> | ||||
| @ -16,18 +15,16 @@ | ||||
|                 <ion-card> | ||||
|                     <ion-item class="core-course-module-handler ion-text-wrap" [detail]="false" (click)="action($event, item)" button> | ||||
|                         <core-mod-icon slot="start" *ngIf="item.iconUrl" [modicon]="item.iconUrl" [modname]="item.modname" | ||||
|                             [componentId]="item.cmid" [showAlt]="false" [purpose]="item.purpose"> | ||||
|                         </core-mod-icon> | ||||
|                             [componentId]="item.cmid" [showAlt]="false" [purpose]="item.purpose" /> | ||||
|                         <ion-label> | ||||
|                             <!-- Add the icon title so accessibility tools read it. --> | ||||
|                             <span class="sr-only" *ngIf="item.iconTitle">{{ item.iconTitle }}</span> | ||||
|                             <p class="item-heading"> | ||||
|                                 <core-format-text [text]="item.name" contextLevel="module" [contextInstanceId]="item.cmid" | ||||
|                                     [courseId]="item.courseid"></core-format-text> | ||||
|                                     [courseId]="item.courseid" /> | ||||
|                             </p> | ||||
|                             <p> | ||||
|                                 <core-format-text [text]="item.coursename" contextLevel="course" [contextInstanceId]="item.courseid"> | ||||
|                                 </core-format-text> | ||||
|                                 <core-format-text [text]="item.coursename" contextLevel="course" [contextInstanceId]="item.courseid" /> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
| @ -38,6 +35,6 @@ | ||||
|     </div> | ||||
| 
 | ||||
|     <core-empty-box *ngIf="items.length <= 0" image="assets/img/icons/activities.svg" | ||||
|         [message]="'addon.block_recentlyaccesseditems.noitems' | translate"></core-empty-box> | ||||
|         [message]="'addon.block_recentlyaccesseditems.noitems' | translate" /> | ||||
| 
 | ||||
| </core-loading> | ||||
|  | ||||
| @ -8,10 +8,10 @@ | ||||
|         <ion-item class="ion-text-wrap" *ngIf="mainMenuBlock.summary"> | ||||
|             <ion-label> | ||||
|                 <core-format-text [text]="mainMenuBlock.summary" [component]="component" [componentId]="siteHomeId" contextLevel="course" | ||||
|                     [contextInstanceId]="siteHomeId"></core-format-text> | ||||
|                     [contextInstanceId]="siteHomeId" /> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <core-course-module *ngFor="let module of mainMenuBlock.modules" [module]="module" [section]="mainMenuBlock"></core-course-module> | ||||
|         <core-course-module *ngFor="let module of mainMenuBlock.modules" [module]="module" [section]="mainMenuBlock" /> | ||||
|     </ion-list> | ||||
| </core-loading> | ||||
|  | ||||
| @ -3,21 +3,19 @@ | ||||
|         <h2>{{ 'addon.block_starredcourses.pluginname' | translate }}</h2> | ||||
|     </ion-label> | ||||
|     <div slot="end" class="flex-row"> | ||||
|         <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId"> | ||||
|         </core-horizontal-scroll-controls> | ||||
|         <core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId" /> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded"> | ||||
|     <core-empty-box *ngIf="courses.length === 0" image="assets/img/icons/courses.svg" | ||||
|         [message]="'addon.block_starredcourses.nocourses' | translate"></core-empty-box> | ||||
|         [message]="'addon.block_starredcourses.nocourses' | translate" /> | ||||
|     <!-- List of courses. --> | ||||
|     <div [hidden]="courses.length === 0" [id]="scrollElementId" class="core-horizontal-scroll" | ||||
|         (scroll)="scrollControls.updateScrollPosition()"> | ||||
|         <div (onResize)="scrollControls.updateScrollPosition()" class="flex-row"> | ||||
|             <div class="safe-area-pseudo-padding-start"></div> | ||||
|             <ng-container *ngFor="let course of courses"> | ||||
|                 <core-courses-course-list-item [course]="course" class="core-block_starredcourses" layout="summarycard"> | ||||
|                 </core-courses-course-list-item> | ||||
|                 <core-courses-course-list-item [course]="course" class="core-block_starredcourses" layout="summarycard" /> | ||||
|             </ng-container> | ||||
|             <div class="safe-area-pseudo-padding-end"></div> | ||||
|         </div> | ||||
|  | ||||
| @ -2,8 +2,7 @@ | ||||
|     <ion-label class="ion-text-wrap"> | ||||
|         <h3> | ||||
|             <span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span> | ||||
|             <core-format-text [text]="course.displayname || course.fullname" contextLevel="course" [contextInstanceId]="course.id"> | ||||
|             </core-format-text> | ||||
|             <core-format-text [text]="course.displayname || course.fullname" contextLevel="course" [contextInstanceId]="course.id" /> | ||||
|         </h3> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| @ -23,15 +22,13 @@ | ||||
|                             <ion-col class="addon-block-timeline-activity-time ion-no-padding"> | ||||
|                                 <small>{{event.timesort * 1000 | coreFormatDate:"strftimetime24" }}</small> | ||||
|                                 <core-mod-icon *ngIf="event.iconUrl" [modicon]="event.iconUrl" [componentId]="event.instance" | ||||
|                                     [modname]="event.modulename" [purpose]="event.purpose"> | ||||
|                                 </core-mod-icon> | ||||
|                                     [modname]="event.modulename" [purpose]="event.purpose" /> | ||||
|                             </ion-col> | ||||
|                             <ion-col class="addon-block-timeline-activity-name ion-no-padding"> | ||||
|                                 <p class="item-heading"> | ||||
|                                     <span> | ||||
|                                         <core-format-text [text]="event.activityname || event.name" contextLevel="module" | ||||
|                                             [contextInstanceId]="event.id" [courseId]="event.course?.id"> | ||||
|                                         </core-format-text> | ||||
|                                             [contextInstanceId]="event.id" [courseId]="event.course?.id" /> | ||||
|                                     </span> | ||||
|                                     <ion-badge *ngIf="event.overdue" color="danger">{{ 'addon.block_timeline.overdue' | translate }} | ||||
|                                     </ion-badge> | ||||
| @ -39,15 +36,13 @@ | ||||
|                                 <p *ngIf="showInlineCourse && event.course"> | ||||
|                                     <span> | ||||
|                                         <core-format-text [text]="event.course.fullnamedisplay" contextLevel="course" | ||||
|                                             [contextInstanceId]="event.course.id"> | ||||
|                                         </core-format-text> | ||||
|                                             [contextInstanceId]="event.course.id" /> | ||||
|                                     </span> | ||||
|                                 </p> | ||||
|                                 <p *ngIf="event.activitystr"> | ||||
|                                     <span> | ||||
|                                         <core-format-text *ngIf="event.activitystr" [text]="event.activitystr" contextLevel="module" | ||||
|                                             [contextInstanceId]="event.id"> | ||||
|                                         </core-format-text> | ||||
|                                             [contextInstanceId]="event.id" /> | ||||
|                                     </span> | ||||
|                                 </p> | ||||
|                             </ion-col> | ||||
| @ -72,5 +67,5 @@ | ||||
|     <ion-button expand="block" (click)="loadMore.emit()" fill="outline" *ngIf="!loadingMore"> | ||||
|         {{ 'core.loadmore' | translate }} | ||||
|     </ion-button> | ||||
|     <ion-spinner *ngIf="loadingMore" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|     <ion-spinner *ngIf="loadingMore" [attr.aria-label]="'core.loading' | translate" /> | ||||
| </div> | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
|             <!-- Filter courses. --> | ||||
|             <core-search-box (onSubmit)="searchChanged($event)" (onClear)="searchChanged('')" | ||||
|                 [placeholder]="'addon.block_timeline.searchevents' | translate" autocorrect="off" spellcheck="false" [lengthCheck]="2" | ||||
|                 searchArea="AddonBlockTimeline"></core-search-box> | ||||
|                 searchArea="AddonBlockTimeline" /> | ||||
|         </ion-col> | ||||
|     </ion-row> | ||||
|     <ion-row class="ion-justify-content-between ion-align-items-center addon-block-timeline-filter"> | ||||
| @ -31,7 +31,7 @@ | ||||
|             <!-- Filter courses. --> | ||||
|             <core-search-box (onSubmit)="searchChanged($event)" (onClear)="searchChanged('')" | ||||
|                 [placeholder]="'addon.block_timeline.searchevents' | translate" autocorrect="off" spellcheck="false" [lengthCheck]="2" | ||||
|                 searchArea="AddonBlockTimeline"></core-search-box> | ||||
|                 searchArea="AddonBlockTimeline" /> | ||||
|         </ion-col> | ||||
|         <ion-col size="auto"> | ||||
|             <core-combobox [label]="'core.sortby' | translate" [formControl]="sort" (onChange)="sortChanged($event)" | ||||
| @ -46,9 +46,9 @@ | ||||
|         <ng-container *ngFor="let section of sections"> | ||||
|             <addon-block-timeline-events *ngIf="section.data$ | async as data" [events]="data.events" | ||||
|                 [showInlineCourse]="(sort$ | async) === AddonBlockTimelineSort.ByDates" [canLoadMore]="data.canLoadMore" | ||||
|                 [loadingMore]="data.loadingMore" (loadMore)="section.loadMore()" [course]="section.course"> </addon-block-timeline-events> | ||||
|                 [loadingMore]="data.loadingMore" (loadMore)="section.loadMore()" [course]="section.course" /> | ||||
|         </ng-container> | ||||
|         <core-empty-box *ngIf="sections && sections.length === 0" image="assets/img/icons/courses.svg" | ||||
|             [message]="'addon.block_timeline.noevents' | translate"></core-empty-box> | ||||
|             [message]="'addon.block_timeline.noevents' | translate" /> | ||||
|     </ng-container> | ||||
| </core-loading> | ||||
|  | ||||
| @ -1,37 +1,35 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ title | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <core-user-menu-button></core-user-menu-button> | ||||
|             <core-user-menu-button /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ion-item *ngIf="showMyEntriesToggle"> | ||||
|             <ion-label>{{ 'addon.blog.showonlyyourentries' | translate }}</ion-label> | ||||
|             <ion-toggle [(ngModel)]="onlyMyEntries" (ionChange)="onlyMyEntriesToggleChanged(onlyMyEntries)" slot="end"></ion-toggle> | ||||
|             <ion-toggle [(ngModel)]="onlyMyEntries" (ionChange)="onlyMyEntriesToggleChanged(onlyMyEntries)" slot="end" /> | ||||
|         </ion-item> | ||||
|         <core-empty-box *ngIf="entries && entries.length === 0" icon="far-newspaper" [message]="'addon.blog.noentriesyet' | translate"> | ||||
|         </core-empty-box> | ||||
|         <core-empty-box *ngIf="entries && entries.length === 0" icon="far-newspaper" [message]="'addon.blog.noentriesyet' | translate" /> | ||||
|         <ng-container *ngFor="let entry of entries"> | ||||
|             <ion-card *ngIf="!onlyMyEntries || entry.userid === currentUserId"> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <core-user-avatar [user]="entry.user" slot="start" [courseId]="entry.courseid"></core-user-avatar> | ||||
|                     <core-user-avatar [user]="entry.user" slot="start" [courseId]="entry.courseid" /> | ||||
|                     <ion-label> | ||||
|                         <div class="flex-row ion-justify-content-between ion-align-items-center"> | ||||
|                             <h2> | ||||
|                                 <core-format-text [text]="entry.subject" [contextLevel]="contextLevel" | ||||
|                                     [contextInstanceId]="contextInstanceId"> | ||||
|                                 </core-format-text> | ||||
|                                     [contextInstanceId]="contextInstanceId" /> | ||||
|                             </h2> | ||||
|                             <ion-note class="ion-text-end"> | ||||
|                                 {{ 'addon.blog.' + entry.publishTranslated! | translate}} | ||||
| @ -49,35 +47,32 @@ | ||||
|                     <ion-item class="ion-text-wrap"> | ||||
|                         <ion-label> | ||||
|                             <core-format-text [text]="entry.summary" [component]="this.component" [componentId]="entry.id" | ||||
|                                 [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"> | ||||
|                             </core-format-text> | ||||
|                                 [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" /> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="tagsEnabled && entry.tags && entry.tags!.length > 0"> | ||||
|                         <ion-label> | ||||
|                             <div slot="start">{{ 'core.tag.tags' | translate }}:</div> | ||||
|                             <core-tag-list [tags]="entry.tags"></core-tag-list> | ||||
|                             <core-tag-list [tags]="entry.tags" /> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <core-comments *ngIf="commentsEnabled" [component]="this.component" [itemId]="entry.id" area="format_blog" | ||||
|                         [instanceId]="entry.userid" contextLevel="user" [showItem]="true"> | ||||
|                     </core-comments> | ||||
|                         [instanceId]="entry.userid" contextLevel="user" [showItem]="true" /> | ||||
|                     <core-file *ngFor="let file of entry.attachmentfiles" [file]="file" [component]="this.component" | ||||
|                         [componentId]="entry.id"> | ||||
|                     </core-file> | ||||
|                         [componentId]="entry.id" /> | ||||
|                     <ion-item *ngIf="entry.uniquehash" [href]="entry.uniquehash" core-link [detail]="true"> | ||||
|                         <ion-label>{{ 'addon.blog.linktooriginalentry' | translate }}</ion-label> | ||||
|                     </ion-item> | ||||
|                 </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 | ||||
|                         <ion-icon name="fas-clock" [attr.aria-label]="'core.lastmodified' | translate" /> {{entry.lastmodified | ||||
|                         | | ||||
|                         coreTimeAgo}} | ||||
|                     </ion-note> | ||||
|                 </div> | ||||
|             </ion-card> | ||||
|         </ng-container> | ||||
|         <core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError"></core-infinite-loading> | ||||
|         <core-infinite-loading [enabled]="canLoadMore" (action)="loadMore($event)" [error]="loadMoreError" /> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -2,8 +2,7 @@ | ||||
| <core-navbar-buttons slot="end" prepend> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item *ngIf="canNavigate && !selectedMonthIsCurrent() && displayNavButtons" [priority]="900" | ||||
|             [content]="'addon.calendar.currentmonth' | translate" iconAction="fas-calendar-day" (action)="goToCurrentMonth()"> | ||||
|         </core-context-menu-item> | ||||
|             [content]="'addon.calendar.currentmonth' | translate" iconAction="fas-calendar-day" (action)="goToCurrentMonth()" /> | ||||
|     </core-context-menu> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -14,19 +13,18 @@ | ||||
|             <ion-row class="ion-align-items-center"> | ||||
|                 <ion-col class="ion-text-start" *ngIf="canNavigate"> | ||||
|                     <ion-button fill="clear" (click)="loadPrevious()" [attr.aria-label]="'core.previous' | translate"> | ||||
|                         <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true" /> | ||||
|                     </ion-button> | ||||
|                 </ion-col> | ||||
|                 <ion-col class="ion-text-center addon-calendar-period"> | ||||
|                     <h2 id="addon-calendar-monthname"> | ||||
|                         {{ periodName }} | ||||
|                         <ion-spinner *ngIf="!selectedMonthLoaded()" class="addon-calendar-loading-month"> | ||||
|                         </ion-spinner> | ||||
|                         <ion-spinner *ngIf="!selectedMonthLoaded()" class="addon-calendar-loading-month" /> | ||||
|                     </h2> | ||||
|                 </ion-col> | ||||
|                 <ion-col class="ion-text-end" *ngIf="canNavigate"> | ||||
|                     <ion-button fill="clear" (click)="loadNext()" [attr.aria-label]="'core.next' | translate"> | ||||
|                         <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true" /> | ||||
|                     </ion-button> | ||||
|                 </ion-col> | ||||
|             </ion-row> | ||||
| @ -50,8 +48,7 @@ | ||||
|                         <!-- Weeks. --> | ||||
|                         <ion-row *ngFor="let week of month.weeks" class="addon-calendar-week" role="row"> | ||||
|                             <!-- Empty slots (first week). --> | ||||
|                             <ion-col *ngFor="let value of week.prepadding" class="dayblank addon-calendar-day" role="cell"> | ||||
|                             </ion-col> | ||||
|                             <ion-col *ngFor="let value of week.prepadding" class="dayblank addon-calendar-day" role="cell" /> | ||||
|                             <ion-col *ngFor="let day of week.days" class="addon-calendar-day ion-text-center" [ngClass]='{ | ||||
|                                     "hasevents": day.hasevents, | ||||
|                                     "today": month.isCurrentMonth && day.istoday, | ||||
| @ -76,9 +73,9 @@ | ||||
|                                             [tabindex]="activeView ? 0 : -1"> | ||||
|                                             <span class="calendar_event_type calendar_event_{{event.formattedType}}"></span> | ||||
|                                             <ion-icon *ngIf="event.offline && !event.deleted" name="fas-clock" | ||||
|                                                 [attr.aria-label]="'core.notsent' | translate"></ion-icon> | ||||
|                                                 [attr.aria-label]="'core.notsent' | translate" /> | ||||
|                                             <ion-icon *ngIf="event.deleted" name="fas-trash" | ||||
|                                                 [attr.aria-label]="'core.deletedoffline' | translate"></ion-icon> | ||||
|                                                 [attr.aria-label]="'core.deletedoffline' | translate" /> | ||||
|                                             <span class="addon-calendar-event-time"> | ||||
|                                                 {{ event.timestart * 1000 | coreFormatDate: timeFormat }} | ||||
|                                             </span> | ||||
| @ -98,8 +95,7 @@ | ||||
|                                 </div> | ||||
|                             </ion-col> | ||||
|                             <!-- Empty slots (last week). --> | ||||
|                             <ion-col *ngFor="let value of week.postpadding" class="dayblank addon-calendar-day" role="cell"> | ||||
|                             </ion-col> | ||||
|                             <ion-col *ngFor="let value of week.postpadding" class="dayblank addon-calendar-day" role="cell" /> | ||||
|                         </ion-row> | ||||
|                     </div> | ||||
|                 </ion-grid> | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden=true></ion-icon> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden=true /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -10,18 +10,18 @@ | ||||
| <ion-content [fullscreen]="true"> | ||||
|     <ion-list> | ||||
|         <ion-item *ngFor="let type of types" class="addon-calendar-event" [ngClass]="['addon-calendar-eventtype-'+type]"> | ||||
|             <ion-icon [name]="typeIcons[type]" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon [name]="typeIcons[type]" slot="start" aria-hidden="true" /> | ||||
|             <ion-label>{{ 'addon.calendar.' + type + 'events' | translate}}</ion-label> | ||||
|             <ion-toggle [(ngModel)]="filter[type]" (ionChange)="onChange()" slot="end"></ion-toggle> | ||||
|             <ion-toggle [(ngModel)]="filter[type]" (ionChange)="onChange()" slot="end" /> | ||||
|         </ion-item> | ||||
|         <core-spacer *ngIf="filter.course || filter.category || filter.group"></core-spacer> | ||||
|         <core-spacer *ngIf="filter.course || filter.category || filter.group" /> | ||||
|         <ng-container *ngIf="filter.course || filter.category || filter.group"> | ||||
|             <ion-radio-group [(ngModel)]="courseId" (ionChange)="onChange()"> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let course of sortedCourses"> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="course.shortname"></core-format-text> | ||||
|                         <core-format-text [text]="course.shortname" /> | ||||
|                     </ion-label> | ||||
|                     <ion-radio slot="end" [value]="course.id"></ion-radio> | ||||
|                     <ion-radio slot="end" [value]="course.id" /> | ||||
|                 </ion-item> | ||||
|             </ion-radio-group> | ||||
|         </ng-container> | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <core-loading [hideUntil]="loaded"> | ||||
|     <core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="fas-calendar" [message]="'addon.calendar.noevents' | translate"> | ||||
|     </core-empty-box> | ||||
|     <core-empty-box *ngIf="!filteredEvents || !filteredEvents.length" icon="fas-calendar" | ||||
|         [message]="'addon.calendar.noevents' | translate" /> | ||||
| 
 | ||||
|     <ion-list *ngIf="filteredEvents && filteredEvents.length" class="list-item-limited-width"> | ||||
|         <ng-container *ngFor="let event of filteredEvents"> | ||||
| @ -8,9 +8,8 @@ | ||||
|                 <ion-item class="ion-text-wrap addon-calendar-event" [attr.aria-label]="event.name" (click)="eventClicked(event)" button | ||||
|                     [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" [detail]="false"> | ||||
|                     <core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" slot="start" [modname]="event.modulename" | ||||
|                         [componentId]="event.instance" [showAlt]="false" [purpose]="event.purpose"></core-mod-icon> | ||||
|                     <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true"> | ||||
|                     </ion-icon> | ||||
|                         [componentId]="event.instance" [showAlt]="false" [purpose]="event.purpose" /> | ||||
|                     <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true" /> | ||||
|                     <ion-label> | ||||
|                         <!-- Add the icon title so accessibility tools read it. --> | ||||
|                         <span class="sr-only"> | ||||
| @ -19,18 +18,18 @@ | ||||
|                         </span> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="event.name" [contextLevel]="event.contextLevel" | ||||
|                                 [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                                 [contextInstanceId]="event.contextInstanceId" /> | ||||
|                         </p> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="event.formattedtime" [filter]="false"></core-format-text> | ||||
|                             <core-format-text [text]="event.formattedtime" [filter]="false" /> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                     <ion-note *ngIf="event.offline && !event.deleted" slot="end"> | ||||
|                         <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-clock" aria-hidden="true" /> | ||||
|                         <span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span> | ||||
|                     </ion-note> | ||||
|                     <ion-note *ngIf="event.deleted" slot="end"> | ||||
|                         <ion-icon name="fas-trash" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-trash" aria-hidden="true" /> | ||||
|                         <span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span> | ||||
|                     </ion-note> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -1,30 +1,28 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.calendar.calendarevents' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="openFilter()" [attr.aria-label]="'core.filter' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <core-context-menu> | ||||
|                 <core-context-menu-item *ngIf="!selectedDayIsCurrent()" [priority]="900" [content]="'addon.calendar.today' | translate" | ||||
|                     iconAction="fas-calendar-day" (action)="goToCurrentDay()"> | ||||
|                 </core-context-menu-item> | ||||
|                     iconAction="fas-calendar-day" (action)="goToCurrentDay()" /> | ||||
|                 <core-context-menu-item [hidden]="!loaded || !selectedDayHasOffline() || !isOnline" [priority]="400" | ||||
|                     [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event)" [iconAction]="syncIcon" | ||||
|                     [closeOnClick]="false"> | ||||
|                 </core-context-menu-item> | ||||
|                     [closeOnClick]="false" /> | ||||
|             </core-context-menu> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
| @ -34,7 +32,7 @@ | ||||
|                 <ion-row class="ion-align-items-center"> | ||||
|                     <ion-col class="ion-text-start"> | ||||
|                         <ion-button fill="clear" (click)="loadPrevious()" [attr.aria-label]="'addon.calendar.dayprev' | translate"> | ||||
|                             <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true" /> | ||||
|                         </ion-button> | ||||
|                     </ion-col> | ||||
|                     <ion-col class="ion-text-center addon-calendar-period"> | ||||
| @ -42,7 +40,7 @@ | ||||
|                     </ion-col> | ||||
|                     <ion-col class="ion-text-end"> | ||||
|                         <ion-button fill="clear" (click)="loadNext()" [attr.aria-label]="'addon.calendar.daynext' | translate"> | ||||
|                             <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true" /> | ||||
|                         </ion-button> | ||||
|                     </ion-col> | ||||
|                 </ion-row> | ||||
| @ -54,14 +52,13 @@ | ||||
|                         <!-- There is data to be synchronized --> | ||||
|                         <ion-card class="core-warning-card list-item-limited-width" *ngIf="day.hasOffline"> | ||||
|                             <ion-item> | ||||
|                                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                                 <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'core.day' | translate} }}</ion-label> | ||||
|                             </ion-item> | ||||
|                         </ion-card> | ||||
| 
 | ||||
|                         <core-empty-box *ngIf="!day.filteredEvents || !day.filteredEvents.length" icon="fas-calendar" | ||||
|                             [message]="'addon.calendar.noevents' | translate"> | ||||
|                         </core-empty-box> | ||||
|                             [message]="'addon.calendar.noevents' | translate" /> | ||||
| 
 | ||||
|                         <ion-list *ngIf="day.filteredEvents && day.filteredEvents.length" class="list-item-limited-width"> | ||||
|                             <ng-container *ngFor="let event of day.filteredEvents"> | ||||
| @ -70,11 +67,9 @@ | ||||
|                                         (click)="gotoEvent(event.id, day)" [class.item-dimmed]="event.ispast" | ||||
|                                         [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button [detail]="false"> | ||||
|                                         <core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" slot="start" [showAlt]="false" | ||||
|                                             [modname]="event.modulename" [componentId]="event.instance" [purpose]="event.purpose"> | ||||
|                                         </core-mod-icon> | ||||
|                                             [modname]="event.modulename" [componentId]="event.instance" [purpose]="event.purpose" /> | ||||
|                                         <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" | ||||
|                                             aria-hidden="true"> | ||||
|                                         </ion-icon> | ||||
|                                             aria-hidden="true" /> | ||||
|                                         <ion-label> | ||||
|                                             <!-- Add the icon title so accessibility tools read it. --> | ||||
|                                             <span class="sr-only"> | ||||
| @ -84,18 +79,18 @@ | ||||
|                                             </span> | ||||
|                                             <p class="item-heading"> | ||||
|                                                 <core-format-text [text]="event.name" [contextLevel]="event.contextLevel" | ||||
|                                                     [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                                                     [contextInstanceId]="event.contextInstanceId" /> | ||||
|                                             </p> | ||||
|                                             <p> | ||||
|                                                 <core-format-text [text]="event.formattedtime" [filter]="false"></core-format-text> | ||||
|                                                 <core-format-text [text]="event.formattedtime" [filter]="false" /> | ||||
|                                             </p> | ||||
|                                         </ion-label> | ||||
|                                         <ion-note *ngIf="event.offline && !event.deleted" slot="end"> | ||||
|                                             <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> | ||||
|                                             <ion-icon name="fas-clock" aria-hidden="true" /> | ||||
|                                             <span class="ion-text-wrap">{{ 'core.notsent' | translate }}</span> | ||||
|                                         </ion-note> | ||||
|                                         <ion-note *ngIf="event.deleted" slot="end"> | ||||
|                                             <ion-icon name="fas-trash" aria-hidden="true"></ion-icon> | ||||
|                                             <ion-icon name="fas-trash" aria-hidden="true" /> | ||||
|                                             <span class="ion-text-wrap">{{ 'core.deletedoffline' | translate }}</span> | ||||
|                                         </ion-note> | ||||
|                                     </ion-item> | ||||
| @ -111,7 +106,7 @@ | ||||
|     <!-- Create a calendar event. --> | ||||
|     <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate && loaded"> | ||||
|         <ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate"> | ||||
|             <ion-icon name="fas-plus" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-plus" aria-hidden="true" /> | ||||
|             <span class="sr-only">{{ 'addon.calendar.newevent' | translate }}</span> | ||||
|         </ion-fab-button> | ||||
|     </ion-fab> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ title | translate }}</h1> | ||||
| @ -10,7 +10,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
| @ -20,9 +20,8 @@ | ||||
|                 <ion-label position="stacked"> | ||||
|                     <p class="item-heading" [core-mark-required]="true">{{ 'addon.calendar.eventname' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-input type="text" name="name" [placeholder]="'addon.calendar.eventname' | translate" formControlName="name"> | ||||
|                 </ion-input> | ||||
|                 <core-input-errors [control]="form.controls.name" [errorMessages]="errors"></core-input-errors> | ||||
|                 <ion-input type="text" name="name" [placeholder]="'addon.calendar.eventname' | translate" formControlName="name" /> | ||||
|                 <core-input-errors [control]="form.controls.name" [errorMessages]="errors" /> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Date. --> | ||||
| @ -31,9 +30,8 @@ | ||||
|                     <p class="item-heading" [core-mark-required]="true">{{ 'core.date' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-datetime formControlName="timestart" [placeholder]="'core.date' | translate" [displayFormat]="dateFormat" | ||||
|                     [max]="maxDate" [min]="minDate" [displayTimezone]="displayTimezone"> | ||||
|                 </ion-datetime> | ||||
|                 <core-input-errors [control]="form.controls.timestart" [errorMessages]="errors"></core-input-errors> | ||||
|                     [max]="maxDate" [min]="minDate" [displayTimezone]="displayTimezone" /> | ||||
|                 <core-input-errors [control]="form.controls.timestart" [errorMessages]="errors" /> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Type. --> | ||||
| @ -108,7 +106,7 @@ | ||||
|                 <!-- Loading groups. --> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="loadingGroups"> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner *ngIf="loadingGroups" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         <ion-spinner *ngIf="loadingGroups" [attr.aria-label]="'core.loading' | translate" /> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ng-container> | ||||
| @ -121,7 +119,7 @@ | ||||
|                     </ion-label> | ||||
|                     <ion-button fill="clear" (click)="addReminder()" slot="end" | ||||
|                         [attr.aria-label]="'addon.calendar.setnewreminder' | translate"> | ||||
|                         <ion-icon name="fas-plus" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-plus" slot="icon-only" aria-hidden="true" /> | ||||
|                     </ion-button> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item *ngFor="let reminder of reminders" class="ion-text-wrap"> | ||||
| @ -129,7 +127,7 @@ | ||||
|                         <p>{{ reminder.label }}</p> | ||||
|                     </ion-label> | ||||
|                     <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-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true" /> | ||||
|                     </ion-button> | ||||
|                 </ion-item> | ||||
|             </ng-container> | ||||
| @ -146,31 +144,30 @@ | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.calendar.durationnone' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="end" [value]="0"></ion-radio> | ||||
|                         <ion-radio slot="end" [value]="0" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.calendar.durationuntil' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="end" [value]="1"></ion-radio> | ||||
|                         <ion-radio slot="end" [value]="1" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item *ngIf="form.controls.duration.value === 1"> | ||||
|                         <ion-label position="stacked"></ion-label> | ||||
|                         <ion-label position="stacked" /> | ||||
|                         <ion-datetime formControlName="timedurationuntil" [max]="maxDate" [min]="minDate" | ||||
|                             [placeholder]="'addon.calendar.durationuntil' | translate" [displayFormat]="dateFormat" | ||||
|                             [displayTimezone]="displayTimezone"> | ||||
|                         </ion-datetime> | ||||
|                             [displayTimezone]="displayTimezone" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.calendar.durationminutes' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="end" [value]="2"></ion-radio> | ||||
|                         <ion-radio slot="end" [value]="2" /> | ||||
|                     </ion-item> | ||||
|                     <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-item> | ||||
|                 </ion-radio-group> | ||||
|             </div> | ||||
| @ -181,14 +178,13 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ 'addon.calendar.repeatevent' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-checkbox slot="end" formControlName="repeat"></ion-checkbox> | ||||
|                     <ion-checkbox slot="end" formControlName="repeat" /> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label position="stacked"> | ||||
|                         <p class="item-heading">{{ 'addon.calendar.repeatweeksl' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-input type="number" name="repeats" formControlName="repeats" [disabled]="!form.controls.repeat.value"> | ||||
|                     </ion-input> | ||||
|                     <ion-input type="number" name="repeats" formControlName="repeats" [disabled]="!form.controls.repeat.value" /> | ||||
|                 </ion-item> | ||||
|             </ng-container> | ||||
| 
 | ||||
| @ -204,13 +200,13 @@ | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.calendar.repeateditall' | translate:{$a: otherEventsCount} }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="end" value="1"></ion-radio> | ||||
|                         <ion-radio slot="end" value="1" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.calendar.repeateditthis' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="end" value="0"></ion-radio> | ||||
|                         <ion-radio slot="end" value="0" /> | ||||
|                     </ion-item> | ||||
|                 </ion-radio-group> | ||||
|             </div> | ||||
| @ -222,7 +218,7 @@ | ||||
|                 </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> | ||||
|                     [autoSave]="false" /> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <!-- Location. --> | ||||
| @ -230,8 +226,7 @@ | ||||
|                 <ion-label position="stacked"> | ||||
|                     <p class="item-heading">{{ 'core.location' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-input type="text" name="location" [placeholder]="'core.location' | translate" formControlName="location"> | ||||
|                 </ion-input> | ||||
|                 <ion-input type="text" name="location" [placeholder]="'core.location' | translate" formControlName="location" /> | ||||
|             </ion-item> | ||||
|         </form> | ||||
|         <div collapsible-footer appearOnBottom *ngIf="loaded && !error" slot="fixed"> | ||||
|  | ||||
| @ -1,42 +1,38 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="event"> | ||||
|                 <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" /> | ||||
|             </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)" | ||||
|                     [iconAction]="syncIcon" [closeOnClick]="false"> | ||||
|                 </core-context-menu-item> | ||||
|                     [iconAction]="syncIcon" [closeOnClick]="false" /> | ||||
|                 <core-context-menu-item [hidden]="!event || !event.canedit || event.deleted || (!canEdit && event.id > 0)" [priority]="300" | ||||
|                     [content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-pen"> | ||||
|                 </core-context-menu-item> | ||||
|                     [content]="'core.edit' | translate" (action)="openEdit()" iconAction="fas-pen" /> | ||||
|                 <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 [hidden]="!event || !event.deleted" [priority]="200" [content]="'core.restore' | translate" | ||||
|                     (action)="undoDelete()" iconAction="fas-rotate-left"></core-context-menu-item> | ||||
|                     (action)="undoDelete()" iconAction="fas-rotate-left" /> | ||||
|             </core-context-menu> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content [core-swipe-navigation]="events"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!eventLoaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="eventLoaded"> | ||||
|         <ion-list *ngIf="event"> | ||||
|             <ion-item class="ion-text-wrap addon-calendar-event" collapsible [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> | ||||
|                 <core-mod-icon *ngIf="event.moduleIcon" [modicon]="event.moduleIcon" [showAlt]="false" [modname]="event.modulename" | ||||
|                     [componentId]="event.instance" slot="start" [purpose]="event.purpose"></core-mod-icon> | ||||
|                 <ion-icon *ngIf=" event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" aria-hidden="true" slot="start"> | ||||
|                 </ion-icon> | ||||
|                     [componentId]="event.instance" slot="start" [purpose]="event.purpose" /> | ||||
|                 <ion-icon *ngIf=" event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" aria-hidden="true" slot="start" /> | ||||
|                 <ion-label> | ||||
|                     <!-- Add the icon title so accessibility tools read it. --> | ||||
|                     <span class="sr-only"> | ||||
| @ -45,25 +41,24 @@ | ||||
|                     </span> | ||||
|                     <h1> | ||||
|                         <core-format-text [text]="event.name" [contextLevel]="event.contextLevel" | ||||
|                             [contextInstanceId]="event.contextInstanceId"> | ||||
|                         </core-format-text> | ||||
|                             [contextInstanceId]="event.contextInstanceId" /> | ||||
|                     </h1> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <!-- There is data to be synchronized --> | ||||
|             <ion-card class="core-warning-card" *ngIf="hasOffline || event.deleted"> | ||||
|                 <ion-item> | ||||
|                     <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                     <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendarevent' | translate} }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.calendar.when' | translate }}</p> | ||||
|                     <core-format-text [text]="event.formattedtime" [filter]="false"></core-format-text> | ||||
|                     <core-format-text [text]="event.formattedtime" [filter]="false" /> | ||||
|                 </ion-label> | ||||
|                 <ion-note slot="end" *ngIf="event.deleted"> | ||||
|                     <ion-icon name="fas-trash" aria-hidden="true"></ion-icon> {{ 'core.deletedoffline' | translate }} | ||||
|                     <ion-icon name="fas-trash" aria-hidden="true" /> {{ 'core.deletedoffline' | translate }} | ||||
|                 </ion-note> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
| @ -76,8 +71,7 @@ | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'core.course' | translate}}</p> | ||||
|                     <p> | ||||
|                         <core-format-text [text]="courseName" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                         <core-format-text [text]="courseName" contextLevel="course" [contextInstanceId]="courseId" /> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -85,8 +79,7 @@ | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'core.group' | translate}}</p> | ||||
|                     <p> | ||||
|                         <core-format-text [text]="groupName" contextLevel="course" [contextInstanceId]="event.courseid"> | ||||
|                         </core-format-text> | ||||
|                         <core-format-text [text]="groupName" contextLevel="course" [contextInstanceId]="event.courseid" /> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -94,8 +87,7 @@ | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'core.category' | translate}}</p> | ||||
|                     <p> | ||||
|                         <core-format-text [text]="categoryPath" contextLevel="coursecat" [contextInstanceId]="event.categoryid"> | ||||
|                         </core-format-text> | ||||
|                         <core-format-text [text]="categoryPath" contextLevel="coursecat" [contextInstanceId]="event.categoryid" /> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -104,7 +96,7 @@ | ||||
|                     <p class="item-heading">{{ 'core.description' | translate}}</p> | ||||
|                     <p> | ||||
|                         <core-format-text [text]="event.description" [contextLevel]="event.contextLevel" | ||||
|                             [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                             [contextInstanceId]="event.contextInstanceId" /> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -114,7 +106,7 @@ | ||||
|                     <p> | ||||
|                         <a [href]="event.encodedLocation" core-link auto-login="no"> | ||||
|                             <core-format-text [text]="event.location" [contextLevel]="event.contextLevel" | ||||
|                                 [contextInstanceId]="event.contextInstanceId"></core-format-text> | ||||
|                                 [contextInstanceId]="event.contextInstanceId" /> | ||||
|                         </a> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
| @ -142,7 +134,7 @@ | ||||
|                     </ion-label> | ||||
|                     <ion-button fill="clear" (click)="deleteReminder(reminder.id, $event)" [attr.aria-label]="'core.delete' | translate" | ||||
|                         slot="end"> | ||||
|                         <ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-trash" color="danger" slot="icon-only" aria-hidden="true" /> | ||||
|                     </ion-button> | ||||
|                 </ion-item> | ||||
|             </ng-container> | ||||
|  | ||||
| @ -1,55 +1,52 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </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()" [attr.aria-label]="'core.filter' | translate"> | ||||
|                 <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon slot="icon-only" name="fas-filter" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <core-context-menu> | ||||
|                 <core-context-menu-item *ngIf="showCalendar" [priority]="800" [content]="'addon.calendar.upcomingevents' | translate" | ||||
|                     iconAction="fas-table-list" (action)="toggleDisplay()"></core-context-menu-item> | ||||
|                     iconAction="fas-table-list" (action)="toggleDisplay()" /> | ||||
|                 <core-context-menu-item *ngIf="!showCalendar" [priority]="800" [content]="'addon.calendar.monthlyview' | translate" | ||||
|                     iconAction="fas-calendar-days" (action)="toggleDisplay()"></core-context-menu-item> | ||||
|                     iconAction="fas-calendar-days" (action)="toggleDisplay()" /> | ||||
|                 <core-context-menu-item [priority]="600" [content]="'core.settings.settings' | translate" (action)="openSettings()" | ||||
|                     iconAction="fas-gears"> | ||||
|                 </core-context-menu-item> | ||||
|                     iconAction="fas-gears" /> | ||||
|                 <core-context-menu-item [hidden]="!loaded || !hasOffline || !isOnline" [priority]="400" | ||||
|                     [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(undefined, $event, true)" | ||||
|                     [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item> | ||||
|                     [iconAction]="syncIcon" [closeOnClick]="false" /> | ||||
|             </core-context-menu> | ||||
|             <core-user-menu-button></core-user-menu-button> | ||||
|             <core-user-menu-button /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <!-- There is data to be synchronized --> | ||||
|     <ion-card class="core-warning-card" *ngIf="hasOffline"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|             <ion-label>{{ 'core.hasdatatosync' | translate:{$a: 'addon.calendar.calendar' | translate} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <addon-calendar-calendar [hidden]="!showCalendar" [initialYear]="year" [initialMonth]="month" [filter]="filter" | ||||
|         [displayNavButtons]="showCalendar" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)"> | ||||
|     </addon-calendar-calendar> | ||||
|         [displayNavButtons]="showCalendar" (onEventClicked)="gotoEvent($event)" (onDayClicked)="gotoDay($event)" /> | ||||
| 
 | ||||
|     <addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [filter]="filter" (onEventClicked)="gotoEvent($event)"> | ||||
|     </addon-calendar-upcoming-events> | ||||
|     <addon-calendar-upcoming-events *ngIf="loadUpcoming" [hidden]="showCalendar" [filter]="filter" (onEventClicked)="gotoEvent($event)" /> | ||||
| 
 | ||||
|     <!-- Create a calendar event. --> | ||||
|     <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canCreate"> | ||||
|         <ion-fab-button (click)="openEdit()" [attr.aria-label]="'addon.calendar.newevent' | translate"> | ||||
|             <ion-icon name="fas-plus" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-plus" aria-hidden="true" /> | ||||
|             <span class="sr-only">{{ 'addon.calendar.newevent' | translate }}</span> | ||||
|         </ion-fab-button> | ||||
|     </ion-fab> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'core.settings.settings' | translate }}</h1> | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" [contextLevel]="contextLevel" [contextInstanceId]="contextInstanceId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| @ -14,7 +13,7 @@ | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!competencies.loaded" (ionRefresh)="refreshCompetencies($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="competencies.loaded"> | ||||
|             <ion-list> | ||||
| @ -24,8 +23,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="competency.competency.shortname" [contextLevel]="contextLevel" | ||||
|                                 [contextInstanceId]="contextInstanceId"> | ||||
|                             </core-format-text> <em>{{competency.competency.idnumber}}</em> | ||||
|                                 [contextInstanceId]="contextInstanceId" /> <em>{{competency.competency.idnumber}}</em> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" *ngIf="competency.usercompetency" | ||||
|  | ||||
| @ -1,25 +1,24 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="competency"> | ||||
|                 <core-format-text [text]="competency.competency.competency.shortname" [contextLevel]="contextLevel" | ||||
|                     [contextInstanceId]="contextInstanceId"> | ||||
|                 </core-format-text> <small>{{ competency.competency.competency.idnumber }}</small> | ||||
|                     [contextInstanceId]="contextInstanceId" /> <small>{{ competency.competency.competency.idnumber }}</small> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content [core-swipe-navigation]="competencies" class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!competencyLoaded" (ionRefresh)="refreshCompetency($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="competencyLoaded"> | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <core-user-avatar [user]="user" slot="start"></core-user-avatar> | ||||
|                 <core-user-avatar [user]="user" slot="start" /> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ user.fullname }}</p> | ||||
|                 </ion-label> | ||||
| @ -30,8 +29,7 @@ | ||||
|             <ion-item class="ion-text-wrap" *ngIf="competency.competency.competency.description"> | ||||
|                 <ion-label> | ||||
|                     <core-format-text [text]="competency.competency.competency.description" [contextLevel]="contextLevel" | ||||
|                         [contextInstanceId]="contextInstanceId"> | ||||
|                     </core-format-text> | ||||
|                         [contextInstanceId]="contextInstanceId" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap only-links"> | ||||
| @ -40,26 +38,22 @@ | ||||
|                     <p> | ||||
|                         <a *ngIf="competency.competency.comppath.showlinks" [href]="competencyFrameworkUrl" core-link> | ||||
|                             <core-format-text [text]="competency.competency.comppath.framework.name" [contextLevel]="contextLevel" | ||||
|                                 [contextInstanceId]="contextInstanceId"> | ||||
|                             </core-format-text> | ||||
|                                 [contextInstanceId]="contextInstanceId" /> | ||||
|                         </a> | ||||
|                         <ng-container *ngIf="!competency.competency.comppath.showlinks"> | ||||
|                             <core-format-text [text]="competency.competency.comppath.framework.name" [contextLevel]="contextLevel" | ||||
|                                 [contextInstanceId]="contextInstanceId"> | ||||
|                             </core-format-text> | ||||
|                                 [contextInstanceId]="contextInstanceId" /> | ||||
|                         </ng-container> | ||||
|                          /  | ||||
|                         <ng-container *ngFor="let ancestor of competency.competency.comppath.ancestors"> | ||||
|                             <button *ngIf="competency.competency.comppath.showlinks" (click)="openCompetencySummary(ancestor.id)" | ||||
|                                 class="as-link"> | ||||
|                                 <core-format-text [text]="ancestor.name" [contextLevel]="contextLevel" | ||||
|                                     [contextInstanceId]="contextInstanceId"> | ||||
|                                 </core-format-text> | ||||
|                                     [contextInstanceId]="contextInstanceId" /> | ||||
|                             </button> | ||||
|                             <ng-container *ngIf="!competency.competency.comppath.showlinks"> | ||||
|                                 <core-format-text [text]="ancestor.name" [contextLevel]="contextLevel" | ||||
|                                     [contextInstanceId]="contextInstanceId"> | ||||
|                                 </core-format-text> | ||||
|                                     [contextInstanceId]="contextInstanceId" /> | ||||
|                             </ng-container> | ||||
|                             <ng-container *ngIf="!ancestor.last"> / </ng-container> | ||||
|                         </ng-container> | ||||
| @ -76,8 +70,7 @@ | ||||
|                         <p *ngFor="let relatedcomp of competency.competency.relatedcompetencies"> | ||||
|                             <button (click)="openCompetencySummary(relatedcomp.id)" class="as-link"> | ||||
|                                 <core-format-text [text]="relatedcomp.shortname" [contextLevel]="contextLevel" | ||||
|                                     [contextInstanceId]="contextInstanceId"> | ||||
|                                 </core-format-text> - {{ relatedcomp.idnumber }} | ||||
|                                     [contextInstanceId]="contextInstanceId" /> - {{ relatedcomp.idnumber }} | ||||
|                             </button> | ||||
|                         </p> | ||||
|                     </ng-container> | ||||
| @ -91,12 +84,10 @@ | ||||
|                     </p> | ||||
|                     <ion-item class="ion-text-wrap" *ngFor="let activity of coursemodules" [href]="activity.url" | ||||
|                         [attr.aria-label]="activity.name" core-link capture="true"> | ||||
|                         <core-mod-icon slot="start" [modicon]="activity.iconurl" [showAlt]="false" *ngIf="activity.iconurl"> | ||||
|                         </core-mod-icon> | ||||
|                         <core-mod-icon slot="start" [modicon]="activity.iconurl" [showAlt]="false" *ngIf="activity.iconurl" /> | ||||
|                         <ion-label> | ||||
|                             <core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id" | ||||
|                                 [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                                 [courseId]="courseId" /> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-label> | ||||
| @ -136,7 +127,7 @@ | ||||
|             <ion-card *ngFor="let evidence of competency.evidence"> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="evidence.actionuser" core-user-link [userId]="evidence.actionuser.id" | ||||
|                     [courseId]="courseId"> | ||||
|                     <core-user-avatar [user]="evidence.actionuser" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|                     <core-user-avatar [user]="evidence.actionuser" slot="start" [linkProfile]="false" /> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ evidence.actionuser.fullname }}</p> | ||||
|                         <p>{{ evidence.timemodified * 1000 | coreFormatDate }}</p> | ||||
|  | ||||
| @ -1,28 +1,26 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="competency"> | ||||
|                 <core-format-text [text]="competency.competency.shortname" [contextLevel]="contextLevel" | ||||
|                     [contextInstanceId]="contextInstanceId"> | ||||
|                 </core-format-text> <small>{{ competency.competency.idnumber }}</small> | ||||
|                     [contextInstanceId]="contextInstanceId" /> <small>{{ competency.competency.idnumber }}</small> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!competencyLoaded" (ionRefresh)="refreshCompetency($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="competencyLoaded"> | ||||
|         <ion-card *ngIf="competency"> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="competency.competency.description"> | ||||
|                 <ion-label> | ||||
|                     <core-format-text [text]="competency.competency.description" [contextLevel]="contextLevel" | ||||
|                         [contextInstanceId]="contextInstanceId"> | ||||
|                     </core-format-text> | ||||
|                         [contextInstanceId]="contextInstanceId" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
| @ -30,14 +28,12 @@ | ||||
|                     <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
|                     <p> | ||||
|                         <core-format-text [text]="competency.comppath.framework.name" [contextLevel]="contextLevel" | ||||
|                             [contextInstanceId]="contextInstanceId"> | ||||
|                         </core-format-text> | ||||
|                             [contextInstanceId]="contextInstanceId" /> | ||||
|                         <ng-container *ngFor="let ancestor of competency.comppath.ancestors"> | ||||
|                              /  | ||||
|                             <button class="as-link" (click)="openCompetencySummary(ancestor.id)"> | ||||
|                                 <core-format-text [text]="ancestor.name" [contextLevel]="contextLevel" | ||||
|                                     [contextInstanceId]="contextInstanceId"> | ||||
|                                 </core-format-text> | ||||
|                                     [contextInstanceId]="contextInstanceId" /> | ||||
|                             </button> | ||||
|                         </ng-container> | ||||
|                     </p> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.competency.coursecompetencies' | translate }}</h1> | ||||
| @ -10,7 +10,7 @@ | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!competencies.loaded" (ionRefresh)="refreshCourseCompetencies($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="competencies.loaded"> | ||||
|         <ion-card *ngIf="!user && courseCompetencies && courseCompetencies.statistics.competencycount > 0"> | ||||
| @ -29,8 +29,7 @@ | ||||
|                         {x: courseCompetencies.statistics.proficientcompetencycount, y: courseCompetencies.statistics.competencycount} } }} | ||||
|                     </span> | ||||
|                     <core-progress-bar [progress]="courseCompetencies.statistics.proficientcompetencypercentage" | ||||
|                         ariaDescribedBy="addon-competency-course-{{courseId}}-progress"> | ||||
|                     </core-progress-bar> | ||||
|                         ariaDescribedBy="addon-competency-course-{{courseId}}-progress" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" | ||||
| @ -39,8 +38,8 @@ | ||||
|                     <p class="item-heading">{{ 'addon.competency.competenciesmostoftennotproficientincourse' | translate }}</p> | ||||
|                     <p *ngFor="let comp of courseCompetencies.statistics.leastproficient"> | ||||
|                         <button class="as-link" (click)="openCompetencySummary(comp.id)"> | ||||
|                             <core-format-text [text]="comp.shortname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                             </core-format-text> - {{ comp.idnumber }} | ||||
|                             <core-format-text [text]="comp.shortname" contextLevel="course" [contextInstanceId]="courseId" /> - {{ | ||||
|                             comp.idnumber }} | ||||
|                         </button> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
| @ -52,15 +51,14 @@ | ||||
|         </h2> | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <core-user-avatar [user]="user" slot="start"></core-user-avatar> | ||||
|                 <core-user-avatar [user]="user" slot="start" /> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ user.fullname }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|         <core-empty-box *ngIf="courseCompetencies && courseCompetencies.statistics.competencycount === 0" icon="fas-award" | ||||
|             message="{{ 'addon.competency.nocompetenciesincourse' | translate }}"> | ||||
|         </core-empty-box> | ||||
|             message="{{ 'addon.competency.nocompetenciesincourse' | translate }}" /> | ||||
| 
 | ||||
|         <div *ngIf="competencies.loaded"> | ||||
|             <ion-card *ngFor="let competency of competencies.items"> | ||||
| @ -68,8 +66,8 @@ | ||||
|                     [attr.aria-label]="competency.competency.shortname" [detail]="true" button> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="competency.competency.shortname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                             </core-format-text> <em>{{competency.competency.idnumber}}</em> | ||||
|                             <core-format-text [text]="competency.competency.shortname" contextLevel="course" | ||||
|                                 [contextInstanceId]="courseId" /> <em>{{competency.competency.idnumber}}</em> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" *ngIf="competency.usercompetencycourse && competency.usercompetencycourse.gradename" | ||||
| @ -81,8 +79,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p *ngIf="competency.competency.description"> | ||||
|                             <core-format-text [text]="competency.competency.description" contextLevel="course" | ||||
|                                 [contextInstanceId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                                 [contextInstanceId]="courseId" /> | ||||
|                         </p> | ||||
|                         <div> | ||||
|                             <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
| @ -90,24 +87,20 @@ | ||||
|                                 <a *ngIf="competency.comppath.showlinks" [href]="getCompetencyFrameworkUrl(competency)" core-link | ||||
|                                     [title]="competency.comppath.framework.name"> | ||||
|                                     <core-format-text [text]="competency.comppath.framework.name" contextLevel="course" | ||||
|                                         [contextInstanceId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                         [contextInstanceId]="courseId" /> | ||||
|                                 </a> | ||||
|                                 <ng-container *ngIf="!competency.comppath.showlinks"> | ||||
|                                     <core-format-text [text]="competency.comppath.framework.name" contextLevel="course" | ||||
|                                         [contextInstanceId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                         [contextInstanceId]="courseId" /> | ||||
|                                 </ng-container> | ||||
|                                  /  | ||||
|                                 <ng-container *ngFor="let ancestor of competency.comppath.ancestors"> | ||||
|                                     <button class="as-link" *ngIf="competency.comppath.showlinks" | ||||
|                                         (click)="openCompetencySummary(ancestor.id)"> | ||||
|                                         <core-format-text [text]="ancestor.name" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                         <core-format-text [text]="ancestor.name" contextLevel="course" [contextInstanceId]="courseId" /> | ||||
|                                     </button> | ||||
|                                     <ng-container *ngIf="!competency.comppath.showlinks"> | ||||
|                                         <core-format-text [text]="ancestor.name" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                                         </core-format-text> | ||||
|                                         <core-format-text [text]="ancestor.name" contextLevel="course" [contextInstanceId]="courseId" /> | ||||
|                                     </ng-container> | ||||
|                                     <ng-container *ngIf="!ancestor.last"> / </ng-container> | ||||
|                                 </ng-container> | ||||
| @ -126,12 +119,10 @@ | ||||
|                             </p> | ||||
|                             <ion-item class="ion-text-wrap core-course-module-handler" [attr.aria-label]="activity.name" core-link | ||||
|                                 *ngFor="let activity of competency.coursemodules" [href]="activity.url" capture="true"> | ||||
|                                 <core-mod-icon slot="start" [modicon]="activity.iconurl" [showAlt]="false" *ngIf="activity.iconurl"> | ||||
|                                 </core-mod-icon> | ||||
|                                 <core-mod-icon slot="start" [modicon]="activity.iconurl" [showAlt]="false" *ngIf="activity.iconurl" /> | ||||
|                                 <ion-label> | ||||
|                                     <core-format-text [text]="activity.name" contextLevel="module" [contextInstanceId]="activity.id" | ||||
|                                         [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                         [courseId]="courseId" /> | ||||
|                                 </ion-label> | ||||
|                             </ion-item> | ||||
|                         </div> | ||||
| @ -143,8 +134,7 @@ | ||||
|                             <ion-item class="ion-text-wrap" *ngFor="let plan of competency.plans" [href]="plan.url" | ||||
|                                 [attr.aria-label]="plan.name" core-link capture="true"> | ||||
|                                 <ion-label> | ||||
|                                     <core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid"> | ||||
|                                     </core-format-text> | ||||
|                                     <core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid" /> | ||||
|                                 </ion-label> | ||||
|                             </ion-item> | ||||
|                         </div> | ||||
|  | ||||
| @ -1,25 +1,24 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="plan"> | ||||
|                 <core-format-text [text]="plan.plan.name" contextLevel="user" [contextInstanceId]="plan.plan.userid"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="plan.plan.name" contextLevel="user" [contextInstanceId]="plan.plan.userid" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content [core-swipe-navigation]="plans" class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!competencies.loaded" (ionRefresh)="refreshLearningPlan($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="competencies.loaded"> | ||||
|         <ion-card *ngIf="user"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <core-user-avatar [user]="user" slot="start"></core-user-avatar> | ||||
|                     <core-user-avatar [user]="user" slot="start" /> | ||||
|                     <p class="item-heading">{{ user.fullname }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -29,8 +28,7 @@ | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="plan.plan.description"> | ||||
|                     <ion-label> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="plan.plan.description" contextLevel="user" [contextInstanceId]="plan.plan.userid"> | ||||
|                             </core-format-text> | ||||
|                             <core-format-text [text]="plan.plan.description" contextLevel="user" [contextInstanceId]="plan.plan.userid" /> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| @ -50,8 +48,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ 'addon.competency.template' | translate }}</p> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="plan.plan.template.shortname" contextLevel="system" [contextInstanceId]="0"> | ||||
|                             </core-format-text> | ||||
|                             <core-format-text [text]="plan.plan.template.shortname" contextLevel="system" [contextInstanceId]="0" /> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| @ -64,8 +61,7 @@ | ||||
|                         </p> | ||||
|                         <core-progress-bar [progress]="plan.proficientcompetencypercentage" | ||||
|                             [text]="plan.proficientcompetencypercentageformatted" | ||||
|                             ariaDescribedBy="addon-competency-plan-{{plan.plan.id}}-progress"> | ||||
|                         </core-progress-bar> | ||||
|                             ariaDescribedBy="addon-competency-plan-{{plan.plan.id}}-progress" /> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-list> | ||||
| @ -85,8 +81,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="competency.competency.shortname" contextLevel="user" | ||||
|                                 [contextInstanceId]="plan.plan.userid"> | ||||
|                             </core-format-text> <em>{{competency.competency.idnumber}}</em> | ||||
|                                 [contextInstanceId]="plan.plan.userid" /> <em>{{competency.competency.idnumber}}</em> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge *ngIf="competency.usercompetencyplan" slot="end" | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.competency.userplans' | translate }}</h1> | ||||
| @ -11,19 +11,16 @@ | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!plans.loaded" (ionRefresh)="refreshLearningPlans($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="plans.loaded"> | ||||
|             <core-empty-box *ngIf="plans.empty" icon="fas-route" [message]="'addon.competency.noplanswerecreated' | translate"> | ||||
| 
 | ||||
|             </core-empty-box> | ||||
|             <core-empty-box *ngIf="plans.empty" icon="fas-route" [message]="'addon.competency.noplanswerecreated' | translate" /> | ||||
|             <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-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid"> | ||||
|                             </core-format-text> | ||||
|                             <core-format-text [text]="plan.name" contextLevel="user" [contextInstanceId]="plan.userid" /> | ||||
|                         </p> | ||||
|                         <p *ngIf="plan.duedate > 0"> | ||||
|                             {{ 'addon.competency.duedate' | translate }}:  | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.coursecompletion.coursecompletion' | translate }}</h1> | ||||
| @ -10,11 +10,11 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!completionLoaded" (ionRefresh)="refreshCompletion($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="completionLoaded"> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="user"> | ||||
|             <core-user-avatar [user]="user" [courseId]="courseId" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|             <core-user-avatar [user]="user" [courseId]="courseId" slot="start" [linkProfile]="false" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{user.fullname}}</p> | ||||
|             </ion-label> | ||||
| @ -44,10 +44,10 @@ | ||||
|             <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> | ||||
|                         <core-format-text clean="true" [text]="criteria.details.criteria" [filter]="false" /> | ||||
|                     </p> | ||||
|                     <p> | ||||
|                         <core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false"></core-format-text> | ||||
|                         <core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false" /> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|                 <strong slot="end" *ngIf="criteria.complete">{{ 'core.yes' | translate }}</strong> | ||||
| @ -65,23 +65,23 @@ | ||||
|                     </ion-row> | ||||
|                     <ion-row *ngFor="let criteria of completion.completions"> | ||||
|                         <ion-col> | ||||
|                             <core-format-text clean="true" [text]="criteria.details.type" [filter]="false"></core-format-text> | ||||
|                             <core-format-text clean="true" [text]="criteria.details.type" [filter]="false" /> | ||||
|                         </ion-col> | ||||
|                         <ion-col> | ||||
|                             <core-format-text clean="true" [text]="criteria.details.criteria" [filter]="false"></core-format-text> | ||||
|                             <core-format-text clean="true" [text]="criteria.details.criteria" [filter]="false" /> | ||||
|                         </ion-col> | ||||
|                         <ion-col> | ||||
|                             <core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false"></core-format-text> | ||||
|                             <core-format-text clean="true" [text]="criteria.details.requirement" [filter]="false" /> | ||||
|                         </ion-col> | ||||
|                         <ion-col> | ||||
|                             <core-format-text [text]="criteria.details.status" [filter]="false"></core-format-text> | ||||
|                             <core-format-text [text]="criteria.details.status" [filter]="false" /> | ||||
|                         </ion-col> | ||||
|                         <ion-col *ngIf="criteria.complete">{{ 'core.yes' | translate }}</ion-col> | ||||
|                         <ion-col *ngIf="!criteria.complete">{{ 'core.no' | translate }}</ion-col> | ||||
|                         <ion-col *ngIf="criteria.timecompleted"> | ||||
|                             {{ criteria.timecompleted * 1000 | coreFormatDate :'strftimedatetimeshort' }} | ||||
|                         </ion-col> | ||||
|                         <ion-col *ngIf="!criteria.timecompleted"></ion-col> | ||||
|                         <ion-col *ngIf="!criteria.timecompleted" /> | ||||
|                     </ion-row> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -103,7 +103,7 @@ | ||||
| 
 | ||||
|         <ion-card class="core-warning-card" *ngIf="!tracked"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.coursecompletion.nottracked' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messageoutput_airnotifier.processorsettingsdesc' | translate }}</h1> | ||||
| @ -10,7 +10,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshDevices($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ng-container *ngFor="let platform of platformDevices"> | ||||
| @ -33,8 +33,7 @@ | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                         <core-button-with-spinner [loading]="device.updating" slot="end"> | ||||
|                             <ion-toggle [(ngModel)]="device.enable" (ngModelChange)="enableDevice(device, device.enable)"> | ||||
|                             </ion-toggle> | ||||
|                             <ion-toggle [(ngModel)]="device.enable" (ngModelChange)="enableDevice(device, device.enable)" /> | ||||
|                         </core-button-with-spinner> | ||||
|                     </ion-item> | ||||
|                 </ion-list> | ||||
|  | ||||
| @ -5,14 +5,14 @@ | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
| @ -23,12 +23,11 @@ | ||||
|                         onError="this.src='assets/img/group-avatar.svg'"> | ||||
|                 </div> | ||||
|                 <h2> | ||||
|                     <core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|                     <core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0" /> | ||||
|                 </h2> | ||||
|                 <p> | ||||
|                     <core-format-text *ngIf="conversation.subname" [text]="conversation.subname" contextLevel="system" | ||||
|                         [contextInstanceId]="0"> | ||||
|                     </core-format-text> | ||||
|                         [contextInstanceId]="0" /> | ||||
|                 </p> | ||||
|                 <p>{{ 'addon.messages.numparticipants' | translate:{$a: conversation.membercount} }}</p> | ||||
|             </ion-label> | ||||
| @ -36,19 +35,16 @@ | ||||
| 
 | ||||
|         <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> | ||||
|             <core-user-avatar [user]="member" [linkProfile]="false" [checkOnline]="member.showonlinestatus" slot="start" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading"> | ||||
|                     {{ member.fullname }} | ||||
|                     <ion-icon name="fas-user-slash" *ngIf="member.isblocked" | ||||
|                         [attr.aria-label]="'addon.messages.contactblocked' | translate"> | ||||
|                     </ion-icon> | ||||
|                         [attr.aria-label]="'addon.messages.contactblocked' | translate" /> | ||||
|                 </p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreMembers($event)" [error]="loadMoreError"> | ||||
|         </core-infinite-loading> | ||||
|         <core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreMembers($event)" [error]="loadMoreError" /> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,32 +1,32 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.contacts' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- Add an empty context menu so split view pages can add items, otherwise the menu disappears in some cases. --> | ||||
|             <core-context-menu></core-context-menu> | ||||
|             <core-context-menu /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </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> | ||||
|             autocorrect="off" spellcheck="false" lengthCheck="2" [disabled]="!loaded" searchArea="AddonMessagesContacts" /> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded" [message]="loadingMessage"> | ||||
|             <core-empty-box *ngIf="!hasContacts && searchString === ''" icon="fas-address-book" | ||||
|                 [message]="'addon.messages.contactlistempty' | translate"></core-empty-box> | ||||
|                 [message]="'addon.messages.contactlistempty' | translate" /> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="!hasContacts && searchString !== ''" icon="fas-address-book" | ||||
|                 [message]="'addon.messages.nousersfound' | translate"></core-empty-box> | ||||
|                 [message]="'addon.messages.nousersfound' | translate" /> | ||||
| 
 | ||||
|             <ion-list *ngFor="let contactType of contactTypes" class="ion-no-margin"> | ||||
|                 <ng-container *ngIf="contacts[contactType] && (contacts[contactType].length > 0 || contactType === searchType)"> | ||||
| @ -44,7 +44,7 @@ | ||||
|                             *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> | ||||
|                             <core-user-avatar [user]="contact" slot="start" [checkOnline]="contact.showonlinestatus" /> | ||||
|                             <ion-label> | ||||
|                                 <p class="item-heading">{{ contact.fullname }}</p> | ||||
|                             </ion-label> | ||||
|  | ||||
| @ -1,17 +1,17 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </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-magnifying-glass" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <!-- Add an empty context menu so split view pages can add items, otherwise the menu disappears in some cases. --> | ||||
|             <core-context-menu></core-context-menu> | ||||
|             <core-context-menu /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| @ -23,7 +23,7 @@ | ||||
|             <core-tab [title]="'addon.messages.contacts' | translate" (ionSelect)="selectTab('confirmed')"> | ||||
|                 <ng-template> | ||||
|                     <ion-refresher slot="fixed" [disabled]="!confirmedLoaded" (ionRefresh)="refreshData($event.target)"> | ||||
|                         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|                         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|                     </ion-refresher> | ||||
|                     <core-loading [hideUntil]="confirmedLoaded"> | ||||
|                         <ion-list class="ion-no-margin" *ngIf="confirmedContacts.length"> | ||||
| @ -31,27 +31,22 @@ | ||||
|                                 *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> | ||||
|                                     [linkProfile]="false" /> | ||||
|                                 <ion-label> | ||||
|                                     <p class="item-heading"> | ||||
|                                         <core-format-text [text]="contact.fullname" contextLevel="system" [contextInstanceId]="0"> | ||||
|                                         </core-format-text> | ||||
|                                         <core-format-text [text]="contact.fullname" contextLevel="system" [contextInstanceId]="0" /> | ||||
|                                         <ion-icon *ngIf="contact.isblocked" name="fas-user-slash" slot="end" | ||||
|                                             [attr.aria-label]="'addon.messages.contactblocked' | translate"> | ||||
|                                         </ion-icon> | ||||
|                                             [attr.aria-label]="'addon.messages.contactblocked' | translate" /> | ||||
|                                     </p> | ||||
|                                 </ion-label> | ||||
|                             </ion-item> | ||||
|                         </ion-list> | ||||
| 
 | ||||
|                         <core-empty-box *ngIf="!confirmedContacts.length" icon="far-address-book" | ||||
|                             [message]="'addon.messages.nocontactsgetstarted' | translate"> | ||||
|                         </core-empty-box> | ||||
|                             [message]="'addon.messages.nocontactsgetstarted' | translate" /> | ||||
| 
 | ||||
|                         <core-infinite-loading [enabled]="confirmedCanLoadMore" (action)="loadMore($event)" [error]="confirmedLoadMoreError" | ||||
|                             position="bottom"> | ||||
|                         </core-infinite-loading> | ||||
|                             position="bottom" /> | ||||
|                     </core-loading> | ||||
|                 </ng-template> | ||||
|             </core-tab> | ||||
| @ -61,17 +56,16 @@ | ||||
|                 badgeA11yText="addon.messages.pendingcontactrequests"> | ||||
|                 <ng-template> | ||||
|                     <ion-refresher slot="fixed" [disabled]="!requestsLoaded" (ionRefresh)="refreshData($event.target)"> | ||||
|                         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|                         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|                     </ion-refresher> | ||||
|                     <core-loading [hideUntil]="requestsLoaded"> | ||||
|                         <ion-list class="ion-no-margin" *ngIf="requests.length"> | ||||
|                             <ion-item class="ion-text-wrap addon-messages-conversation-item" *ngFor="let request of requests" | ||||
|                                 [attr.aria-label]="request.fullname" (click)="selectUser(request.id)" button | ||||
|                                 [attr.aria-current]="request.id === selectedUserId ? 'page' : 'false'" [detail]="true"> | ||||
|                                 <core-user-avatar slot="start" [user]="request" [linkProfile]="false"></core-user-avatar> | ||||
|                                 <core-user-avatar slot="start" [user]="request" [linkProfile]="false" /> | ||||
|                                 <ion-label> | ||||
|                                     <core-format-text [text]="request.fullname" contextLevel="system" [contextInstanceId]="0"> | ||||
|                                     </core-format-text> | ||||
|                                     <core-format-text [text]="request.fullname" contextLevel="system" [contextInstanceId]="0" /> | ||||
|                                     <p *ngIf="!request.iscontact"> | ||||
|                                         {{ 'addon.messages.wouldliketocontactyou' | translate }} | ||||
|                                     </p> | ||||
| @ -79,11 +73,9 @@ | ||||
|                             </ion-item> | ||||
|                         </ion-list> | ||||
|                         <core-empty-box *ngIf="!requests.length" icon="far-address-book" | ||||
|                             [message]="'addon.messages.nocontactrequests' | translate"> | ||||
|                         </core-empty-box> | ||||
|                             [message]="'addon.messages.nocontactrequests' | translate" /> | ||||
|                         <core-infinite-loading [enabled]="requestsCanLoadMore" (action)="loadMore($event)" [error]="requestsLoadMoreError" | ||||
|                             position="bottom"> | ||||
|                         </core-infinite-loading> | ||||
|                             position="bottom" /> | ||||
|                     </core-loading> | ||||
|                 </ng-template> | ||||
|             </core-tab> | ||||
|  | ||||
| @ -1,67 +1,57 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </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.svg'" core-external-content role="presentation" [siteId]="siteId"> | ||||
|                 <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> | ||||
|                     [checkOnline]="otherMember.showonlinestatus" /> | ||||
|                 <core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0" /> | ||||
|                 <ion-icon *ngIf="conversation && conversation.isfavourite" name="fas-star" | ||||
|                     [attr.aria-label]="'core.favourites' | translate"> | ||||
|                 </ion-icon> | ||||
|                     [attr.aria-label]="'core.favourites' | translate" /> | ||||
|                 <ion-icon *ngIf="conversation && conversation.ismuted" name="fas-bell-slash" | ||||
|                     [attr.aria-label]="'addon.messages.mutedconversation' | translate"> | ||||
|                 </ion-icon> | ||||
|                     [attr.aria-label]="'addon.messages.mutedconversation' | translate" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"></ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </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-circle-info"></core-context-menu-item> | ||||
|                 [content]="'addon.messages.info' | translate" (action)="viewInfo()" iconAction="fas-circle-info" /> | ||||
|             <core-context-menu-item [hidden]="isSelf || !showInfo || !isGroup" [priority]="1000" | ||||
|                 [content]="'addon.messages.groupinfo' | translate" (action)="viewInfo()" iconAction="fas-circle-info"> | ||||
|             </core-context-menu-item> | ||||
|                 [content]="'addon.messages.groupinfo' | translate" (action)="viewInfo()" iconAction="fas-circle-info" /> | ||||
|             <core-context-menu-item [hidden]="!groupMessagingEnabled || !conversation" [priority]="800" (action)="changeFavourite($event)" | ||||
|                 [closeOnClick]="false" [content]="(conversation && conversation.isfavourite ? 'addon.messages.removefromfavourites' : | ||||
|                 'addon.messages.addtofavourites') | translate" [iconAction]="favouriteIcon" [iconSlash]="favouriteIconSlash"> | ||||
|             </core-context-menu-item> | ||||
|                 'addon.messages.addtofavourites') | translate" [iconAction]="favouriteIcon" [iconSlash]="favouriteIconSlash" /> | ||||
|             <core-context-menu-item [hidden]="isSelf || !otherMember || otherMember.isblocked" [priority]="700" | ||||
|                 [content]="'addon.messages.blockuser' | translate" (action)="blockUser()" [iconAction]="blockIcon"> | ||||
|             </core-context-menu-item> | ||||
|                 [content]="'addon.messages.blockuser' | translate" (action)="blockUser()" [iconAction]="blockIcon" /> | ||||
|             <core-context-menu-item [hidden]="isSelf || !otherMember || !otherMember.isblocked" [priority]="700" | ||||
|                 [content]="'addon.messages.unblockuser' | translate" (action)="unblockUser()" [iconAction]="blockIcon"> | ||||
|             </core-context-menu-item> | ||||
|                 [content]="'addon.messages.unblockuser' | translate" (action)="unblockUser()" [iconAction]="blockIcon" /> | ||||
|             <core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" (action)="changeMute($event)" | ||||
|                 [closeOnClick]="false" [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' : | ||||
|                 'addon.messages.muteconversation') | translate" [iconAction]="muteIcon"></core-context-menu-item> | ||||
|                 'addon.messages.muteconversation') | translate" [iconAction]="muteIcon" /> | ||||
|             <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 [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> | ||||
|                 [closeOnClick]="false" [iconAction]="deleteIcon" /> | ||||
|             <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> | ||||
|                 [content]="'addon.messages.addtoyourcontacts' | translate" (action)="createContactRequest()" [iconAction]="addRemoveIcon" /> | ||||
|             <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> | ||||
|                 [iconSlash]="true" /> | ||||
|         </core-context-menu> | ||||
|     </core-navbar-buttons> | ||||
| </ion-header> | ||||
| <ion-content (ionScroll)="scrollFunction()"> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <!-- Load previous messages. --> | ||||
|         <core-infinite-loading [enabled]="canLoadMore" (action)="loadPrevious($event)" position="top" [error]="loadMoreError"> | ||||
|         </core-infinite-loading> | ||||
|         <core-infinite-loading [enabled]="canLoadMore" (action)="loadPrevious($event)" position="top" [error]="loadMoreError" /> | ||||
| 
 | ||||
|         <ng-container *ngIf="isSelf && !canLoadMore"> | ||||
|             <p class="ion-text-center">{{ 'addon.messages.selfconversation' | translate }}</p> | ||||
| @ -78,25 +68,23 @@ | ||||
| 
 | ||||
|                 <ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom > 0 && 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-icon name="fas-arrow-down" aria-hidden="true" /> | ||||
|                 </ion-chip> | ||||
| 
 | ||||
|                 <core-message [message]="message" [user]="members[message.useridfrom]" (afterRender)="last && scrollToBottom()" | ||||
|                     [text]="message.text" (onDeleteMessage)="deleteMessage(message, index)" [showDelete]="showDelete" | ||||
|                     [time]="message.timecreated"> | ||||
|                 </core-message> | ||||
|                     [time]="message.timecreated" /> | ||||
|             </ng-container> | ||||
|         </ion-list> | ||||
| 
 | ||||
|         <core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments" | ||||
|             [message]="'addon.messages.nomessagesfound' | translate"> | ||||
|         </core-empty-box> | ||||
|             [message]="'addon.messages.nomessagesfound' | translate" /> | ||||
|     </core-loading> | ||||
|     <!-- Scroll bottom. --> | ||||
|     <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && newMessages > 0"> | ||||
|         <ion-fab-button size="small" (click)="scrollToFirstUnreadMessage()" color="light" | ||||
|             [attr.aria-label]="'addon.messages.newmessages' | translate"> | ||||
|             <ion-icon name="fas-arrow-down" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-arrow-down" aria-hidden="true" /> | ||||
|             <span class="sr-only">{{ 'addon.messages.newmessages' | translate }}</span> | ||||
|         </ion-fab-button> | ||||
|         <ion-badge class="core-discussion-messages-badge">{{ newMessages }}</ion-badge> | ||||
| @ -138,6 +126,6 @@ | ||||
|             </p> | ||||
|         </div> | ||||
|         <core-send-message-form *ngIf="footerType === 'message'" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard" | ||||
|             [placeholder]="'addon.messages.newmessage' | translate"></core-send-message-form> | ||||
|             [placeholder]="'addon.messages.newmessage' | translate" /> | ||||
|     </ion-toolbar> | ||||
| </ion-footer> | ||||
|  | ||||
| @ -1,27 +1,27 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.messages' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- Add an empty context menu so split view pages can add items, otherwise the menu disappears in some cases. --> | ||||
|             <core-context-menu></core-context-menu> | ||||
|             <core-user-menu-button></core-user-menu-button> | ||||
|             <core-context-menu /> | ||||
|             <core-user-menu-button /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshData($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </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> | ||||
|             [autoFocus]="false" /> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded" [message]="loadingMessage"> | ||||
| 
 | ||||
| @ -29,7 +29,7 @@ | ||||
| 
 | ||||
|                 <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-icon name="fas-address-book" slot="start" aria-hidden="true" /> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ 'addon.messages.contacts' | translate }}</p> | ||||
|                     </ion-label> | ||||
| @ -47,12 +47,12 @@ | ||||
|                     <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)" | ||||
|                         [attr.aria-current]="result.userid === discussionUserId ? 'page' : 'false'" [detail]="false"> | ||||
|                         <core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar> | ||||
|                         <core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus" /> | ||||
|                         <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> | ||||
|                                     [contextInstanceId]="0" /> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
| @ -61,7 +61,7 @@ | ||||
|                     <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let discussion of discussions" button | ||||
|                         [attr.aria-label]="discussion.fullname" (click)="gotoDiscussion(discussion.message!.user)" | ||||
|                         [attr.aria-current]="discussion.message!.user === discussionUserId ? 'page' : 'false'" [detail]="false"> | ||||
|                         <core-user-avatar [user]="discussion" slot="start" checkOnline="false"></core-user-avatar> | ||||
|                         <core-user-avatar [user]="discussion" slot="start" checkOnline="false" /> | ||||
|                         <ion-label> | ||||
|                             <div class="flex-row ion-justify-content-between"> | ||||
|                                 <p class="item-heading">{{ discussion.fullname }}</p> | ||||
| @ -69,8 +69,7 @@ | ||||
|                                     <span *ngIf="discussion.message!.timecreated > 0" class="addon-message-last-message-date"> | ||||
|                                         {{discussion.message!.timecreated / 1000 | coreDateDayOrTime}} | ||||
|                                     </span> | ||||
|                                     <ion-icon *ngIf="discussion.unread" name="fas-circle" color="primary" aria-hidden="true"> | ||||
|                                     </ion-icon> | ||||
|                                     <ion-icon *ngIf="discussion.unread" name="fas-circle" color="primary" aria-hidden="true" /> | ||||
|                                     <span *ngIf="discussion.unread" class="sr-only"> | ||||
|                                         {{ 'addon.messages.unreadmessages' | translate }} | ||||
|                                     </span> | ||||
| @ -78,8 +77,7 @@ | ||||
|                             </div> | ||||
|                             <p> | ||||
|                                 <core-format-text clean="true" singleLine="true" [text]="discussion.message!.message" contextLevel="system" | ||||
|                                     [contextInstanceId]="0"> | ||||
|                                 </core-format-text> | ||||
|                                     [contextInstanceId]="0" /> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
| @ -87,10 +85,10 @@ | ||||
|             </ion-list> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="(!discussions || discussions.length <= 0) && !search.showResults" icon="far-comments" | ||||
|                 [message]="'addon.messages.nomessagesfound' | translate"></core-empty-box> | ||||
|                 [message]="'addon.messages.nomessagesfound' | translate" /> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="(!search.results || search.results.length <= 0) && search.showResults" icon="fas-magnifying-glass" | ||||
|                 [message]="'core.noresults' | translate"></core-empty-box> | ||||
|                 [message]="'core.noresults' | translate" /> | ||||
|         </core-loading> | ||||
|     </core-split-view> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,34 +1,34 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </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-magnifying-glass" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <ion-button (click)="gotoSettings()" [attr.aria-label]="'addon.messages.messagepreferences' | translate"> | ||||
|                 <ion-icon name="fas-gear" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-gear" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|             <!-- Add an empty context menu so split view pages can add items, otherwise the menu disappears in some cases. --> | ||||
|             <core-context-menu></core-context-menu> | ||||
|             <core-user-menu-button></core-user-menu-button> | ||||
|             <core-context-menu /> | ||||
|             <core-user-menu-button /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!loaded || !currentListEl" (ionRefresh)="refreshData($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded" [message]="loadingMessage"> | ||||
|             <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-icon name="fas-address-book" slot="start" aria-hidden="true" /> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.messages.contacts' | translate }}</h2> | ||||
|                     </ion-label> | ||||
| @ -43,8 +43,7 @@ | ||||
|                     [attr.aria-expanded]="favourites.expanded" aria-controls="addon-messages-groupconversations-favourite" role="heading" | ||||
|                     [detail]="false"> | ||||
|                     <ion-icon name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon" | ||||
|                         [class.expandable-status-icon-expanded]="favourites.expanded"> | ||||
|                     </ion-icon> | ||||
|                         [class.expandable-status-icon-expanded]="favourites.expanded" /> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.favourites' | translate }} ({{ favourites.count }})</h2> | ||||
|                     </ion-label> | ||||
| @ -55,11 +54,10 @@ | ||||
|                 </ion-item> | ||||
|                 <div [hidden]="!favourites.conversations || !favourites.expanded || favourites.loading" #favlist | ||||
|                     id="addon-messages-groupconversations-favourite"> | ||||
|                     <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}"> | ||||
|                     </ng-container> | ||||
|                     <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: favourites.conversations}" /> | ||||
|                     <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> | ||||
|                     <core-infinite-loading [enabled]="favourites.canLoadMore" (action)="loadMoreConversations(favourites, $event)" | ||||
|                         [error]="favourites.loadMoreError"></core-infinite-loading> | ||||
|                         [error]="favourites.loadMoreError" /> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="favourites.conversations && favourites.conversations.length === 0"> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.nofavourites' | translate }}</p> | ||||
| @ -68,7 +66,7 @@ | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-center" *ngIf="favourites.loading"> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate" /> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
| @ -77,8 +75,7 @@ | ||||
|                     [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 name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon" | ||||
|                         [class.expandable-status-icon-expanded]="group.expanded"> | ||||
|                     </ion-icon> | ||||
|                         [class.expandable-status-icon-expanded]="group.expanded" /> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.messages.groupconversations' | translate }} ({{ group.count }})</h2> | ||||
|                     </ion-label> | ||||
| @ -89,11 +86,10 @@ | ||||
|                 </ion-item> | ||||
|                 <div [hidden]="!group.conversations || !group.expanded || group.loading" #grouplist | ||||
|                     id="addon-messages-groupconversations-group"> | ||||
|                     <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}"> | ||||
|                     </ng-container> | ||||
|                     <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: group.conversations}" /> | ||||
|                     <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> | ||||
|                     <core-infinite-loading [enabled]="group.canLoadMore" (action)="loadMoreConversations(group, $event)" | ||||
|                         [error]="group.loadMoreError"></core-infinite-loading> | ||||
|                         [error]="group.loadMoreError" /> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="group.conversations && group.conversations.length === 0"> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.nogroupconversations' | translate }}</p> | ||||
| @ -102,7 +98,7 @@ | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-center" *ngIf="group.loading"> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate" /> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
| @ -111,8 +107,7 @@ | ||||
|                     [attr.aria-expanded]="individual.expanded" aria-controls="addon-messages-groupconversations-individual" role="heading" | ||||
|                     [detail]="false"> | ||||
|                     <ion-icon name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon" | ||||
|                         [class.expandable-status-icon-expanded]="individual.expanded"> | ||||
|                     </ion-icon> | ||||
|                         [class.expandable-status-icon-expanded]="individual.expanded" /> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.messages.individualconversations' | translate }} ({{ individual.count }})</h2> | ||||
|                     </ion-label> | ||||
| @ -123,11 +118,10 @@ | ||||
|                 </ion-item> | ||||
|                 <div [hidden]="!individual.conversations || !individual.expanded || individual.loading" #indlist | ||||
|                     id="addon-messages-groupconversations-individual"> | ||||
|                     <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}"> | ||||
|                     </ng-container> | ||||
|                     <ng-container *ngTemplateOutlet="conversationsTemplate; context: {conversations: individual.conversations}" /> | ||||
|                     <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> | ||||
|                     <core-infinite-loading [enabled]="individual.canLoadMore" (action)="loadMoreConversations(individual, $event)" | ||||
|                         [error]="individual.loadMoreError"></core-infinite-loading> | ||||
|                         [error]="individual.loadMoreError" /> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="individual.conversations && individual.conversations.length === 0"> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.noindividualconversations' | translate }}</p> | ||||
| @ -136,7 +130,7 @@ | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-center" *ngIf="individual.loading"> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate" /> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
| @ -148,9 +142,9 @@ | ||||
| <!-- 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-current]="((conversation.id && conversation.id === selectedConversationId) || | ||||
|             (conversation.userid && conversation.userid === selectedUserId)) ? 'page': 'false'" | ||||
|         (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 }}" | ||||
|         [attr.aria-label]="conversation.name"> | ||||
|         <!-- Group conversation image. --> | ||||
| @ -161,16 +155,15 @@ | ||||
| 
 | ||||
|         <!-- 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> | ||||
|             [checkOnline]="conversation.showonlinestatus" slot="start" /> | ||||
| 
 | ||||
|         <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-xmark" [title]="'addon.messages.mutedconversation' | translate"> | ||||
|                     </ion-icon> | ||||
|                     <core-format-text [text]="conversation.name" contextLevel="system" [contextInstanceId]="0" /> | ||||
|                     <ion-icon name="fas-user-slash" *ngIf="conversation.isblocked" [title]="'addon.messages.contactblocked' | translate" /> | ||||
|                     <ion-icon *ngIf="conversation.ismuted" name="fas-volume-xmark" | ||||
|                         [title]="'addon.messages.mutedconversation' | translate" /> | ||||
|                 </p> | ||||
|                 <ion-note *ngIf="conversation.lastmessagedate > 0 || conversation.unreadcount"> | ||||
|                     <span *ngIf="conversation.lastmessagedate > 0" class="addon-message-last-message-date"> | ||||
| @ -183,7 +176,7 @@ | ||||
|                 </ion-note> | ||||
|             </div> | ||||
|             <p *ngIf="conversation.subname"> | ||||
|                 <core-format-text [text]="conversation.subname" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|                 <core-format-text [text]="conversation.subname" contextLevel="system" [contextInstanceId]="0" /> | ||||
|             </p> | ||||
|             <p *ngIf="conversation.lastmessage !== undefined" class="addon-message-last-message"> | ||||
|                 <span *ngIf="conversation.sentfromcurrentuser" class="addon-message-last-message-user"> | ||||
| @ -192,7 +185,7 @@ | ||||
|                 <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> | ||||
|                     contextLevel="system" [contextInstanceId]="0" /> | ||||
|             </p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|  | ||||
| @ -1,35 +1,34 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.searchcombined' | translate }}</h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- Add an empty context menu so split view pages can add items, otherwise the menu disappears in some cases. --> | ||||
|             <core-context-menu></core-context-menu> | ||||
|             <core-context-menu /> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <core-search-box (onSubmit)="search($event)" (onClear)="clearSearch()" [disabled]="disableSearch" autocorrect="off" | ||||
|             [spellcheck]="false" [autoFocus]="true" [lengthCheck]="1" searchArea="AddonMessagesSearch"></core-search-box> | ||||
|             [spellcheck]="false" [autoFocus]="true" [lengthCheck]="1" searchArea="AddonMessagesSearch" /> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="!displaySearching" [message]="'core.searching' | translate"> | ||||
|             <ion-list *ngIf="displayResults"> | ||||
|                 <ng-container *ngTemplateOutlet="resultsTemplate; context: {item: contacts}"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="resultsTemplate; context: {item: nonContacts}"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="resultsTemplate; context: {item: messages}"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="resultsTemplate; context: {item: contacts}" /> | ||||
|                 <ng-container *ngTemplateOutlet="resultsTemplate; context: {item: nonContacts}" /> | ||||
|                 <ng-container *ngTemplateOutlet="resultsTemplate; context: {item: messages}" /> | ||||
|                 <!-- The infinite loading cannot be inside the ng-template, it fails because it doesn't find ion-content. --> | ||||
|                 <core-infinite-loading [enabled]="messages.canLoadMore" (action)="search(query, 'messages', $event)" | ||||
|                     [error]="messages.loadMoreError"></core-infinite-loading> | ||||
|                     [error]="messages.loadMoreError" /> | ||||
|             </ion-list> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="displayResults && !contacts.results.length && !nonContacts.results.length && !messages.results.length" | ||||
|                 icon="fas-magnifying-glass" [message]="'core.noresults' | translate"> | ||||
|             </core-empty-box> | ||||
|                 icon="fas-magnifying-glass" [message]="'core.noresults' | translate" /> | ||||
|         </core-loading> | ||||
|     </core-split-view> | ||||
| </ion-content> | ||||
| @ -46,13 +45,11 @@ | ||||
|         <!-- 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> | ||||
|             <core-user-avatar slot="start" [user]="result" [checkOnline]="true" [linkProfile]="false"></core-user-avatar> | ||||
|             <core-user-avatar slot="start" [user]="result" [checkOnline]="true" [linkProfile]="false" /> | ||||
|             <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> | ||||
|                     <core-format-text [text]="result.fullname" [highlight]="result.highlightName" [filter]="false" /> | ||||
|                     <ion-icon name="fas-ban" *ngIf="result.isblocked" [attr.aria-label]="'addon.messages.contactblocked' | translate" /> | ||||
|                 </p> | ||||
|                 <ion-note *ngIf="result.lastmessagedate > 0"> | ||||
|                     {{result.lastmessagedate | coreDateDayOrTime}} | ||||
| @ -62,7 +59,7 @@ | ||||
|                         {{ '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> | ||||
|                         contextLevel="system" [contextInstanceId]="0" class="addon-message-last-message-text" /> | ||||
|                 </p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| @ -75,7 +72,7 @@ | ||||
|                 </ion-button> | ||||
|             </div> | ||||
|             <div *ngIf="item.loadingMore" class="ion-padding ion-text-center"> | ||||
|                 <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                 <ion-spinner [attr.aria-label]="'core.loading' | translate" /> | ||||
|             </div> | ||||
|         </ng-container> | ||||
|     </ng-container> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.messages.messages' | translate }}</h1> | ||||
| @ -10,7 +10,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!preferencesLoaded" (ionRefresh)="refreshPreferences($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="preferencesLoaded"> | ||||
|         <!-- General settings. --> | ||||
| @ -25,7 +25,7 @@ | ||||
|                     <ion-label> | ||||
|                         <p>{{ 'addon.messages.useentertosend' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-toggle [(ngModel)]="sendOnEnter" (ngModelChange)="sendOnEnterChanged()" slot="end"></ion-toggle> | ||||
|                     <ion-toggle [(ngModel)]="sendOnEnter" (ngModelChange)="sendOnEnterChanged()" slot="end" /> | ||||
|                 </ion-item> | ||||
|             </ion-list> | ||||
|         </ion-card> | ||||
| @ -36,8 +36,7 @@ | ||||
|                 <ion-label class="ion-text-wrap"> | ||||
|                     <p>{{ 'addon.messages.blocknoncontacts' | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-toggle [(ngModel)]="contactablePrivacy" (ngModelChange)="saveContactablePrivacy(contactablePrivacy)" slot="end"> | ||||
|                 </ion-toggle> | ||||
|                 <ion-toggle [(ngModel)]="contactablePrivacy" (ngModelChange)="saveContactablePrivacy(contactablePrivacy)" slot="end" /> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-list *ngIf="advancedContactable"> | ||||
| @ -51,19 +50,19 @@ | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.contactableprivacy_onlycontacts' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="start" [value]="onlyContactsValue"></ion-radio> | ||||
|                         <ion-radio slot="start" [value]="onlyContactsValue" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap"> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.contactableprivacy_coursemember' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="start" [value]="courseMemberValue"></ion-radio> | ||||
|                         <ion-radio slot="start" [value]="courseMemberValue" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item *ngIf="allowSiteMessaging" class="ion-text-wrap"> | ||||
|                         <ion-label> | ||||
|                             <p>{{ 'addon.messages.contactableprivacy_site' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-radio slot="start" [value]="siteValue"></ion-radio> | ||||
|                         <ion-radio slot="start" [value]="siteValue" /> | ||||
|                     </ion-item> | ||||
|                 </ion-radio-group> | ||||
|             </ion-list> | ||||
| @ -72,10 +71,10 @@ | ||||
|         <!-- Notifications. --> | ||||
|         <ng-container *ngIf="preferences"> | ||||
|             <ng-container *ngIf="!groupMessagingEnabled"> | ||||
|                 <ng-container *ngTemplateOutlet="legacySettings; context: {preferences: preferences}"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="legacySettings; context: {preferences: preferences}" /> | ||||
|             </ng-container> | ||||
|             <ng-container *ngIf="groupMessagingEnabled"> | ||||
|                 <ng-container *ngTemplateOutlet="settings; context: {preferences: preferences}"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="settings; context: {preferences: preferences}" /> | ||||
|             </ng-container> | ||||
|         </ng-container> | ||||
|     </core-loading> | ||||
| @ -109,8 +108,7 @@ | ||||
|                             <!-- If notifications enabled, show toggle. --> | ||||
|                             <core-button-with-spinner *ngIf="!processor.locked" [loading]="notification['updating'+state]" slot="end"> | ||||
|                                 <ion-toggle [(ngModel)]="processor[state].checked" | ||||
|                                     (ngModelChange)="changePreferenceLegacy(notification, processor, state)"> | ||||
|                                 </ion-toggle> | ||||
|                                     (ngModelChange)="changePreferenceLegacy(notification, processor, state)" /> | ||||
|                             </core-button-with-spinner> | ||||
|                             <span *ngIf="processor.locked && processor[state].checked" class="text-gray" slot="end"> | ||||
|                                 {{'core.settings.forced' | translate }} | ||||
| @ -145,8 +143,7 @@ | ||||
|                     <ng-container *ngIf="!preferences.disableall"> | ||||
|                         <!-- If notifications enabled, show toggle. --> | ||||
|                         <core-button-with-spinner *ngIf="!processor.locked" [loading]="notification.updating" slot="end"> | ||||
|                             <ion-toggle [(ngModel)]="processor.enabled" (ngModelChange)="changePreference(notification, processor)"> | ||||
|                             </ion-toggle> | ||||
|                             <ion-toggle [(ngModel)]="processor.enabled" (ngModelChange)="changePreference(notification, processor)" /> | ||||
|                         </core-button-with-spinner> | ||||
|                         <span class="text-gray" *ngIf="processor.locked" slot="end"> | ||||
|                             {{ processor.lockedmessage }} | ||||
|  | ||||
| @ -5,15 +5,14 @@ | ||||
|         </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-xmark" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon slot="icon-only" name="fas-xmark" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </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> | ||||
|         <addon-mod-assign-feedback-plugin [assign]="assign" [submission]="submission" [userId]="userId" [plugin]="plugin" [edit]="true" /> | ||||
|         <ion-button expand="block" (click)="done($event)">{{ 'core.done' | translate }}</ion-button> | ||||
|     </form> | ||||
| </ion-content> | ||||
|  | ||||
| @ -9,12 +9,10 @@ | ||||
|                 </ion-badge> | ||||
|                 <p *ngIf="text"> | ||||
|                     <core-format-text [component]="component" [componentId]="assign.cmid" collapsible-item [text]="text" | ||||
|                         contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|                     </core-format-text> | ||||
|                         contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course" /> | ||||
|                 </p> | ||||
|                 <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" | ||||
|                     [alwaysDownload]="true"> | ||||
|                 </core-file> | ||||
|                     [alwaysDownload]="true" /> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|     </core-loading> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -12,8 +12,7 @@ | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()"> | ||||
|         <div description *ngIf="assign && assign.introattachments?.length && !assign.submissionattachments"> | ||||
|             <core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId"> | ||||
|             </core-file> | ||||
|             <core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId" /> | ||||
|         </div> | ||||
|     </core-course-module-info> | ||||
| 
 | ||||
| @ -21,8 +20,7 @@ | ||||
|     <ng-container *ngIf="assign && canViewAllSubmissions"> | ||||
|         <ion-list class="core-list-align-detail-right"> | ||||
| 
 | ||||
|             <core-group-selector [groupInfo]="groupInfo" [(selected)]="group" (selectedChange)="setGroup(group)" [courseId]="courseId"> | ||||
|             </core-group-selector> | ||||
|             <core-group-selector [groupInfo]="groupInfo" [(selected)]="group" (selectedChange)="setGroup(group)" [courseId]="courseId" /> | ||||
| 
 | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
| @ -115,19 +113,17 @@ | ||||
|         <!-- Ungrouped users. --> | ||||
|         <ion-card *ngIf="assign.teamsubmission && summary && summary.warnofungroupedusers" class="core-info-card"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-question" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-question" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.mod_assign.'+summary.warnofungroupedusers | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <div collapsible-footer *ngIf="!showLoading" slot="fixed"> | ||||
|             <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|             </core-course-module-navigation> | ||||
|             <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
|         </div> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <!-- If it's a student, display his submission. --> | ||||
|     <addon-mod-assign-submission *ngIf="!showLoading && !canViewAllSubmissions && canViewOwnSubmission" [courseId]="courseId" | ||||
|         [moduleId]="module.id"> | ||||
|     </addon-mod-assign-submission> | ||||
|         [moduleId]="module.id" /> | ||||
| </core-loading> | ||||
|  | ||||
| @ -9,12 +9,10 @@ | ||||
|                 </ion-badge> | ||||
|                 <p *ngIf="text"> | ||||
|                     <core-format-text [component]="component" [componentId]="assign.cmid" collapsible-item [text]="text" | ||||
|                         contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|                     </core-format-text> | ||||
|                         contextLevel="module" [contextInstanceId]="assign.cmid" [courseId]="assign.course" /> | ||||
|                 </p> | ||||
|                 <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" | ||||
|                     [alwaysDownload]="true"> | ||||
|                 </core-file> | ||||
|                     [alwaysDownload]="true" /> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|     </core-loading> | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|         <!-- Time limit is over. --> | ||||
|         <ion-card *ngIf="timeLimitFinished && (canEdit || canSubmit)" class="core-danger-card"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <p>{{ 'addon.mod_assign.caneditsubmission' | translate }}</p> | ||||
|                 </ion-label> | ||||
| @ -13,10 +13,10 @@ | ||||
|         <!-- User and status of the submission. --> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="!blindMarking && user" core-user-link [userId]="submitId" [courseId]="courseId" | ||||
|             [attr.aria-label]="user!.fullname"> | ||||
|             <core-user-avatar [user]="user" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|             <core-user-avatar [user]="user" slot="start" [linkProfile]="false" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ user!.fullname }}</p> | ||||
|                 <ng-container *ngTemplateOutlet="submissionStatus"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="submissionStatus" /> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
| @ -24,7 +24,7 @@ | ||||
|         <ion-item class="ion-text-wrap" *ngIf="blindMarking && !user"> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_assign.hiddenuser' | translate }} {{blindId}}</p> | ||||
|                 <ng-container *ngTemplateOutlet="submissionStatus"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="submissionStatus" /> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
| @ -32,7 +32,7 @@ | ||||
|         <ion-item class="ion-text-wrap" *ngIf="(blindMarking && user) || (!blindMarking && !user)"> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_assign.submissionstatus' | translate }}</p> | ||||
|                 <ng-container *ngTemplateOutlet="submissionStatus"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="submissionStatus" /> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
| @ -103,8 +103,7 @@ | ||||
|                             <p class="item-heading">{{ 'addon.mod_assign.timeremaining' | translate }}</p> | ||||
|                             <p *ngIf="!timeLimitEndTime" [innerHTML]="timeRemaining"></p> | ||||
|                             <core-timer *ngIf="timeLimitEndTime > 0" [endTime]="timeLimitEndTime" mode="basic" timeUpText="00:00:00" | ||||
|                                 [timeLeftClassThreshold]="-1" [underTimeClassThresholds]="[300, 900]" (finished)="timeUp()"> | ||||
|                             </core-timer> | ||||
|                                 [timeLeftClassThreshold]="-1" [underTimeClassThresholds]="[300, 900]" (finished)="timeUp()" /> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
| 
 | ||||
| @ -136,8 +135,7 @@ | ||||
|                     </ion-item> | ||||
| 
 | ||||
|                     <addon-mod-assign-submission-plugin *ngFor="let plugin of submissionPlugins" [assign]="assign" | ||||
|                         [submission]="userSubmission" [plugin]="plugin"> | ||||
|                     </addon-mod-assign-submission-plugin> | ||||
|                         [submission]="userSubmission" [plugin]="plugin" /> | ||||
| 
 | ||||
|                     <!-- Team members that need to submit it too. --> | ||||
|                     <ion-item-divider class="ion-text-wrap" *ngIf="membersToSubmit && membersToSubmit.length > 0"> | ||||
| @ -149,7 +147,7 @@ | ||||
|                         <ng-container *ngFor="let user of membersToSubmit"> | ||||
|                             <ion-item class="ion-text-wrap" core-user-link [userId]="user.id" [courseId]="courseId" | ||||
|                                 [attr.aria-label]="user.fullname"> | ||||
|                                 <core-user-avatar [user]="user" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|                                 <core-user-avatar [user]="user" slot="start" [linkProfile]="false" /> | ||||
|                                 <ion-label> | ||||
|                                     <p class="item-heading">{{ user.fullname }}</p> | ||||
|                                 </ion-label> | ||||
| @ -213,7 +211,7 @@ | ||||
|                                             <ion-button expand="block" *ngIf="submissionUrl" [href]="submissionUrl" core-link | ||||
|                                                 [showBrowserWarning]="false"> | ||||
|                                                 {{ 'core.openinbrowser' | translate }} | ||||
|                                                 <ion-icon name="fas-up-right-from-square" slot="end" aria-hidden="true"></ion-icon> | ||||
|                                                 <ion-icon name="fas-up-right-from-square" slot="end" aria-hidden="true" /> | ||||
|                                             </ion-button> | ||||
| 
 | ||||
|                                         </ng-container> | ||||
| @ -229,10 +227,9 @@ | ||||
|                             <ng-container *ngIf="canSubmit"> | ||||
|                                 <ion-item class="ion-text-wrap" *ngIf="submissionStatement"> | ||||
|                                     <ion-label> | ||||
|                                         <core-format-text [text]="submissionStatement" [filter]="false"></core-format-text> | ||||
|                                         <core-format-text [text]="submissionStatement" [filter]="false" /> | ||||
|                                     </ion-label> | ||||
|                                     <ion-checkbox slot="end" name="submissionstatement" [(ngModel)]="acceptStatement"> | ||||
|                                     </ion-checkbox> | ||||
|                                     <ion-checkbox slot="end" name="submissionstatement" [(ngModel)]="acceptStatement" /> | ||||
|                                 </ion-item> | ||||
|                                 <!-- Submit button. --> | ||||
|                                 <ion-item class="ion-text-wrap" *ngIf="!showErrorStatementSubmit"> | ||||
| @ -253,8 +250,7 @@ | ||||
|                                 </ion-item> | ||||
|                             </ng-container> | ||||
|                         </div> | ||||
|                         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="moduleId"> | ||||
|                         </core-course-module-navigation> | ||||
|                         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="moduleId" /> | ||||
|                     </div> | ||||
|                 </ng-template> | ||||
|             </core-tab> | ||||
| @ -268,12 +264,12 @@ | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ 'addon.mod_assign.currentgrade' | translate }}</p> | ||||
|                             <p> | ||||
|                                 <core-format-text [text]="feedback!.gradefordisplay" [filter]="false"></core-format-text> | ||||
|                                 <core-format-text [text]="feedback!.gradefordisplay" [filter]="false" /> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                         <ion-button slot="end" *ngIf="feedback!.advancedgrade" (click)="showAdvancedGrade()" | ||||
|                             [attr.aria-label]="'core.showadvanced' |translate"> | ||||
|                             <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" /> | ||||
|                         </ion-button> | ||||
|                     </ion-item> | ||||
| 
 | ||||
| @ -285,8 +281,7 @@ | ||||
|                                 <p class="item-heading">{{ 'addon.mod_assign.gradeoutof' | translate: {$a: gradeInfo!.grade} }}</p> | ||||
|                             </ion-label> | ||||
|                             <ion-input *ngIf="!grade.disabled" type="text" [(ngModel)]="grade.grade" min="0" [max]="gradeInfo!.grade" | ||||
|                                 [lang]="grade.lang"> | ||||
|                             </ion-input> | ||||
|                                 [lang]="grade.lang" /> | ||||
|                             <p *ngIf="grade.disabled">{{ 'addon.mod_assign.gradelocked' | translate }}</p> | ||||
|                         </ion-item> | ||||
| 
 | ||||
| @ -345,8 +340,7 @@ | ||||
| 
 | ||||
|                     <ng-container *ngIf="feedback"> | ||||
|                         <addon-mod-assign-feedback-plugin *ngFor="let plugin of feedback.plugins" [assign]="assign" | ||||
|                             [submission]="userSubmission" [userId]="submitId" [plugin]="plugin" [canEdit]="canSaveGrades"> | ||||
|                         </addon-mod-assign-feedback-plugin> | ||||
|                             [submission]="userSubmission" [userId]="submitId" [plugin]="plugin" [canEdit]="canSaveGrades" /> | ||||
|                     </ng-container> | ||||
| 
 | ||||
|                     <!-- Workflow status. --> | ||||
| @ -363,7 +357,7 @@ | ||||
|                             <p class="item-heading">{{ 'addon.mod_assign.groupsubmissionsettings' | translate }}</p> | ||||
|                             <p>{{ 'addon.mod_assign.applytoteam' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-toggle [(ngModel)]="grade.applyToAll" slot="end"></ion-toggle> | ||||
|                         <ion-toggle [(ngModel)]="grade.applyToAll" slot="end" /> | ||||
|                     </ion-item> | ||||
| 
 | ||||
|                     <!-- Attempt status. --> | ||||
| @ -387,14 +381,14 @@ | ||||
|                         </ion-item> | ||||
|                         <ion-item *ngIf="canSaveGrades && allowAddAttempt"> | ||||
|                             <ion-label>{{ 'addon.mod_assign.addattempt' | translate }}</ion-label> | ||||
|                             <ion-toggle [(ngModel)]="grade.addAttempt" slot="end"></ion-toggle> | ||||
|                             <ion-toggle [(ngModel)]="grade.addAttempt" slot="end" /> | ||||
|                         </ion-item> | ||||
|                     </ng-container> | ||||
| 
 | ||||
|                     <!-- Data about the grader (teacher who graded). --> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="grader" core-user-link [userId]="grader!.id" [courseId]="courseId" | ||||
|                         [attr.aria-label]="grader!.fullname" [detail]="true"> | ||||
|                         <core-user-avatar [user]="grader" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|                         <core-user-avatar [user]="grader" slot="start" [linkProfile]="false" /> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ 'addon.mod_assign.gradedby' | translate }}</p> | ||||
|                             <p class="item-heading">{{ grader!.fullname }}</p> | ||||
| @ -413,12 +407,12 @@ | ||||
|                     <!-- Warning message if cannot save grades. --> | ||||
|                     <ion-card *ngIf="isGrading && !canSaveGrades" class="core-warning-card"> | ||||
|                         <ion-item> | ||||
|                             <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                             <ion-label> | ||||
|                                 <p>{{ 'addon.mod_assign.cannotgradefromapp' | translate }}</p> | ||||
|                                 <ion-button expand="block" *ngIf="gradeUrl" [href]="gradeUrl" core-link [showBrowserWarning]="false"> | ||||
|                                     {{ 'core.openinbrowser' | translate }} | ||||
|                                     <ion-icon name="fas-up-right-from-square" slot="end" aria-hidden="true"></ion-icon> | ||||
|                                     <ion-icon name="fas-up-right-from-square" slot="end" aria-hidden="true" /> | ||||
|                                 </ion-button> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
| @ -434,8 +428,7 @@ | ||||
|     <ng-container *ngIf="assign && assign!.teamsubmission && lastAttempt"> | ||||
|         <p *ngIf="lastAttempt.submissiongroup && lastAttempt.submissiongroupname" class="core-groupname"> | ||||
|             <core-format-text [text]="lastAttempt.submissiongroupname" contextLevel="course" [contextInstanceId]="courseId" | ||||
|                 [wsNotFiltered]="true"> | ||||
|             </core-format-text> | ||||
|                 [wsNotFiltered]="true" /> | ||||
|         </p> | ||||
|         <ng-container *ngIf="assign!.preventsubmissionnotingroup && | ||||
|             !lastAttempt!.submissiongroup && | ||||
|  | ||||
| @ -4,18 +4,17 @@ | ||||
|         <h2>{{ plugin.name }}</h2> | ||||
|         <p> | ||||
|             <core-format-text [component]="component" [componentId]="assign.cmid" collapsible-item [text]="text" contextLevel="module" | ||||
|                 [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|             </core-format-text> | ||||
|                 [contextInstanceId]="assign.cmid" [courseId]="assign.course" /> | ||||
|         </p> | ||||
|     </ion-label> | ||||
|     <div slot="end"> | ||||
|         <div class="ion-text-end"> | ||||
|             <ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" [attr.aria-label]="'core.edit' | translate"> | ||||
|                 <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </div> | ||||
|         <ion-note *ngIf="!isSent" color="dark"> | ||||
|             <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'core.notsent' | translate }} | ||||
|             <ion-icon name="fas-clock" aria-hidden="true" /> {{ 'core.notsent' | translate }} | ||||
|         </ion-note> | ||||
|     </div> | ||||
| </ion-item> | ||||
| @ -25,6 +24,5 @@ | ||||
|     <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> | ||||
|         elementId="assignfeedbackcomments_editor" [draftExtraParams]="{userid: userId, action: 'grade'}" /> | ||||
| </ion-item> | ||||
|  | ||||
| @ -3,8 +3,8 @@ | ||||
|     <ion-label> | ||||
|         <h2>{{plugin.name}}</h2> | ||||
|         <ng-container> | ||||
|             <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true"> | ||||
|             </core-file> | ||||
|             <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" | ||||
|                 [alwaysDownload]="true" /> | ||||
|         </ng-container> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
|  | ||||
| @ -3,8 +3,8 @@ | ||||
|     <ion-label> | ||||
|         <h2>{{plugin.name}}</h2> | ||||
|         <ng-container> | ||||
|             <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true"> | ||||
|             </core-file> | ||||
|             <core-file *ngFor="let file of files" [file]="file" [component]="component" [componentId]="assign.cmid" | ||||
|                 [alwaysDownload]="true" /> | ||||
|         </ng-container> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
| @ -22,38 +21,33 @@ | ||||
|             <!-- @todo plagiarism_print_disclosure --> | ||||
|             <core-timer *ngIf="timeLimitEndTime > 0" [endTime]="timeLimitEndTime" (finished)="timeUp()" timeUpText="00:00:00" | ||||
|                 [timerText]="'addon.mod_assign.assigntimeleft' | translate" [align]="'center'" [timeLeftClassThreshold]="-1" | ||||
|                 [underTimeClassThresholds]="[300, 900]"> | ||||
|             </core-timer> | ||||
|                 [underTimeClassThresholds]="[300, 900]" /> | ||||
| 
 | ||||
|             <!-- Assign activity instructions and attachments if needed. --> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="activityInstructions"> | ||||
|                 <ion-label> | ||||
|                     <core-format-text [text]="activityInstructions" [component]="component" [componentId]="moduleId" contextLevel="module" | ||||
|                         [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                         [contextInstanceId]="moduleId" [courseId]="courseId" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ng-container *ngIf="assign?.submissionattachments"> | ||||
|                 <core-file *ngFor="let file of introAttachments" [file]="file" [component]="component" [componentId]="moduleId"> | ||||
|                 </core-file> | ||||
|                 <core-file *ngFor="let file of introAttachments" [file]="file" [component]="component" [componentId]="moduleId" /> | ||||
|             </ng-container> | ||||
| 
 | ||||
|             <form name="addon-mod_assign-edit-form" #editSubmissionForm> | ||||
|                 <!-- Submission statement. --> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="submissionStatement"> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="submissionStatement" [filter]="false"> | ||||
|                         </core-format-text> | ||||
|                         <core-format-text [text]="submissionStatement" [filter]="false" /> | ||||
|                     </ion-label> | ||||
|                     <ion-checkbox slot="end" name="submissionstatement" [(ngModel)]="submissionStatementAccepted"></ion-checkbox> | ||||
|                     <ion-checkbox slot="end" name="submissionstatement" [(ngModel)]="submissionStatementAccepted" /> | ||||
|                     <!-- ion-checkbox doesn't use an input. Create a hidden input to hold the value. --> | ||||
|                     <input type="hidden" [ngModel]="submissionStatementAccepted" name="submissionstatement"> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <addon-mod-assign-submission-plugin *ngFor="let plugin of userSubmission.plugins" [assign]="assign" | ||||
|                     [submission]="userSubmission" [plugin]="plugin" [edit]="true" [allowOffline]="allowOffline"> | ||||
|                 </addon-mod-assign-submission-plugin> | ||||
|                     [submission]="userSubmission" [plugin]="plugin" [edit]="true" [allowOffline]="allowOffline" /> | ||||
|             </form> | ||||
|         </ion-list> | ||||
|     </core-loading> | ||||
|  | ||||
| @ -1,24 +1,21 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-assign-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-assign-index> | ||||
|     <addon-mod-assign-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,35 +1,33 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"></ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| 
 | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!submissions.loaded" (ionRefresh)="refreshList($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="submissions.loaded"> | ||||
|             <ion-list> | ||||
|                 <core-group-selector [groupInfo]="groupInfo" [(selected)]="groupId" (selectedChange)="reloadSubmissions()" | ||||
|                     [courseId]="courseId"> | ||||
|                 </core-group-selector> | ||||
|                     [courseId]="courseId" /> | ||||
| 
 | ||||
|                 <!-- List of submissions. --> | ||||
|                 <ng-container *ngFor="let submission of submissions.items"> | ||||
|                     <ion-item class="ion-text-wrap" (click)="submissions.select(submission)" button | ||||
|                         [attr.aria-current]="submissions.getItemAriaCurrent(submission)" [detail]="true"> | ||||
|                         <core-user-avatar [user]="submission" [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                         <core-user-avatar [user]="submission" [linkProfile]="false" slot="start" /> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading" *ngIf="submission.userfullname">{{submission.userfullname}}</p> | ||||
|                             <p class="item-heading" *ngIf="!submission.userfullname"> | ||||
| @ -37,8 +35,7 @@ | ||||
|                             </p> | ||||
|                             <p *ngIf="assign && assign!.teamsubmission"> | ||||
|                                 <span *ngIf="submission.groupname" class="core-groupname"> | ||||
|                                     <core-format-text [text]="submission.groupname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                     <core-format-text [text]="submission.groupname" contextLevel="course" [contextInstanceId]="courseId" /> | ||||
|                                 </span> | ||||
|                                 <span *ngIf="assign!.preventsubmissionnotingroup && !submission.groupname && submission.noGroups | ||||
|                                     && !submission.blindid" class="text-danger"> | ||||
| @ -68,8 +65,7 @@ | ||||
|             </ion-list> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="!submissions || submissions.empty" icon="fas-file-signature" | ||||
|                 [message]="'addon.mod_assign.submissionstatus_' | translate"> | ||||
|             </core-empty-box> | ||||
|                 [message]="'addon.mod_assign.submissionstatus_' | translate" /> | ||||
|         </core-loading> | ||||
|     </core-split-view> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,16 +1,15 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"></ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| 
 | ||||
|     <core-navbar-buttons slot="end"> | ||||
| @ -21,10 +20,9 @@ | ||||
| </ion-header> | ||||
| <ion-content [core-swipe-navigation]="submissions"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshSubmission($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <addon-mod-assign-submission *ngIf="loaded" [courseId]="courseId" [moduleId]="moduleId" [submitId]="submitId" [blindId]="blindId"> | ||||
|         </addon-mod-assign-submission> | ||||
|         <addon-mod-assign-submission *ngIf="loaded" [courseId]="courseId" [moduleId]="moduleId" [submitId]="submitId" [blindId]="blindId" /> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -2,7 +2,6 @@ | ||||
|     <ion-label> | ||||
|         <h2>{{plugin.name}}</h2> | ||||
|         <core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" [itemId]="submission.id" | ||||
|             area="submission_comments" [title]="plugin.name" [courseId]="assign.course"> | ||||
|         </core-comments> | ||||
|             area="submission_comments" [title]="plugin.name" [courseId]="assign.course" /> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|     <ion-label> | ||||
|         <h2>{{ plugin.name }}</h2> | ||||
|         <div> | ||||
|             <core-files [files]="files" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true"></core-files> | ||||
|             <core-files [files]="files" [component]="component" [componentId]="assign.cmid" [alwaysDownload]="true" /> | ||||
|         </div> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| @ -16,6 +16,5 @@ | ||||
|         </ion-label> | ||||
|     </ion-item-divider> | ||||
|     <core-attachments [files]="files" [maxSize]="maxSize" [maxSubmissions]="maxSubmissions" [courseId]="assign.course" | ||||
|         [component]="component" [componentId]="assign.cmid" [acceptedTypes]="acceptedTypes" [allowOffline]="allowOffline"> | ||||
|     </core-attachments> | ||||
|         [component]="component" [componentId]="assign.cmid" [acceptedTypes]="acceptedTypes" [allowOffline]="allowOffline" /> | ||||
| </div> | ||||
|  | ||||
| @ -5,8 +5,7 @@ | ||||
|         <p *ngIf="words">{{ 'addon.mod_assign.numwords' | translate: {'$a': words} }}</p> | ||||
|         <p> | ||||
|             <core-format-text [component]="component" [componentId]="assign.cmid" collapsible-item [text]="text" contextLevel="module" | ||||
|                 [contextInstanceId]="assign.cmid" [courseId]="assign.course"> | ||||
|             </core-format-text> | ||||
|                 [contextInstanceId]="assign.cmid" [courseId]="assign.course" /> | ||||
|         </p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| @ -29,7 +28,6 @@ | ||||
|         <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> | ||||
|             [draftExtraParams]="{userid: currentUserId, action: 'editsubmission'}" /> | ||||
|     </ion-item> | ||||
| </div> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -10,12 +10,10 @@ | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
|         [courseId]="courseId" (completionChanged)="onCompletionChange()" /> | ||||
| 
 | ||||
|     <core-group-selector [groupInfo]="groupInfo" [(selected)]="groupId" (selectedChange)="groupChanged()" | ||||
|         [multipleGroupsMessage]="'addon.mod_bigbluebuttonbn.view_groups_selection_warning' | translate" [courseId]="module.course"> | ||||
|     </core-group-selector> | ||||
|         [multipleGroupsMessage]="'addon.mod_bigbluebuttonbn.view_groups_selection_warning' | translate" [courseId]="module.course" /> | ||||
| 
 | ||||
|     <ng-container *ngIf="meetingInfo && showRoom"> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="meetingInfo.openingtime"> | ||||
| @ -78,7 +76,7 @@ | ||||
| 
 | ||||
|         <ion-card *ngIf="!meetingInfo.canjoin" class="core-warning-card"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ meetingInfo.statusmessage }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -94,8 +92,7 @@ | ||||
|             <ion-item button class="addon-mod_bbb-recording-title" [attr.aria-expanded]="recording.expanded" (click)="toggle(recording)" | ||||
|                 [attr.aria-label]="(recording.expanded ? 'core.collapse' : 'core.expand') | translate" [detail]="false"> | ||||
|                 <ion-icon name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon" | ||||
|                     [class.expandable-status-icon-expanded]="recording.expanded"> | ||||
|                 </ion-icon> | ||||
|                     [class.expandable-status-icon-expanded]="recording.expanded" /> | ||||
|                 <ion-label> | ||||
|                     <p>{{ recording.type }}</p> | ||||
|                     <p>{{ recording.name }}</p> | ||||
| @ -113,7 +110,7 @@ | ||||
|                         <ion-label> | ||||
|                             <p>{{ playback.name }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-icon slot="end" [name]="playback.icon" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon slot="end" [name]="playback.icon" aria-hidden="true" /> | ||||
|                     </ion-item> | ||||
|                 </div> | ||||
|                 <ion-item *ngFor="let data of recording.details" class="ion-text-wrap"> | ||||
| @ -121,7 +118,7 @@ | ||||
|                         <p class="item-heading">{{ data.label }}</p> | ||||
|                         <p *ngIf="data.allowHTML"> | ||||
|                             <core-format-text [text]="data.value" [component]="component" [componentId]="module.id" contextLevel="module" | ||||
|                                 [contextInstanceId]="module.id" [courseId]="module.course"></core-format-text> | ||||
|                                 [contextInstanceId]="module.id" [courseId]="module.course" /> | ||||
|                         </p> | ||||
|                         <p *ngIf="!data.allowHTML">{{ data.value }}</p> | ||||
|                     </ion-label> | ||||
| @ -130,8 +127,7 @@ | ||||
|         </ng-container> | ||||
| 
 | ||||
|         <core-empty-box *ngIf="recordings && !recordings.length" icon="far-file-video" | ||||
|             [message]="'addon.mod_bigbluebuttonbn.view_message_norecordings' | translate"> | ||||
|         </core-empty-box> | ||||
|             [message]="'addon.mod_bigbluebuttonbn.view_message_norecordings' | translate" /> | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <div collapsible-footer *ngIf="!showLoading" slot="fixed"> | ||||
| @ -146,7 +142,6 @@ | ||||
|             </ion-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|         </core-course-module-navigation> | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
|     </div> | ||||
| </core-loading> | ||||
|  | ||||
| @ -1,23 +1,20 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-bbb-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-bbb-index> | ||||
|     <addon-mod-bbb-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -10,8 +10,7 @@ | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
|         [courseId]="courseId" (completionChanged)="onCompletionChange()" /> | ||||
| 
 | ||||
|     <ion-list> | ||||
|         <ion-item> | ||||
| @ -26,8 +25,7 @@ | ||||
|                 <p [class.ion-padding-start]="addPadding && chapter.level === 1 ? true : null"> | ||||
|                     <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]="module.id" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                     <core-format-text [text]="chapter.title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|                 </p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| @ -41,7 +39,6 @@ | ||||
|             </ion-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|         </core-course-module-navigation> | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
|     </div> | ||||
| </core-loading> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden=true></ion-icon> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden=true /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -20,8 +20,8 @@ | ||||
|                     <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> | ||||
|                         <core-format-text [text]="chapter.title" contextLevel="module" [contextInstanceId]="moduleId" | ||||
|                             [courseId]="courseId" /> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|  | ||||
| @ -1,31 +1,30 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button (click)="showToc()" [attr.aria-label]="'addon.mod_book.toc' | translate" aria-haspopup="true" *ngIf="loaded"> | ||||
|                 <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <div class="safe-area-padding-horizontal core-swipe-slides-container"> | ||||
|             <ion-card class="core-warning-card" *ngIf="warning"> | ||||
|                 <ion-item> | ||||
|                     <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                     <ion-label><span [innerHTML]="warning"></span></ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
| @ -34,10 +33,10 @@ | ||||
|                 <ng-template let-chapter="item" let-active="active"> | ||||
|                     <div class="ion-padding"> | ||||
|                         <core-format-text [component]="component" [componentId]="cmId" [text]="chapter.content" contextLevel="module" | ||||
|                             [contextInstanceId]="cmId" [courseId]="courseId" [disabled]="!active"></core-format-text> | ||||
|                             [contextInstanceId]="cmId" [courseId]="courseId" [disabled]="!active" /> | ||||
|                         <div class="ion-margin-top" *ngIf="chapter.tags?.length > 0"> | ||||
|                             <strong>{{ 'core.tag.tags' | translate }}: </strong> | ||||
|                             <core-tag-list [tags]="chapter.tags"></core-tag-list> | ||||
|                             <core-tag-list [tags]="chapter.tags" /> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </ng-template> | ||||
| @ -47,6 +46,5 @@ | ||||
| 
 | ||||
|     <core-navigation-bar collapsible-footer appearOnBottom *ngIf="loaded && displayNavBar && navigationItems.length > 1" | ||||
|         [items]="navigationItems" previousTranslate="addon.mod_book.navprevtitle" nextTranslate="addon.mod_book.navnexttitle" | ||||
|         (action)="changeChapter($event.id)" slot="fixed"> | ||||
|     </core-navigation-bar> | ||||
|         (action)="changeChapter($event.id)" slot="fixed" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,24 +1,20 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-book-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"> | ||||
|     </addon-mod-book-index> | ||||
|     <addon-mod-book-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -10,12 +10,11 @@ | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
|         [courseId]="courseId" (completionChanged)="onCompletionChange()" /> | ||||
| 
 | ||||
|     <ion-card *ngIf="chatTime" class="core-info-card"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-clock" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-clock" slot="start" aria-hidden="true" /> | ||||
|             <ion-label>{{ 'addon.mod_chat.sessionstartsin' | translate:{$a: chatTime} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| @ -31,7 +30,6 @@ | ||||
|             </ion-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|         </core-course-module-navigation> | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
|     </div> | ||||
| </core-loading> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|         </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-xmark" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon slot="icon-only" name="fas-xmark" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -14,16 +14,16 @@ | ||||
|     <core-loading [hideUntil]="usersLoaded"> | ||||
|         <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> | ||||
|             <core-user-avatar [user]="user" slot="start" [linkProfile]="false" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ user.fullname }}</p> | ||||
|                 <ng-container *ngIf="currentUserId !== user.id && isOnline"> | ||||
|                     <ion-button fill="clear" (click)="talkTo(user)"> | ||||
|                         <ion-icon name="fas-comments" slot="start" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-comments" slot="start" aria-hidden="true" /> | ||||
|                         {{ 'addon.mod_chat.talk' | translate }} | ||||
|                     </ion-button> | ||||
|                     <ion-button fill="clear" (click)="beepTo(user)"> | ||||
|                         <ion-icon name="fas-bell" slot="start" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-bell" slot="start" aria-hidden="true" /> | ||||
|                         {{ 'addon.mod_chat.beep' | translate }} | ||||
|                     </ion-button> | ||||
|                 </ng-container> | ||||
|  | ||||
| @ -1,17 +1,16 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|             </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> | ||||
|                 <ion-icon name="fas-users" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -28,7 +27,7 @@ | ||||
|                 <div class="ion-text-center addon-mod_chat-notice" *ngIf="message.special"> | ||||
|                     <ion-badge class="ion-text-wrap" color="success" *ngIf="message.system && message.message === 'enter'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-right-to-bracket" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-right-to-bracket" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -36,7 +35,7 @@ | ||||
| 
 | ||||
|                     <ion-badge class="ion-text-wrap" color="danger" *ngIf="message.system && message.message === 'exit'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-right-from-bracket" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-right-from-bracket" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -44,7 +43,7 @@ | ||||
| 
 | ||||
|                     <ion-badge class="ion-text-wrap" color="primary" *ngIf="message.beep === 'all'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -53,7 +52,7 @@ | ||||
|                     <ion-badge class="ion-text-wrap" color="primary" | ||||
|                         *ngIf="message.userid !== currentUserId && message.beep === currentUserId"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -62,7 +61,7 @@ | ||||
|                     <ion-badge class="ion-text-wrap" color="light" | ||||
|                         *ngIf="message.userid === currentUserId && message.beep && message.beep !== 'all'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepWho} }} | ||||
|                         </span> | ||||
| @ -70,12 +69,11 @@ | ||||
| 
 | ||||
|                     <ion-badge class="ion-text-wrap" color="info" *ngIf="!message.system && !message.beep"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-asterisk" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-asterisk" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             <strong> | ||||
|                                 {{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module" | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId" (afterRender)="last && scrollToBottom()"> | ||||
|                                 </core-format-text> | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId" (afterRender)="last && scrollToBottom()" /> | ||||
|                             </strong> | ||||
|                         </span> | ||||
|                     </ion-badge> | ||||
| @ -83,13 +81,11 @@ | ||||
| 
 | ||||
|                 <core-message *ngIf="!message.special" [message]="message" [user]="message" [text]="message.message" | ||||
|                     [time]="message.timestamp * 1000" (afterRender)="last && scrollToBottom()" contextLevel="module" [instanceId]="cmId" | ||||
|                     [courseId]="courseId"> | ||||
|                 </core-message> | ||||
|                     [courseId]="courseId" /> | ||||
|             </ng-container> | ||||
|         </ion-list> | ||||
| 
 | ||||
|         <core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments" [message]="'addon.mod_chat.nomessages' | translate"> | ||||
|         </core-empty-box> | ||||
|         <core-empty-box *ngIf="!messages || messages.length <= 0" icon="far-comments" [message]="'addon.mod_chat.nomessages' | translate" /> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
| <ion-footer class="footer-adjustable"> | ||||
| @ -99,8 +95,7 @@ | ||||
|         </p> | ||||
| 
 | ||||
|         <core-send-message-form [sendDisabled]="sending" *ngIf="isOnline && polling && loaded" [message]="newMessage" | ||||
|             (onSubmit)="sendMessage($event)" [placeholder]="'addon.messages.newmessage' | translate"> | ||||
|         </core-send-message-form> | ||||
|             (onSubmit)="sendMessage($event)" [placeholder]="'addon.messages.newmessage' | translate" /> | ||||
| 
 | ||||
|         <ion-button *ngIf="isOnline && !polling && loaded" (click)="reconnect()" expand="block" fill="outline"> | ||||
|             {{ 'core.login.reconnect' | translate }} | ||||
|  | ||||
| @ -1,23 +1,20 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-chat-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-chat-index> | ||||
|     <addon-mod-chat-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_chat.messages' | translate }}</h1> | ||||
| @ -10,7 +10,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshMessages($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ion-list class="addon-messages-discussion-container"> | ||||
| @ -23,7 +23,7 @@ | ||||
|                 <div class="ion-text-center addon-mod_chat-notice" *ngIf="message.special"> | ||||
|                     <ion-badge class="ion-text-wrap" color="success" *ngIf="message.issystem && message.message === 'enter'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-right-to-bracket" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-right-to-bracket" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -31,7 +31,7 @@ | ||||
| 
 | ||||
|                     <ion-badge class="ion-text-wrap" color="danger" *ngIf="message.issystem && message.message === 'exit'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-right-from-bracket" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-right-from-bracket" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -39,7 +39,7 @@ | ||||
| 
 | ||||
|                     <ion-badge class="ion-text-wrap" color="primary" *ngIf="message.beep === 'all'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -48,7 +48,7 @@ | ||||
|                     <ion-badge class="ion-text-wrap" color="primary" | ||||
|                         *ngIf="message.userid !== currentUserId && message.beep === currentUserId"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} | ||||
|                         </span> | ||||
| @ -57,7 +57,7 @@ | ||||
|                     <ion-badge class="ion-text-wrap" color="light" | ||||
|                         *ngIf="message.userid === currentUserId && message.beep && message.beep !== 'all'"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-bell" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             {{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepWho} }} | ||||
|                         </span> | ||||
| @ -65,19 +65,18 @@ | ||||
| 
 | ||||
|                     <ion-badge class="ion-text-wrap" color="info" *ngIf="!message.issystem && !message.beep"> | ||||
|                         <span> | ||||
|                             <ion-icon name="fas-asterisk" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-asterisk" aria-hidden="true" /> | ||||
|                             {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} | ||||
|                             <strong> | ||||
|                                 {{ message.userfullname }} <core-format-text [text]="message.message" contextLevel="module" | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId"></core-format-text> | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|                             </strong> | ||||
|                         </span> | ||||
|                     </ion-badge> | ||||
|                 </div> | ||||
| 
 | ||||
|                 <core-message *ngIf="!message.special" [message]="message" [user]="message" [text]="message.message" | ||||
|                     [time]="message.timestamp * 1000" contextLevel="module" [instanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-message> | ||||
|                     [time]="message.timestamp * 1000" contextLevel="module" [instanceId]="cmId" [courseId]="courseId" /> | ||||
|             </ng-container> | ||||
|         </ion-list> | ||||
|     </core-loading> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_chat.chatreport' | translate }}</h1> | ||||
| @ -11,15 +11,14 @@ | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!sessions.loaded" (ionRefresh)="refreshSessions($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="sessions.loaded"> | ||||
|             <core-group-selector [groupInfo]="groupInfo" [(selected)]="groupId" (selectedChange)="reloadSessions()" [courseId]="courseId"> | ||||
|             </core-group-selector> | ||||
|             <core-group-selector [groupInfo]="groupInfo" [(selected)]="groupId" (selectedChange)="reloadSessions()" [courseId]="courseId" /> | ||||
| 
 | ||||
|             <ion-item> | ||||
|                 <ion-label>{{ 'addon.mod_chat.showincompletesessions' | translate }}</ion-label> | ||||
|                 <ion-toggle [(ngModel)]="showAll" (ionChange)="reloadSessions()" slot="end"></ion-toggle> | ||||
|                 <ion-toggle [(ngModel)]="showAll" (ionChange)="reloadSessions()" slot="end" /> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-card *ngFor="let session of sessions.items" (click)="sessions.select(session)" button | ||||
| @ -45,8 +44,7 @@ | ||||
|                 </ion-button> | ||||
|             </ion-card> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="sessions.empty" icon="far-comments" [message]="'addon.mod_chat.nosessionsfound' | translate"> | ||||
|             </core-empty-box> | ||||
|             <core-empty-box *ngIf="sessions.empty" icon="far-comments" [message]="'addon.mod_chat.nosessionsfound' | translate" /> | ||||
|         </core-loading> | ||||
|     </core-split-view> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -9,13 +9,12 @@ | ||||
| <core-loading [hideUntil]="!showLoading"> | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()" /> | ||||
| 
 | ||||
|     <!-- Activity availability messages --> | ||||
|     <ion-card class="core-info-card" *ngIf="choiceNotOpenYet"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p *ngIf="options.length">{{ 'addon.mod_choice.previewonly' | translate:{$a: openTimeReadable} }}</p> | ||||
|                 <p *ngIf="!options.length">{{ 'addon.mod_choice.notopenyet' | translate:{$a: openTimeReadable} }}</p> | ||||
| @ -25,12 +24,12 @@ | ||||
| 
 | ||||
|     <ion-card class="core-info-card" *ngIf="choiceClosed"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <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> | ||||
|                     <core-format-text [text]="options[0].text" contextLevel="module" [contextInstanceId]="module.id" | ||||
|                         [courseId]="courseId" /> | ||||
|                 </p> | ||||
|                 <p>{{ 'addon.mod_choice.expired' | translate:{$a: closeTimeReadable} }}</p> | ||||
|             </ion-label> | ||||
| @ -40,7 +39,7 @@ | ||||
|     <!-- Inform what will happen with the choices. --> | ||||
|     <ion-card class="core-info-card" *ngIf="canEdit && publishInfo && options.length"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label>{{ publishInfo | translate }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| @ -50,17 +49,17 @@ | ||||
|         <ng-container *ngIf="choice.allowmultiple"> | ||||
|             <ion-item class="ion-text-wrap" *ngFor="let option of options"> | ||||
|                 <ion-label> | ||||
|                     <ng-container *ngTemplateOutlet="optionLabelTemplate; context: {option: option}"></ng-container> | ||||
|                     <ng-container *ngTemplateOutlet="optionLabelTemplate; context: {option: option}" /> | ||||
|                 </ion-label> | ||||
|                 <ion-checkbox slot="end" [(ngModel)]="option.checked" [disabled]="option.disabled || !canEdit"></ion-checkbox> | ||||
|                 <ion-checkbox slot="end" [(ngModel)]="option.checked" [disabled]="option.disabled || !canEdit" /> | ||||
|             </ion-item> | ||||
|         </ng-container> | ||||
|         <ion-radio-group *ngIf="!choice.allowmultiple" [(ngModel)]="selectedOption.id"> | ||||
|             <ion-item class="ion-text-wrap" *ngFor="let option of options"> | ||||
|                 <ion-label> | ||||
|                     <ng-container *ngTemplateOutlet="optionLabelTemplate; context: {option: option}"></ng-container> | ||||
|                     <ng-container *ngTemplateOutlet="optionLabelTemplate; context: {option: option}" /> | ||||
|                 </ion-label> | ||||
|                 <ion-radio slot="end" [value]="option.id" [disabled]="option.disabled || !canEdit"></ion-radio> | ||||
|                 <ion-radio slot="end" [value]="option.id" [disabled]="option.disabled || !canEdit" /> | ||||
|             </ion-item> | ||||
|         </ion-radio-group> | ||||
|     </ion-card> | ||||
| @ -75,14 +74,13 @@ | ||||
|             <ion-row> | ||||
|                 <ion-col size="12" size-lg="5"> | ||||
|                     <ion-item class="ion-text-wrap core-warning-item" *ngIf="hasOffline"> | ||||
|                         <ion-icon slot="start" name="fas-triangle-exclamation" color="warning" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon slot="start" name="fas-triangle-exclamation" color="warning" aria-hidden="true" /> | ||||
|                         <ion-label>{{ 'addon.mod_choice.resultsnotsynced' | translate }}</ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <ion-label> | ||||
|                             <core-chart type="pie" [data]="data" [labels]="labels" height="300" contextLevel="module" | ||||
|                                 [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                             </core-chart> | ||||
|                                 [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-col> | ||||
| @ -91,13 +89,11 @@ | ||||
|                         <ion-item [button]="result.numberofuser > 0" class="divider ion-text-wrap" (click)="toggle(result)" | ||||
|                             [attr.aria-label]="(result.expanded ? 'core.collapse' : 'core.expand') | translate" [detail]="false"> | ||||
|                             <ion-icon [name]="result.numberofuser > 0 ? 'fas-chevron-right' : ''" flip-rtl slot="start" aria-hidden="true" | ||||
|                                 class="expandable-status-icon" [class.expandable-status-icon-expanded]="result.expanded"> | ||||
|                             </ion-icon> | ||||
|                                 class="expandable-status-icon" [class.expandable-status-icon-expanded]="result.expanded" /> | ||||
|                             <ion-label> | ||||
|                                 <h3 class="item-heading"> | ||||
|                                     <core-format-text [text]="result.text" contextLevel="module" [contextInstanceId]="module.id" | ||||
|                                         [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                         [courseId]="courseId" /> | ||||
|                                 </h3> | ||||
|                                 <p> | ||||
|                                     {{ 'addon.mod_choice.numberofuser' | translate }}: {{ result.numberofuser }} | ||||
| @ -111,7 +107,7 @@ | ||||
|                         <ng-container *ngIf="result.expanded"> | ||||
|                             <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" [linkProfile]="false"></core-user-avatar> | ||||
|                                 <core-user-avatar [user]="user" slot="start" [courseId]="courseId" [linkProfile]="false" /> | ||||
|                                 <ion-label> | ||||
|                                     <p>{{user.fullname}}</p> | ||||
|                                 </ion-label> | ||||
| @ -125,7 +121,7 @@ | ||||
| 
 | ||||
|     <ion-card class="core-info-card" *ngIf="!canSeeResults && !choiceNotOpenYet"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p>{{ 'addon.mod_choice.noresultsviewable' | translate }}</p> | ||||
|             </ion-label> | ||||
| @ -143,8 +139,7 @@ | ||||
|             </ion-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|         </core-course-module-navigation> | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
|     </div> | ||||
| </core-loading> | ||||
| 
 | ||||
| @ -153,8 +148,7 @@ | ||||
| <!-- Template to render a choice option label. --> | ||||
| <ng-template #optionLabelTemplate let-option="option"> | ||||
|     <p> | ||||
|         <core-format-text [text]="option.text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|         </core-format-text> | ||||
|         <core-format-text [text]="option.text" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|         <span *ngIf="choice!.limitanswers && option.countanswers >= option.maxanswers"> | ||||
|             {{ 'addon.mod_choice.full' | translate }} | ||||
|         </span> | ||||
|  | ||||
| @ -1,23 +1,20 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-choice-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-choice-index> | ||||
|     <addon-mod-choice-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,49 +1,48 @@ | ||||
| <ion-button size="small" *ngIf="action === 'actionsmenu'" fill="clear" (click)="actionsMenu($event)" | ||||
|     [attr.aria-label]="'addon.mod_data.actionsmenu' | translate"> | ||||
|     <ion-icon name="fas-ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="fas-ellipsis-vertical" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <ion-button size="small" *ngIf="action === 'more'" fill="clear" (click)="viewEntry()" | ||||
|     [attr.aria-label]="'addon.mod_data.showmore' | translate"> | ||||
|     <ion-icon name="fas-magnifying-glass-plus" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="fas-magnifying-glass-plus" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <ion-button size="small" *ngIf="action === 'edit'" fill="clear" (click)="editEntry()" [attr.aria-label]="'core.edit' | translate"> | ||||
|     <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <ion-button size="small" *ngIf="action === 'delete' && !entry.deleted" fill="clear" color="danger" (click)="deleteEntry()" | ||||
|     [attr.aria-label]="'core.delete' | translate"> | ||||
|     <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <ion-button size="small" *ngIf="action === 'delete' && entry.deleted" fill="clear" color="danger" (click)="undoDelete()" | ||||
|     [attr.aria-label]="'core.restore' | translate"> | ||||
|     <ion-icon name="fas-rotate-left" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="fas-rotate-left" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <ion-button size="small" *ngIf="action === 'approve'" fill="clear" (click)="approveEntry()" | ||||
|     [attr.aria-label]="'addon.mod_data.approve' | translate"> | ||||
|     <ion-icon name="fas-thumbs-up" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="fas-thumbs-up" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <ion-button size="small" *ngIf="action === 'disapprove'" fill="clear" (click)="disapproveEntry()" | ||||
|     [attr.aria-label]="'addon.mod_data.disapprove' | translate"> | ||||
|     <ion-icon name="far-thumbs-down" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     <ion-icon name="far-thumbs-down" slot="icon-only" aria-hidden="true" /> | ||||
| </ion-button> | ||||
| 
 | ||||
| <core-comments *ngIf="action === 'comments' && mode === 'list'" contextLevel="module" [instanceId]="database.coursemodule" | ||||
|     component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="database.course"> | ||||
| </core-comments> | ||||
|     component="mod_data" [itemId]="entry.id" area="database_entry" [courseId]="database.course" /> | ||||
| 
 | ||||
| <span *ngIf="action === 'timeadded'">{{ entry.timecreated * 1000 | coreFormatDate }}</span> | ||||
| <span *ngIf="action === 'timemodified'">{{ entry.timemodified * 1000 | coreFormatDate }}</span> | ||||
| 
 | ||||
| <core-user-avatar *ngIf="action === 'userpicture'" [user]="entry" slot="start" [courseId]="database.course" [userId]="entry.userid" | ||||
|     [profileUrl]="userPicture"></core-user-avatar> | ||||
|     [profileUrl]="userPicture" /> | ||||
| 
 | ||||
| <a *ngIf="action === 'user' && entry" core-user-link [courseId]="database.course" [userId]="entry.userid" [title]="entry.fullname"> | ||||
|     {{entry.fullname}} | ||||
| </a> | ||||
| 
 | ||||
| <core-tag-list *ngIf="tagsEnabled && action === 'tags' && entry" [tags]="entry.tags"></core-tag-list> | ||||
| <core-tag-list *ngIf="tagsEnabled && action === 'tags' && entry" [tags]="entry.tags" /> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ item.text | translate }}</p> | ||||
|             </ion-label> | ||||
|             <ion-icon [name]="item.icon" slot="end" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon [name]="item.icon" slot="end" aria-hidden="true" /> | ||||
|         </ion-item> | ||||
|     </ion-list> | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <core-dynamic-component [component]="fieldComponent" [data]="pluginData"> | ||||
|     <!-- This content will be replaced by the component if found. --> | ||||
|     <core-loading [hideUntil]="fieldLoaded" [fullscreen]="false"></core-loading> | ||||
|     <core-loading [hideUntil]="fieldLoaded" [fullscreen]="false" /> | ||||
| </core-dynamic-component> | ||||
|  | ||||
| @ -1,19 +1,17 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button *ngIf="canSearch" (click)="showSearch()" [attr.aria-label]="'addon.mod_data.search' | translate"> | ||||
|         <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
|     <core-context-menu> | ||||
|         <core-context-menu-item [priority]="500" *ngIf="canAdd" [content]="'addon.mod_data.addentries' | translate" iconAction="fas-plus" | ||||
|             (action)="gotoAddEntries()"> | ||||
|         </core-context-menu-item> | ||||
|             (action)="gotoAddEntries()" /> | ||||
|         <core-context-menu-item [priority]="400" *ngIf="firstEntry" [content]="'addon.mod_data.single' | translate" iconAction="fas-file" | ||||
|             (action)="gotoEntry(firstEntry)"> | ||||
|         </core-context-menu-item> | ||||
|             (action)="gotoEntry(firstEntry)" /> | ||||
|     </core-context-menu> | ||||
| 
 | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -22,30 +20,28 @@ | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings" (completionChanged)="onCompletionChange()" /> | ||||
| 
 | ||||
|     <core-group-selector [groupInfo]="groupInfo" [(selected)]="selectedGroup" (selectedChange)="setGroup(selectedGroup)" | ||||
|         [courseId]="database?.course"> | ||||
|     </core-group-selector> | ||||
|         [courseId]="database?.course" /> | ||||
| 
 | ||||
|     <ion-card class="core-info-card" *ngIf="!access?.timeavailable && timeAvailableFrom"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label>{{ 'addon.mod_data.notopenyet' | translate:{$a: timeAvailableFromReadable} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <ion-card class="core-info-card" *ngIf="!access?.timeavailable && timeAvailableTo"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label>{{ 'addon.mod_data.expired' | translate:{$a: timeAvailableToReadable} }}</ion-label> | ||||
|         </ion-item> | ||||
|     </ion-card> | ||||
| 
 | ||||
|     <ion-card class="core-info-card" *ngIf="access && access.entrieslefttoview"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 {{ 'addon.mod_data.entrieslefttoaddtoview' | translate:{$a: {entrieslefttoview: access.entrieslefttoview} } }} | ||||
|             </ion-label> | ||||
| @ -54,7 +50,7 @@ | ||||
| 
 | ||||
|     <ion-card class="core-info-card" *ngIf="access && access.entrieslefttoadd"> | ||||
|         <ion-item> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 {{ 'addon.mod_data.entrieslefttoadd' | translate:{$a: {entriesleft: access.entrieslefttoadd} } }} | ||||
|             </ion-label> | ||||
| @ -79,30 +75,29 @@ | ||||
|     </ng-container> | ||||
| 
 | ||||
|     <div class="addon-data-contents addon-data-entries-{{database.id}}" *ngIf="!isEmpty && database"> | ||||
|         <core-style [css]="database.csstemplate" prefix=".addon-data-entries-{{database.id}}"></core-style> | ||||
|         <core-style [css]="database.csstemplate" prefix=".addon-data-entries-{{database.id}}" /> | ||||
| 
 | ||||
|         <core-compile-html [text]="entriesRendered" [jsData]="jsData" [extraImports]="extraImports"></core-compile-html> | ||||
|         <core-compile-html [text]="entriesRendered" [jsData]="jsData" [extraImports]="extraImports" /> | ||||
|     </div> | ||||
| 
 | ||||
|     <ion-grid *ngIf="search.page > 0 || hasNextPage"> | ||||
|         <ion-row class="ion-align-items-center"> | ||||
|             <ion-col *ngIf="search.page > 0"> | ||||
|                 <ion-button expand="block" fill="outline" (click)="searchEntries(search.page - 1)"> | ||||
|                     <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true" /> | ||||
|                     {{ 'core.previous' | translate }} | ||||
|                 </ion-button> | ||||
|             </ion-col> | ||||
|             <ion-col *ngIf="hasNextPage"> | ||||
|                 <ion-button expand="block" (click)="searchEntries(search.page + 1)"> | ||||
|                     {{ 'core.next' | translate }} | ||||
|                     <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true" /> | ||||
|                 </ion-button> | ||||
|             </ion-col> | ||||
|         </ion-row> | ||||
|     </ion-grid> | ||||
| 
 | ||||
|     <core-empty-box *ngIf="isEmpty && !search.searching" icon="fas-database" [message]="'addon.mod_data.norecords' | translate"> | ||||
|     </core-empty-box> | ||||
|     <core-empty-box *ngIf="isEmpty && !search.searching" icon="fas-database" [message]="'addon.mod_data.norecords' | translate" /> | ||||
| 
 | ||||
|     <core-empty-box *ngIf="isEmpty && search.searching" icon="fas-database" [message]="'addon.mod_data.nomatch' | translate" | ||||
|         class="core-empty-box-clickable"> | ||||
| @ -111,12 +106,11 @@ | ||||
| 
 | ||||
| </core-loading> | ||||
| 
 | ||||
| <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id"> | ||||
| </core-course-module-navigation> | ||||
| <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
| 
 | ||||
| <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd"> | ||||
|     <ion-fab-button (click)="gotoAddEntries()" [attr.aria-label]="'addon.mod_data.addentries' | translate"> | ||||
|         <ion-icon name="fas-plus" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-plus" aria-hidden="true" /> | ||||
|         <span class="sr-only">{{ 'addon.mod_data.addentries' | translate }}</span> | ||||
|     </ion-fab-button> | ||||
| </ion-fab> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden=true></ion-icon> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden=true /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| @ -13,15 +13,14 @@ | ||||
| <ion-content> | ||||
|     <ion-item> | ||||
|         <ion-label>{{ 'addon.mod_data.advancedsearch' | translate }}</ion-label> | ||||
|         <ion-toggle [(ngModel)]="search.searchingAdvanced" slot="end"></ion-toggle> | ||||
|         <ion-toggle [(ngModel)]="search.searchingAdvanced" slot="end" /> | ||||
|     </ion-item> | ||||
|     <form (ngSubmit)="searchEntries($event)" [formGroup]="searchForm" #searchFormEl> | ||||
|         <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> | ||||
|                     formControlName="text" /> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label position="stacked">{{ 'core.sortby' | translate }}</ion-label> | ||||
| @ -45,21 +44,21 @@ | ||||
|                 <ion-radio-group [(ngModel)]="search.sortDirection" name="sortDirection" formControlName="sortDirection"> | ||||
|                     <ion-item> | ||||
|                         <ion-label>{{ 'addon.mod_data.ascending' | translate }}</ion-label> | ||||
|                         <ion-radio slot="start" value="ASC"></ion-radio> | ||||
|                         <ion-radio slot="start" value="ASC" /> | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <ion-label>{{ 'addon.mod_data.descending' | translate }}</ion-label> | ||||
|                         <ion-radio slot="start" value="DESC"></ion-radio> | ||||
|                         <ion-radio slot="start" value="DESC" /> | ||||
|                     </ion-item> | ||||
|                 </ion-radio-group> | ||||
|             </ion-list> | ||||
|             <div class="ion-padding addon-data-advanced-search" [hidden]="!advancedSearch || !search.searchingAdvanced"> | ||||
|                 <core-compile-html [text]="advancedSearch" [jsData]="jsData" [extraImports]="extraImports"></core-compile-html> | ||||
|                 <core-compile-html [text]="advancedSearch" [jsData]="jsData" [extraImports]="extraImports" /> | ||||
|             </div> | ||||
|         </ion-list> | ||||
|         <div class="ion-padding"> | ||||
|             <ion-button expand="block" type="submit"> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="start" aria-hidden="true" /> | ||||
|                 {{ 'addon.mod_data.search' | translate }} | ||||
|             </ion-button> | ||||
|         </div> | ||||
|  | ||||
| @ -5,13 +5,12 @@ | ||||
|         interface="alert"> | ||||
|         <ion-select-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-select-option> | ||||
|     </ion-select> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| 
 | ||||
|     <ion-item *ngIf="searchMode"> | ||||
|         <ion-label>{{ 'addon.mod_data.selectedrequired' | translate }}</ion-label> | ||||
|         <ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_allreq'" [(ngModel)]="searchFields!['f_'+field.id+'_allreq']"> | ||||
|         </ion-checkbox> | ||||
|         <ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_allreq'" [(ngModel)]="searchFields!['f_'+field.id+'_allreq']" /> | ||||
|     </ion-item> | ||||
| </span> | ||||
| 
 | ||||
| <core-format-text *ngIf="displayMode && value && value.content" [text]="value.content" [filter]="false"></core-format-text> | ||||
| <core-format-text *ngIf="displayMode && value && value.content" [text]="value.content" [filter]="false" /> | ||||
|  | ||||
| @ -1,14 +1,12 @@ | ||||
| <span *ngIf="inputMode && form" [formGroup]="form"> | ||||
|     <span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <ion-datetime [formControlName]="'f_'+field.id" [placeholder]="'core.date' | translate" [max]="maxDate" [min]="minDate" | ||||
|         [disabled]="searchMode && !searchFields!['f_'+field.id+'_z']" [displayFormat]="format" [displayTimezone]="displayTimezone"> | ||||
|     </ion-datetime> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|         [disabled]="searchMode && !searchFields!['f_'+field.id+'_z']" [displayFormat]="format" [displayTimezone]="displayTimezone" /> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| 
 | ||||
|     <ion-item *ngIf="searchMode"> | ||||
|         <ion-label>{{ 'addon.mod_data.usedate' | translate }}</ion-label> | ||||
|         <ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_z'" [(ngModel)]="searchFields!['f_'+field.id+'_z']"> | ||||
|         </ion-checkbox> | ||||
|         <ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_z'" [(ngModel)]="searchFields!['f_'+field.id+'_z']" /> | ||||
|     </ion-item> | ||||
| </span> | ||||
| 
 | ||||
|  | ||||
| @ -1,17 +1,16 @@ | ||||
| <span *ngIf="editMode && form"> | ||||
|     <span [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" | ||||
|         [allowOffline]="true" [courseId]="database?.course"> | ||||
|     </core-attachments> | ||||
|     <core-input-errors *ngIf="error" [errorText]="error"></core-input-errors> | ||||
|         [allowOffline]="true" [courseId]="database?.course" /> | ||||
|     <core-input-errors *ngIf="error" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="searchMode && form" [formGroup]="form"> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name" /> | ||||
| </span> | ||||
| 
 | ||||
| <ng-container *ngIf="displayMode"> | ||||
|     <div> | ||||
|         <core-files [files]="files" [component]="component" [componentId]="componentId" [alwaysDownload]="true"></core-files> | ||||
|         <core-files [files]="files" [component]="component" [componentId]="componentId" [alwaysDownload]="true" /> | ||||
|     </div> | ||||
| </ng-container> | ||||
|  | ||||
| @ -1,23 +1,23 @@ | ||||
| <span *ngIf="inputMode && form" [formGroup]="form"> | ||||
|     <ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input> | ||||
|     <ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id" /> | ||||
| 
 | ||||
|     <ng-container *ngIf="editMode"> | ||||
|         <span [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|         <div class="addon-data-latlong"> | ||||
|             <ion-input type="text" [formControlName]="'f_'+field.id+'_0'" maxlength="10"></ion-input> | ||||
|             <ion-input type="text" [formControlName]="'f_'+field.id+'_0'" maxlength="10" /> | ||||
|             <span class="placeholder-icon" item-right>°N</span> | ||||
|         </div> | ||||
|         <div class="addon-data-latlong"> | ||||
|             <ion-input type="text" [formControlName]="'f_'+field.id+'_1'" maxlength="10"></ion-input> | ||||
|             <ion-input type="text" [formControlName]="'f_'+field.id+'_1'" maxlength="10" /> | ||||
|             <span class="placeholder-icon" item-right>°E</span> | ||||
|         </div> | ||||
|         <div class="addon-data-latlong" *ngIf="locationServicesEnabled"> | ||||
|             <ion-button (click)="getLocation($event)"> | ||||
|                 <ion-icon name="fas-crosshairs" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-crosshairs" slot="start" aria-hidden="true" /> | ||||
|                 {{ 'addon.mod_data.mylocation' | translate }} | ||||
|             </ion-button> | ||||
|         </div> | ||||
|         <core-input-errors *ngIf="error" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|         <core-input-errors *ngIf="error" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
|     </ng-container> | ||||
| </span> | ||||
| 
 | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|         <ion-select-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-select-option> | ||||
|         <ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option> | ||||
|     </ion-select> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="displayMode && value && value.content">{{ value.content }}</span> | ||||
|  | ||||
| @ -5,14 +5,13 @@ | ||||
|         interface="alert"> | ||||
|         <ion-select-option *ngFor="let option of options" [value]="option.value">{{option.key}}</ion-select-option> | ||||
|     </ion-select> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| 
 | ||||
| 
 | ||||
|     <ion-item *ngIf="searchMode"> | ||||
|         <ion-label>{{ 'addon.mod_data.selectedrequired' | translate }}</ion-label> | ||||
|         <ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_allreq'" [(ngModel)]="searchFields!['f_'+field.id+'_allreq']"> | ||||
|         </ion-checkbox> | ||||
|         <ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_allreq'" [(ngModel)]="searchFields!['f_'+field.id+'_allreq']" /> | ||||
|     </ion-item> | ||||
| </span> | ||||
| 
 | ||||
| <core-format-text *ngIf="displayMode && value && value.content" [text]="value.content" [filter]="false"></core-format-text> | ||||
| <core-format-text *ngIf="displayMode && value && value.content" [text]="value.content" [filter]="false" /> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <span *ngIf="inputMode && form" [formGroup]="form"> | ||||
|     <span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <ion-input type="number" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <ion-input type="number" [formControlName]="'f_'+field.id" [placeholder]="field.name" /> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="displayMode && value && value.content">{{ value.content }}</span> | ||||
|  | ||||
| @ -1,17 +1,15 @@ | ||||
| <span *ngIf="editMode && form" [formGroup]="form"> | ||||
|     <span [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <core-attachments [files]="files" [maxSize]="maxSizeBytes" maxSubmissions="1" [component]="component" [componentId]="componentId" | ||||
|         [allowOffline]="true" acceptedTypes="image" [courseId]="database?.course"> | ||||
|     </core-attachments> | ||||
|     <core-input-errors *ngIf="error" [errorText]="error"></core-input-errors> | ||||
|         [allowOffline]="true" acceptedTypes="image" [courseId]="database?.course" /> | ||||
|     <core-input-errors *ngIf="error" [errorText]="error" /> | ||||
| 
 | ||||
|     <ion-label position="stacked">{{ 'addon.mod_data.alttext' | translate }}</ion-label> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [placeholder]=" 'addon.mod_data.alttext' | translate"> | ||||
|     </ion-input> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id+'_alttext'" [placeholder]=" 'addon.mod_data.alttext' | translate" /> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="searchMode && form" [formGroup]="form"> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name" /> | ||||
| </span> | ||||
| 
 | ||||
| <button class="as-link" *ngIf="listMode && imageUrl" (click)="navigateEntry()"> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|         <ion-select-option value="">{{ 'addon.mod_data.menuchoose' | translate }}</ion-select-option> | ||||
|         <ion-select-option *ngFor="let option of options" [value]="option">{{option}}</ion-select-option> | ||||
|     </ion-select> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="displayMode && value && value.content">{{ value.content }}</span> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <span *ngIf="inputMode && form" [formGroup]="form"> | ||||
|     <span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name" /> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="displayMode && value && value.content">{{ value.content }}</span> | ||||
|  | ||||
| @ -1,14 +1,12 @@ | ||||
| <span *ngIf="inputMode && form" [formGroup]="form"> | ||||
|     <ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id"></ion-input> | ||||
|     <ion-input *ngIf="searchMode" type="text" [placeholder]="field.name" [formControlName]="'f_'+field.id" /> | ||||
| 
 | ||||
|     <span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <core-rich-text-editor *ngIf="editMode" [control]="form.controls['f_'+field.id]" [placeholder]="field.name" [name]="'f_'+field.id" | ||||
|         [component]="component" [componentId]="componentId" [autoSave]="true" contextLevel="module" [contextInstanceId]="componentId" | ||||
|         [elementId]="'field_'+field.id" ngDefaultControl> | ||||
|     </core-rich-text-editor> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|         [elementId]="'field_'+field.id" ngDefaultControl /> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <core-format-text *ngIf="displayMode && value" [text]="format(value)" [component]="component" [componentId]="componentId" | ||||
|     contextLevel="module" [contextInstanceId]="componentId" [courseId]="database!.course"> | ||||
| </core-format-text> | ||||
|     contextLevel="module" [contextInstanceId]="componentId" [courseId]="database!.course" /> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <span *ngIf="inputMode && form" [formGroup]="form"> | ||||
|     <span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span> | ||||
|     <ion-input type="url" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error"></core-input-errors> | ||||
|     <ion-input type="url" [formControlName]="'f_'+field.id" [placeholder]="field.name" /> | ||||
|     <core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" /> | ||||
| </span> | ||||
| 
 | ||||
| <ng-container *ngIf="displayMode && value && value.content"> | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
| @ -19,14 +18,13 @@ | ||||
| <ion-content> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <core-group-selector [groupInfo]="groupInfo" [(selected)]="selectedGroup" (selectedChange)="setGroup(selectedGroup)" | ||||
|             [courseId]="database?.course"> | ||||
|         </core-group-selector> | ||||
|             [courseId]="database?.course" /> | ||||
| 
 | ||||
|         <div class="addon-data-contents {{cssClass}}" *ngIf="database"> | ||||
|             <core-style [css]="database.csstemplate" prefix=".{{cssClass}}"></core-style> | ||||
|             <core-style [css]="database.csstemplate" prefix=".{{cssClass}}" /> | ||||
| 
 | ||||
|             <form (ngSubmit)="save($event)" [formGroup]="editForm" #editFormEl> | ||||
|                 <core-compile-html [text]="editFormRender" [jsData]="jsData" [extraImports]="extraImports"></core-compile-html> | ||||
|                 <core-compile-html [text]="editFormRender" [jsData]="jsData" [extraImports]="extraImports" /> | ||||
|             </form> | ||||
|         </div> | ||||
|     </core-loading> | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="moduleId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| @ -14,57 +13,51 @@ | ||||
| <ion-content class="limited-width"> | ||||
|     <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-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="entryLoaded && (isPullingToRefresh || !renderingEntry && !loadingRating && !loadingComments)"> | ||||
|         <!-- Database entries found to be synchronized --> | ||||
|         <ion-card class="core-warning-card" *ngIf="entry && entry.hasOffline"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate: {$a: moduleName} }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <core-group-selector [groupInfo]="groupInfo" [(selected)]="selectedGroup" (selectedChange)="setGroup(selectedGroup)" | ||||
|             [courseId]="courseId"> | ||||
|         </core-group-selector> | ||||
|             [courseId]="courseId" /> | ||||
| 
 | ||||
|         <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-style [css]="database.csstemplate" prefix=".addon-data-entries-{{database.id}}" /> | ||||
| 
 | ||||
|             <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)" /> | ||||
|         </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> | ||||
|             (onUpdate)="ratingUpdated()" /> | ||||
|         <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> | ||||
|             [scaleId]="database.scale" /> | ||||
| 
 | ||||
|         <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> | ||||
|             (onLoading)="setLoadingComments($event)" [showItem]="true" /> | ||||
|     </core-loading> | ||||
|     <div collapsible-footer *ngIf="entryLoaded && hasPrevious || hasNext" slot="fixed" appearOnBottom> | ||||
|         <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap"> | ||||
|             <ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto"> | ||||
|                 <ion-button [disabled]="!hasPrevious" fill="clear" [attr.aria-label]="'core.previous' | translate" | ||||
|                     (click)="gotoEntry(offset! -1)"> | ||||
|                     <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true" /> | ||||
|                 </ion-button> | ||||
|             </ion-col> | ||||
|             <ion-col class="ion-text-center"> | ||||
|             </ion-col> | ||||
|             <ion-col class="ion-text-center" /> | ||||
|             <ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto"> | ||||
|                 <ion-button [disabled]="!hasNext" fill="clear" [attr.aria-label]=" 'core.next' | translate" | ||||
|                     (click)="gotoEntry(offset! + 1)"> | ||||
|                     <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true" /> | ||||
|                 </ion-button> | ||||
|             </ion-col> | ||||
|         </ion-row> | ||||
|  | ||||
| @ -1,25 +1,21 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-data-index [module]="module" [courseId]="courseId" [group]="group" (dataRetrieved)="updateData($event)"> | ||||
|     </addon-mod-data-index> | ||||
|     <addon-mod-data-index [module]="module" [courseId]="courseId" [group]="group" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -10,26 +10,25 @@ | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()"> | ||||
|     </core-course-module-info> | ||||
|         [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()" /> | ||||
| 
 | ||||
|     <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-container *ngTemplateOutlet="tabOverview" /> | ||||
|             </ng-template> | ||||
|         </core-tab> | ||||
|         <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-container *ngTemplateOutlet="tabAnalysis" /> | ||||
|             </ng-template> | ||||
|         </core-tab> | ||||
| 
 | ||||
|         <core-tab *ngIf="showAnalysis && access && !access.canviewreports" id="analysis" | ||||
|             [title]="'addon.mod_feedback.completed_feedbacks' | translate" (ionSelect)="tabChanged('analysis')"> | ||||
|             <ng-template> | ||||
|                 <ng-container *ngTemplateOutlet="tabAnalysis"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="tabAnalysis" /> | ||||
|             </ng-template> | ||||
|         </core-tab> | ||||
|     </core-tabs> | ||||
| @ -39,7 +38,7 @@ | ||||
|             *ngIf="access && (access.canedititems || access.canviewreports || !access.isempty)"> | ||||
|             <ion-button *ngIf="access.canedititems || access.canviewreports" expand="block" fill="outline" | ||||
|                 (click)="gotoAnswerQuestions(true)" class="ion-margin ion-text-wrap"> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-magnifying-glass" slot="start" aria-hidden="true" /> | ||||
|                 {{ 'addon.mod_feedback.preview' | translate }} | ||||
|             </ion-button> | ||||
|             <ion-button *ngIf="access.cancomplete && access.cansubmit && access.isopen" expand="block" (click)="gotoAnswerQuestions()" | ||||
| @ -53,15 +52,13 @@ | ||||
|             </ion-button> | ||||
|         </div> | ||||
| 
 | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|         </core-course-module-navigation> | ||||
|         <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
|     </div> | ||||
| </core-loading> | ||||
| 
 | ||||
| <ng-template #basicInfo> | ||||
|     <ion-list *ngIf="access && access.canviewanalysis && !access.isempty"> | ||||
|         <core-group-selector [groupInfo]="groupInfo" [(selected)]="group" (selectedChange)="setGroup(group)" [courseId]="courseId"> | ||||
|         </core-group-selector> | ||||
|         <core-group-selector [groupInfo]="groupInfo" [(selected)]="group" (selectedChange)="setGroup(group)" [courseId]="courseId" /> | ||||
| 
 | ||||
|         <ion-item class="ion-text-wrap" (click)="openAttempts()" [class.hide-detail]="!(access.canviewreports && completedCount > 0)" | ||||
|             [detail]="true" [button]="access.canviewreports && completedCount > 0"> | ||||
| @ -98,18 +95,18 @@ | ||||
| <!-- Template to render the overview. --> | ||||
| <ng-template #tabOverview> | ||||
|     <core-loading [hideUntil]="tabsLoaded.overview"> | ||||
|         <ng-container *ngTemplateOutlet="basicInfo"></ng-container> | ||||
|         <ng-container *ngTemplateOutlet="basicInfo" /> | ||||
| 
 | ||||
|         <ion-card class="core-info-card" *ngIf="access && access.cancomplete && !access.isopen"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-question" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-question" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.mod_feedback.feedback_is_not_open' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ion-card class="core-success-card" *ngIf="access && access.cancomplete && access.isopen && !access.cansubmit"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-check" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.mod_feedback.this_feedback_is_already_submitted' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -131,8 +128,7 @@ | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.mod_feedback.page_after_submit' | translate }}</p> | ||||
|                     <core-format-text [component]="component" [componentId]="componentId" [text]="feedback.page_after_submit" | ||||
|                         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                         contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ng-container *ngIf="!access.isempty"> | ||||
| @ -151,12 +147,12 @@ | ||||
| <!-- Template to render the analysis. --> | ||||
| <ng-template #tabAnalysis> | ||||
|     <core-loading [hideUntil]="tabsLoaded.analysis"> | ||||
|         <ng-container *ngTemplateOutlet="basicInfo"></ng-container> | ||||
|         <ng-container *ngTemplateOutlet="basicInfo" /> | ||||
| 
 | ||||
|         <ng-container *ngIf="access && (access.canedititems || !access.isempty)"> | ||||
|             <ion-card class="core-info-card" *ngIf="warning"> | ||||
|                 <ion-item> | ||||
|                     <ion-icon name="fas-circle-question" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-circle-question" slot="start" aria-hidden="true" /> | ||||
|                     <ion-label>{{ warning }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
| @ -166,13 +162,11 @@ | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             {{item.num}}. <core-format-text [component]="component" [componentId]="componentId" [text]="item.name" | ||||
|                                 contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                                 contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|                         </p> | ||||
|                         <p> | ||||
|                             <core-format-text [component]="component" [componentId]="componentId" [text]="item.label" contextLevel="module" | ||||
|                                 [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                                 [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|                         </p> | ||||
|                         <ng-container [ngSwitch]="item.templateName"> | ||||
|                             <ng-container *ngSwitchCase="'numeric'"> | ||||
| @ -190,8 +184,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"> | ||||
|                                 </core-chart> | ||||
|                                     contextLevel="module" [contextInstanceId]="module.id" [wsNotFiltered]="true" [courseId]="courseId" /> | ||||
|                                 <p *ngIf="item.average"> | ||||
|                                     {{ 'addon.mod_feedback.average' | translate }}: {{item.average | number : '1.2-2'}} | ||||
|                                 </p> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="attempt">{{ attempt.fullname }}</h1> | ||||
| @ -14,7 +14,7 @@ | ||||
|         <ion-list class="ion-no-margin" *ngIf="attempt || anonAttempt"> | ||||
|             <ion-item *ngIf="attempt" class="ion-text-wrap" core-user-link [userId]="attempt.userid" | ||||
|                 [attr.aria-label]="'core.user.viewprofile' | translate" [courseId]="attempt.courseid"> | ||||
|                 <core-user-avatar [user]="attempt" slot="start" [linkProfile]="false"></core-user-avatar> | ||||
|                 <core-user-avatar [user]="attempt" slot="start" [linkProfile]="false" /> | ||||
|                 <ion-label> | ||||
|                     <h2>{{attempt.fullname}}</h2> | ||||
|                     <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p> | ||||
| @ -22,7 +22,7 @@ | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-item class="ion-text-wrap" *ngIf="anonAttempt"> | ||||
|                 <core-user-avatar [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                 <core-user-avatar [linkProfile]="false" slot="start" /> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_feedback.anonymous_user' |translate }}</h2> | ||||
|                     <p>{{ 'addon.mod_feedback.response_nr' | translate }}: {{anonAttempt.number}}</p> | ||||
| @ -30,19 +30,17 @@ | ||||
|             </ion-item> | ||||
|             <ng-container *ngIf="items && items.length"> | ||||
|                 <ng-container *ngFor="let item of items"> | ||||
|                     <core-spacer *ngIf="item.typ === 'pagebreak'"></core-spacer> | ||||
|                     <core-spacer *ngIf="item.typ === 'pagebreak'" /> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="item.typ !== 'pagebreak'" [color]="item.dependitem > 0 ? 'light' : ''"> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading" *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> | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|                             </p> | ||||
|                             <p *ngIf="item.submittedValue"> | ||||
|                                 <core-format-text [component]="component" [componentId]="cmId" [text]="item.submittedValue" | ||||
|                                     contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                 </core-format-text> | ||||
|                                     contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_feedback.responses' |translate }}</h1> | ||||
| @ -11,13 +11,12 @@ | ||||
| <ion-content> | ||||
|     <core-split-view> | ||||
|         <ion-refresher slot="fixed" [disabled]="!attempts || !attempts.loaded" (ionRefresh)="refreshFeedback($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="attempts && attempts.loaded"> | ||||
|             <ion-list class="ion-no-margin"> | ||||
|                 <core-group-selector [groupInfo]="groupInfo" [(selected)]="selectedGroup" (selectedChange)="reloadAttempts()" | ||||
|                     [courseId]="courseId"> | ||||
|                 </core-group-selector> | ||||
|                     [courseId]="courseId" /> | ||||
| 
 | ||||
|                 <ng-container *ngIf="identifiableAttemptsTotal > 0"> | ||||
|                     <ion-item-divider> | ||||
| @ -27,7 +26,7 @@ | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item *ngFor="let attempt of identifiableAttempts" class="ion-text-wrap" button [detail]="true" | ||||
|                         (click)="attempts?.select(attempt)" [attr.aria-current]="attempts?.getItemAriaCurrent(attempt)"> | ||||
|                         <core-user-avatar [user]="attempt" [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                         <core-user-avatar [user]="attempt" [linkProfile]="false" slot="start" /> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ attempt.fullname }}</p> | ||||
|                             <p *ngIf="attempt.timemodified">{{ attempt.timemodified * 1000 | coreFormatDate }}</p> | ||||
| @ -43,7 +42,7 @@ | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item *ngFor="let attempt of anonymousAttempts" class="ion-text-wrap" button [detail]="true" | ||||
|                         (click)="attempts?.select(attempt)" [attr.aria-current]="attempts?.getItemAriaCurrent(attempt)"> | ||||
|                         <core-user-avatar [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                         <core-user-avatar [linkProfile]="false" slot="start" /> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ 'addon.mod_feedback.anonymous_user' | translate }}</p> | ||||
|                             <p>{{ 'addon.mod_feedback.response_nr' | translate }}: {{attempt.number}}</p> | ||||
| @ -52,8 +51,7 @@ | ||||
|                 </ng-container> | ||||
| 
 | ||||
|                 <core-infinite-loading [enabled]="attempts && attempts.loaded && !attempts.completed" [error]="fetchFailed" | ||||
|                     (action)="fetchMoreAttempts($event)"> | ||||
|                 </core-infinite-loading> | ||||
|                     (action)="fetchMoreAttempts($event)" /> | ||||
|             </ion-list> | ||||
|         </core-loading> | ||||
|     </core-split-view> | ||||
|  | ||||
| @ -1,12 +1,11 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| @ -23,7 +22,7 @@ | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ng-container *ngFor="let item of items"> | ||||
|                     <core-spacer *ngIf="item.typ === 'pagebreak'"></core-spacer> | ||||
|                     <core-spacer *ngIf="item.typ === 'pagebreak'" /> | ||||
|                     <ng-container *ngIf="item.typ !== 'pagebreak'"> | ||||
|                         <ion-item class="ion-text-wrap addon-mod_feedback-item" [color]="item.dependitem > 0 ? 'light' : ''" | ||||
|                             [class.core-danger-item]="item.isEmpty || item.hasError"> | ||||
| @ -31,42 +30,36 @@ | ||||
|                                 <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> | ||||
|                                         [contextInstanceId]="cmId" [courseId]="courseId" [wsNotFiltered]="true" /> | ||||
|                                     <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> | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId" /> | ||||
|                                 </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> | ||||
|                                 name="{{item.typ}}_{{item.id}}" maxlength="{{item.length}}" [required]="item.required" /> | ||||
| 
 | ||||
|                             <ng-container *ngIf="item.templateName === 'numeric'"> | ||||
|                                 <ion-input type="number" [(ngModel)]="item.value" name="{{item.typ}}_{{item.id}}" | ||||
|                                     [required]="item.required"> | ||||
|                                 </ion-input> | ||||
|                                     [required]="item.required" /> | ||||
|                                 <ion-text *ngIf="item.hasError" color="danger" class="addon-mod_feedback-item-error"> | ||||
|                                     {{ 'addon.mod_feedback.numberoutofrange' | translate }} [{{item.rangefrom}} | ||||
|                                     <span *ngIf="item.rangefrom && item.rangeto">, </span>{{item.rangeto}}] | ||||
|                                 </ion-text> | ||||
|                             </ng-container> | ||||
| 
 | ||||
|                             <ion-textarea *ngIf="item.templateName === 'textarea'" [required]="item.required" name="{{item.typ}}_{{item.id}}" | ||||
|                                 [(ngModel)]="item.value"> | ||||
|                             </ion-textarea> | ||||
|                             <ion-textarea *ngIf="item.templateName === 'textarea'" [required]="item.required" | ||||
|                                 name="{{item.typ}}_{{item.id}}" [(ngModel)]="item.value" /> | ||||
| 
 | ||||
|                             <ion-select *ngIf="item.templateName === 'multichoice-d'" [required]="item.required" | ||||
|                                 name="{{item.typ}}_{{item.id}}" [(ngModel)]="item.value" interface="action-sheet" | ||||
|                                 [cancelText]="'core.cancel' | translate" [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"> | ||||
|                                     </core-format-text> | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId" /> | ||||
|                                 </ion-select-option> | ||||
|                             </ion-select> | ||||
|                         </ion-item> | ||||
| @ -76,10 +69,9 @@ | ||||
|                             <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> | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId" /> | ||||
|                                 </ion-label> | ||||
|                                 <ion-radio slot="start" [value]="option.value"></ion-radio> | ||||
|                                 <ion-radio slot="start" [value]="option.value" /> | ||||
|                             </ion-item> | ||||
|                         </ion-radio-group> | ||||
| 
 | ||||
| @ -87,22 +79,19 @@ | ||||
|                             <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> | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [wsNotFiltered]="true" [courseId]="courseId" /> | ||||
|                                 </ion-label> | ||||
|                                 <ion-checkbox [required]="item.required" name="{{item.typ}}_{{item.id}}" [(ngModel)]="option.checked" | ||||
|                                     value="option.value"> | ||||
|                                 </ion-checkbox> | ||||
|                                     value="option.value" /> | ||||
|                             </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> | ||||
|                                 modelValueName="value" /> | ||||
|                             <div *ngIf="!preview && (!item.captcha || offline)" class="core-warning-card"> | ||||
|                                 <ion-item> | ||||
|                                     <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                                     <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                                     <ion-label>{{ 'addon.mod_feedback.captchaofflinewarning' | translate }}</ion-label> | ||||
|                                 </ion-item> | ||||
|                             </div> | ||||
| @ -113,14 +102,14 @@ | ||||
|                 <ion-row class="ion-align-items-center spacer-top" *ngIf="!preview"> | ||||
|                     <ion-col *ngIf="hasPrevPage"> | ||||
|                         <ion-button expand="block" fill="outline" (click)="gotoPage(true)" class="ion-text-wrap"> | ||||
|                             <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-chevron-left" slot="start" aria-hidden="true" /> | ||||
|                             {{ 'core.previous' | translate }} | ||||
|                         </ion-button> | ||||
|                     </ion-col> | ||||
|                     <ion-col *ngIf="hasNextPage"> | ||||
|                         <ion-button expand="block" (click)="gotoPage(false)" class="ion-text-wrap"> | ||||
|                             {{ 'core.next' | translate }} | ||||
|                             <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-chevron-right" slot="end" aria-hidden="true" /> | ||||
|                         </ion-button> | ||||
|                     </ion-col> | ||||
|                     <ion-col *ngIf="!hasNextPage"> | ||||
| @ -134,7 +123,7 @@ | ||||
| 
 | ||||
|         <ion-card class="core-success-card" *ngIf="completed"> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-icon name="fas-check" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-check" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <p *ngIf="!completionPageContents && !completedOffline"> | ||||
|                         {{ 'addon.mod_feedback.this_feedback_is_already_submitted' | translate }} | ||||
| @ -143,8 +132,7 @@ | ||||
|                         {{ 'addon.mod_feedback.feedback_submitted_offline' | translate }} | ||||
|                     </p> | ||||
|                     <core-format-text *ngIf="completionPageContents" [component]="component" componentId="componentId" | ||||
|                         [text]="completionPageContents" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                         [text]="completionPageContents" contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -153,7 +141,7 @@ | ||||
|             <div class="list-item-limited-width adaptable-buttons-row"> | ||||
|                 <ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap ion-margin" | ||||
|                     *ngIf="access!.canviewanalysis"> | ||||
|                     <ion-icon name="fas-chart-bar" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon name="fas-chart-bar" slot="start" aria-hidden="true" /> | ||||
|                     {{ 'addon.mod_feedback.completed_feedbacks' | translate }} | ||||
|                 </ion-button> | ||||
|                 <ion-button expand="block" (click)="continue()" class="ion-text-wrap ion-margin"> | ||||
|  | ||||
| @ -1,24 +1,21 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="activityComponent?.showLoading" (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-feedback-index [module]="module" [courseId]="courseId" [group]="selectedGroup" [tab]="selectedTab" | ||||
|         (dataRetrieved)="updateData($event)"></addon-mod-feedback-index> | ||||
|         (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1>{{ 'addon.mod_feedback.responses' |translate }}</h1> | ||||
| @ -10,13 +10,12 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshFeedback($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ion-list class="ion-no-margin"> | ||||
|             <core-group-selector [groupInfo]="groupInfo" [(selected)]="selectedGroup" (selectedChange)="loadAttempts(selectedGroup)" | ||||
|                 [courseId]="courseId"> | ||||
|             </core-group-selector> | ||||
|                 [courseId]="courseId" /> | ||||
| 
 | ||||
|             <ion-item-divider> | ||||
|                 <ion-label> | ||||
| @ -25,7 +24,7 @@ | ||||
|             </ion-item-divider> | ||||
|             <ng-container *ngIf="total > 0"> | ||||
|                 <ion-item *ngFor="let user of users" class="ion-text-wrap"> | ||||
|                     <core-user-avatar [user]="user" slot="start"></core-user-avatar> | ||||
|                     <core-user-avatar [user]="user" slot="start" /> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ user.fullname }}</p> | ||||
|                         <p> | ||||
| @ -40,8 +39,7 @@ | ||||
|                 </ion-item> | ||||
|             </ng-container> | ||||
| 
 | ||||
|             <core-infinite-loading [enabled]="canLoadMore" (action)="loadAttempts(undefined, $event)" [error]="loadMoreError"> | ||||
|             </core-infinite-loading> | ||||
|             <core-infinite-loading [enabled]="canLoadMore" (action)="loadAttempts(undefined, $event)" [error]="loadMoreError" /> | ||||
|         </ion-list> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| @ -10,28 +10,26 @@ | ||||
| 
 | ||||
|     <!-- Activity info. --> | ||||
|     <core-course-module-info *ngIf="!subfolder" [module]="module" [description]="description" [component]="component" | ||||
|         [componentId]="componentId" [courseId]="courseId"> | ||||
|     </core-course-module-info> | ||||
|         [componentId]="componentId" [courseId]="courseId" /> | ||||
| 
 | ||||
|     <ion-list *ngIf="contents && (contents.files.length + contents.folders.length > 0)"> | ||||
|         <ng-container *ngFor="let folder of contents.folders"> | ||||
|             <ion-item class="ion-text-wrap item-file item-directory" (click)="openFolder(folder)" [detail]="true" button> | ||||
|                 <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate"></ion-icon> | ||||
|                 <ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.folder' | translate" /> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{folder.filename}}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ng-container> | ||||
|         <ng-container *ngFor="let file of contents.files"> | ||||
|             <core-file [file]="file" [component]="component" [componentId]="componentId"></core-file> | ||||
|             <core-file [file]="file" [component]="component" [componentId]="componentId" /> | ||||
|         </ng-container> | ||||
|     </ion-list> | ||||
| 
 | ||||
|     <core-empty-box *ngIf="!contents || (contents.files.length + contents.folders.length === 0)" icon="far-folder-open" | ||||
|         [message]=" 'addon.mod_folder.emptyfilelist' | translate"></core-empty-box> | ||||
|         [message]=" 'addon.mod_folder.emptyfilelist' | translate" /> | ||||
| 
 | ||||
| </core-loading> | ||||
| 
 | ||||
| <core-course-module-navigation collapsible-footer appearOnBottom *ngIf="!subfolder" [hidden]="showLoading" [courseId]="courseId" | ||||
|     [currentModuleId]="module.id" (completionChanged)="onCompletionChange()"> | ||||
| </core-course-module-navigation> | ||||
|     [currentModuleId]="module.id" (completionChanged)="onCompletionChange()" /> | ||||
|  | ||||
| @ -1,27 +1,23 @@ | ||||
| <ion-header [collapsible]="!subfolder"> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
| 
 | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="subfolder || activityComponent?.showLoading" | ||||
|         (ionRefresh)="activityComponent?.doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <addon-mod-folder-index [module]="module" [courseId]="courseId" [folderInstance]="folderInstance" [subfolder]="subfolder" | ||||
|         (dataRetrieved)="updateData($event)"> | ||||
|     </addon-mod-folder-index> | ||||
|         (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,39 +1,41 @@ | ||||
| <ion-content> | ||||
|     <ion-list> | ||||
|         <ion-item button class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked" [detail]="false"> | ||||
|             <ion-icon name="fas-lock" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-item button class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked" | ||||
|             [detail]="false"> | ||||
|             <ion-icon name="fas-lock" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_forum.lockdiscussion' | translate }}</p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|         <ion-item button class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked" [detail]="false"> | ||||
|             <ion-icon name="fas-unlock" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-item button class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked" | ||||
|             [detail]="false"> | ||||
|             <ion-icon name="fas-unlock" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_forum.unlockdiscussion' | translate }}</p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|         <ion-item button class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned" [detail]="false"> | ||||
|             <ion-icon name="fas-map-pin" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-map-pin" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_forum.pindiscussion' | translate }}</p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|         <ion-item button class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned" [detail]="false"> | ||||
|             <ion-icon name="fas-map-pin" slot="start" class="icon-slash" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-map-pin" slot="start" class="icon-slash" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_forum.unpindiscussion' | translate }}</p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|         <ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred" | ||||
|             [detail]="false"> | ||||
|             <ion-icon name="fas-star" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-star" slot="start" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_forum.addtofavourites' | translate }}</p> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|         <ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred" | ||||
|             [detail]="false"> | ||||
|             <ion-icon name="fas-star" slot="start" class="icon-slash" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-star" slot="start" class="icon-slash" aria-hidden="true" /> | ||||
|             <ion-label> | ||||
|                 <p class="item-heading">{{ 'addon.mod_forum.removefromfavourites' | translate }}</p> | ||||
|             </ion-label> | ||||
|  | ||||
| @ -1,19 +1,19 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button fill="clear" (click)="openSearch()" [attr.aria-label]="'core.search' | translate"> | ||||
|         <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-magnifying-glass" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
|     <ion-button fill="clear" (click)="openModuleSummary()" aria-haspopup="true" [attr.aria-label]="'core.info' | translate"> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|         <ion-icon name="fas-circle-info" slot="icon-only" aria-hidden="true" /> | ||||
|     </ion-button> | ||||
|     <!-- Add an empty context menu so split view pages can add items, otherwise the menu disappears in some cases. --> | ||||
|     <core-context-menu></core-context-menu> | ||||
|     <core-context-menu /> | ||||
| </core-navbar-buttons> | ||||
| 
 | ||||
| <!-- Content. --> | ||||
| <core-split-view> | ||||
|     <ion-refresher slot="fixed" [disabled]="showLoading || (discussions && !discussions.loaded)" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <core-loading [hideUntil]="!showLoading && discussions && discussions.loaded"> | ||||
| @ -29,13 +29,12 @@ | ||||
|         </core-course-module-info> | ||||
| 
 | ||||
|         <core-group-selector *ngIf="supportsChangeGroup" [groupInfo]="groupInfo" [(selected)]="groupId" (selectedChange)="groupChanged()" | ||||
|             [courseId]="courseId"> | ||||
|         </core-group-selector> | ||||
|             [courseId]="courseId" /> | ||||
| 
 | ||||
|         <!-- Cut-off date or due date message --> | ||||
|         <ion-card class="core-info-card" *ngIf="availabilityMessage"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ availabilityMessage }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -43,7 +42,7 @@ | ||||
|         <!-- Q&A message. --> | ||||
|         <ion-card class="core-info-card" *ngIf="showQAMessage"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.mod_forum.qandanotify' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -51,7 +50,7 @@ | ||||
|         <!-- Cannot add discussion to group messages. --> | ||||
|         <ion-card class="core-info-card" *ngIf="usesGroups && canAddDiscussion && !canAddDiscussionToGroup"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <span *ngIf="groupId <= 0">{{ 'addon.mod_forum.cannotadddiscussionall' | translate }}</span> | ||||
|                     <span *ngIf="groupId > 0">{{ 'addon.mod_forum.cannotadddiscussion' | translate }}</span> | ||||
| @ -63,13 +62,11 @@ | ||||
|             <div *ngIf="discussions && 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" | ||||
|                     interface="modal"> | ||||
|                 </core-combobox> | ||||
|                     interface="modal" /> | ||||
|             </div> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="!discussions || (!discussions.hasDiscussions && !errorLoadingDiscussions)" icon="far-comments" | ||||
|                 [message]="'addon.mod_forum.forumnodiscussionsyet' | translate"> | ||||
|             </core-empty-box> | ||||
|                 [message]="'addon.mod_forum.forumnodiscussionsyet' | translate" /> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="errorLoadingDiscussions" icon="fas-triangle-exclamation" | ||||
|                 [message]="'addon.mod_forum.errorloadingsortingorder' | translate"> | ||||
| @ -82,33 +79,29 @@ | ||||
|                 <ion-label> | ||||
|                     <p class="addon-mod-forum-discussion-title ion-text-wrap item-heading"> | ||||
|                         <ion-icon name="fas-map-pin" *ngIf="discussion.pinned" | ||||
|                             [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"></ion-icon> | ||||
|                             [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate" /> | ||||
|                         <ion-icon name="fas-star" class="addon-forum-star" *ngIf="discussion.starred" | ||||
|                             [attr.aria-label]="'addon.mod_forum.favourites' | translate"></ion-icon> | ||||
|                             [attr.aria-label]="'addon.mod_forum.favourites' | translate" /> | ||||
|                         <core-format-text [text]="discussion.subject" contextLevel="module" [contextInstanceId]="module && module.id" | ||||
|                             [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                             [courseId]="courseId" /> | ||||
|                         <ion-icon name="fas-lock" *ngIf="discussion.locked" class="addon-mod-forum-locked-icon" | ||||
|                             [attr.aria-label]="'addon.mod_forum.discussionlocked' | translate"></ion-icon> | ||||
|                             [attr.aria-label]="'addon.mod_forum.discussionlocked' | translate" /> | ||||
|                     </p> | ||||
|                     <div class="addon-mod-forum-discussion-info"> | ||||
|                         <core-user-avatar *ngIf="discussion.userfullname" [user]="discussion" slot="start" [courseId]="courseId" | ||||
|                             [linkProfile]="false"> | ||||
|                         </core-user-avatar> | ||||
|                             [linkProfile]="false" /> | ||||
|                         <div class="addon-mod-forum-discussion-author"> | ||||
|                             <span *ngIf="discussion.userfullname" class="core-discussionusername">{{discussion.userfullname}}</span> | ||||
|                             <p *ngIf="discussion.groupname" class="core-groupname"> | ||||
|                                 <ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate"> | ||||
|                                 </ion-icon> | ||||
|                                 <ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate" /> | ||||
|                                 <core-format-text [text]="discussion.groupname" contextLevel="course" [contextInstanceId]="courseId" | ||||
|                                     [wsNotFiltered]="true"> | ||||
|                                 </core-format-text> | ||||
|                                     [wsNotFiltered]="true" /> | ||||
|                             </p> | ||||
|                             <p *ngIf="isOnlineDiscussion(discussion)"> | ||||
|                                 {{discussion.created * 1000 | coreFormatDate: "strftimerecentfull"}} | ||||
|                             </p> | ||||
|                             <p *ngIf="isOfflineDiscussion(discussion)"> | ||||
|                                 <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> | ||||
|                                 <ion-icon name="fas-clock" aria-hidden="true" /> | ||||
|                                 {{ 'core.notsent' | translate }} | ||||
|                             </p> | ||||
|                         </div> | ||||
| @ -116,7 +109,7 @@ | ||||
|                     <ion-row *ngIf="isOnlineDiscussion(discussion)" class="ion-text-center addon-mod-forum-discussion-more-info"> | ||||
|                         <ion-col class="ion-text-start"> | ||||
|                             <ion-note> | ||||
|                                 <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'addon.mod_forum.lastpost' | translate }} | ||||
|                                 <ion-icon name="fas-clock" aria-hidden="true" /> {{ 'addon.mod_forum.lastpost' | translate }} | ||||
|                                 <ng-container *ngIf="discussion.timemodified > discussion.created"> | ||||
|                                     {{ discussion.timemodified | coreTimeAgo }} | ||||
|                                 </ng-container> | ||||
| @ -127,7 +120,7 @@ | ||||
|                         </ion-col> | ||||
|                         <ion-col class="ion-text-end"> | ||||
|                             <ion-note> | ||||
|                                 <ion-icon name="fas-comments" aria-hidden="true"></ion-icon> | ||||
|                                 <ion-icon name="fas-comments" aria-hidden="true" /> | ||||
|                                 {{ 'addon.mod_forum.numreplies' | translate:{numreplies: discussion.numreplies} }} | ||||
|                                 <ion-badge *ngIf="discussion.numunread" class="ion-text-center"> | ||||
|                                     <span aria-hidden="true">{{ discussion.numunread }}</span> | ||||
| @ -141,23 +134,20 @@ | ||||
|                 </ion-label> | ||||
|                 <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear" | ||||
|                     [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)" slot="end"> | ||||
|                     <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> | ||||
|                     </ion-icon> | ||||
|                     <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true" /> | ||||
|                 </ion-button> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <core-infinite-loading [enabled]="discussions && discussions.loaded && !discussions.completed" [error]="fetchFailed" | ||||
|                 (action)="fetchMoreDiscussions($event)"> | ||||
|             </core-infinite-loading> | ||||
|                 (action)="fetchMoreDiscussions($event)" /> | ||||
|         </ng-container> | ||||
|     </core-loading> | ||||
| 
 | ||||
|     <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id"> | ||||
|     </core-course-module-navigation> | ||||
|     <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id" /> | ||||
| 
 | ||||
|     <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAddDiscussionToGroup"> | ||||
|         <ion-fab-button (click)="openNewDiscussion()" [attr.aria-label]="addDiscussionText"> | ||||
|             <ion-icon name="fas-plus" aria-hidden="true"></ion-icon> | ||||
|             <ion-icon name="fas-plus" aria-hidden="true" /> | ||||
|             <span class="sr-only">{{ addDiscussionText }}</span> | ||||
|         </ion-fab-button> | ||||
|     </ion-fab> | ||||
|  | ||||
| @ -2,13 +2,13 @@ | ||||
|     <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
|         <ion-list> | ||||
|             <ion-item button class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || canEdit" [detail]="false"> | ||||
|                 <ion-icon name="fas-pen" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-pen" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'addon.mod_forum.edit' | translate }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item button class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || canDelete" [detail]="false"> | ||||
|                 <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-trash" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading" *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</p> | ||||
|                     <p class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p> | ||||
| @ -16,7 +16,7 @@ | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button [detail]="false" | ||||
|                 [showBrowserWarning]="false"> | ||||
|                 <ion-icon name="fas-up-right-from-square" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-up-right-from-square" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'core.openinbrowser' | translate }}</p> | ||||
|                 </ion-label> | ||||
|  | ||||
| @ -6,55 +6,48 @@ | ||||
|                     <div class="addon-mod-forum-post-title" *ngIf="displaySubject"> | ||||
|                         <h2 class="ion-text-wrap"> | ||||
|                             <ion-icon name="fas-map-pin" *ngIf="discussion && !post.parentid && discussion.pinned" | ||||
|                                 [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate"> | ||||
|                             </ion-icon> | ||||
|                                 [attr.aria-label]="'addon.mod_forum.discussionpinned' | translate" /> | ||||
|                             <ion-icon name="fas-star" class="addon-forum-star" [attr.aria-label]="'addon.mod_forum.favourites' | translate" | ||||
|                                 *ngIf="discussion && !post.parentid && !discussion.pinned && discussion.starred"> | ||||
|                             </ion-icon> | ||||
|                                 *ngIf="discussion && !post.parentid && !discussion.pinned && discussion.starred" /> | ||||
|                             <core-format-text [text]="post.subject" contextLevel="module" [contextInstanceId]="forum && forum.cmid" | ||||
|                                 [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                                 [courseId]="courseId" /> | ||||
|                         </h2> | ||||
|                         <ion-note *ngIf="trackPosts && post.unread" class="ion-float-end ion-padding-start ion-text-end" | ||||
|                             [attr.aria-label]="'addon.mod_forum.unread' | translate"> | ||||
|                             <ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon> | ||||
|                             <ion-icon name="fas-circle" color="primary" aria-hidden="true" /> | ||||
|                         </ion-note> | ||||
|                         <ion-button *ngIf="optionsMenuEnabled" fill="clear" [attr.aria-label]="('core.displayoptions' | translate)" | ||||
|                             (click)="showOptionsMenu($event)"> | ||||
|                             <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> | ||||
|                             </ion-icon> | ||||
|                             <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true" /> | ||||
|                         </ion-button> | ||||
|                     </div> | ||||
|                     <div class="addon-mod-forum-post-info"> | ||||
|                         <core-user-avatar *ngIf="post.author && post.author.fullname" [user]="post.author" slot="start" | ||||
|                             [courseId]="courseId"> | ||||
|                         </core-user-avatar> | ||||
|                             [courseId]="courseId" /> | ||||
|                         <div class="addon-mod-forum-post-author"> | ||||
|                             <span *ngIf="post.author && post.author.fullname" class="core-discussionusername"> | ||||
|                                 {{ post.author.fullname }} | ||||
|                             </span> | ||||
|                             <div *ngIf="post.author && post.author.groups"> | ||||
|                                 <p *ngFor="let group of post.author.groups" class="core-groupname"> | ||||
|                                     <ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate"> | ||||
|                                     </ion-icon> | ||||
|                                     <ion-icon name="fas-users" [attr.aria-label]="'addon.mod_forum.group' | translate" /> | ||||
|                                     <core-format-text [text]="group.name" contextLevel="course" [contextInstanceId]="courseId" | ||||
|                                         [wsNotFiltered]="true"> | ||||
|                                     </core-format-text> | ||||
|                                         [wsNotFiltered]="true" /> | ||||
|                                 </p> | ||||
|                             </div> | ||||
|                             <p *ngIf="post.timecreated">{{post.timecreated * 1000 | coreFormatDate: "strftimerecentfull"}}</p> | ||||
|                             <p *ngIf="!post.timecreated"> | ||||
|                                 <ion-icon name="fas-clock" aria-hidden="true"></ion-icon> {{ 'core.notsent' | translate }} | ||||
|                                 <ion-icon name="fas-clock" aria-hidden="true" /> {{ 'core.notsent' | translate }} | ||||
|                             </p> | ||||
|                         </div> | ||||
|                         <ng-container *ngIf="!displaySubject"> | ||||
|                             <ion-note *ngIf="trackPosts && post.unread" class="ion-float-end ion-padding-start ion-text-end" | ||||
|                                 [attr.aria-label]="'addon.mod_forum.unread' | translate"> | ||||
|                                 <ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon> | ||||
|                                 <ion-icon name="fas-circle" color="primary" aria-hidden="true" /> | ||||
|                             </ion-note> | ||||
|                             <ion-button *ngIf="optionsMenuEnabled" fill="clear" [attr.aria-label]="('core.displayoptions' | translate)" | ||||
|                                 (click)="showOptionsMenu($event)"> | ||||
|                                 <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                                 <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true" /> | ||||
|                             </ion-button> | ||||
|                         </ng-container> | ||||
|                     </div> | ||||
| @ -66,37 +59,33 @@ | ||||
|                 <ion-note color="danger">{{ 'addon.mod_forum.postisprivatereply' | translate }}</ion-note> | ||||
|             </div> | ||||
|             <core-format-text [component]="component" [componentId]="componentId" [text]="post.message" contextLevel="module" | ||||
|                 [contextInstanceId]="forum && forum.cmid" [courseId]="courseId"> | ||||
|             </core-format-text> | ||||
|                 [contextInstanceId]="forum && forum.cmid" [courseId]="courseId" /> | ||||
|             <p *ngIf="post.haswordcount && post.wordcount"> | ||||
|                 <em>{{ 'core.numwords' | translate: {'$a': post.wordcount} }}</em> | ||||
|             </p> | ||||
|             <div *ngIf="post.attachments && post.attachments.length > 0"> | ||||
|                 <core-files [files]="post.attachments" [component]="component" [componentId]="componentId" showInline="true"> | ||||
|                 </core-files> | ||||
|                 <core-files [files]="post.attachments" [component]="component" [componentId]="componentId" showInline="true" /> | ||||
|             </div> | ||||
|         </ion-card-content> | ||||
|         <div class="addon-mod-forum-post-more-info"> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="tagsEnabled && post.tags && post.tags.length > 0"> | ||||
|                 <div slot="start">{{ 'core.tag.tags' | translate }}:</div> | ||||
|                 <ion-label> | ||||
|                     <core-tag-list [tags]="post.tags"></core-tag-list> | ||||
|                     <core-tag-list [tags]="post.tags" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <core-rating-rate *ngIf="forum && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" | ||||
|                 [itemId]="post.id" [itemSetId]="discussionId" [courseId]="courseId" [aggregateMethod]="forum.assessed" | ||||
|                 [scaleId]="forum.scale" [userId]="post.author.id" (onUpdate)="ratingUpdated()"> | ||||
|             </core-rating-rate> | ||||
|                 [scaleId]="forum.scale" [userId]="post.author.id" (onUpdate)="ratingUpdated()" /> | ||||
|             <core-rating-aggregate *ngIf="forum && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" [instanceId]="componentId" | ||||
|                 [itemId]="post.id" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale"> | ||||
|             </core-rating-aggregate> | ||||
|                 [itemId]="post.id" [courseId]="courseId" [aggregateMethod]="forum.assessed" [scaleId]="forum.scale" /> | ||||
| 
 | ||||
|             <ion-item *ngIf="post.id > 0 && post.capabilities.reply && !post.isprivatereply" | ||||
|                 class="ion-no-padding ion-text-end addon-forum-reply-button"> | ||||
|                 <ion-label> | ||||
|                     <ion-button fill="clear" size="small" [attr.aria-controls]="'addon-forum-reply-edit-form-' + uniqueId" | ||||
|                         [attr.aria-expanded]="formData.replyingTo === post.id" (click)="showReplyForm($event)"> | ||||
|                         <ion-icon name="fas-reply" slot="start" aria-hidden="true"></ion-icon> | ||||
|                         <ion-icon name="fas-reply" slot="start" aria-hidden="true" /> | ||||
|                         {{ 'addon.mod_forum.reply' | translate }} | ||||
|                     </ion-button> | ||||
|                 </ion-label> | ||||
| @ -107,37 +96,33 @@ | ||||
|     <form *ngIf="showForm" [id]="'addon-forum-reply-edit-form-' + uniqueId" #replyFormEl> | ||||
|         <ion-item> | ||||
|             <ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label> | ||||
|             <ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="formData.subject" name="subject"> | ||||
|             </ion-input> | ||||
|             <ion-input type="text" [placeholder]="'addon.mod_forum.subject' | translate" [(ngModel)]="formData.subject" name="subject" /> | ||||
|         </ion-item> | ||||
|         <ion-item> | ||||
|             <ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label> | ||||
|             <core-rich-text-editor elementId="message" contextLevel="module" [control]="messageControl" | ||||
|                 [placeholder]="'addon.mod_forum.replyplaceholder' | translate" [name]="'mod_forum_reply_' + post.id" [component]="component" | ||||
|                 [componentId]="componentId" [autoSave]="true" [contextInstanceId]="forum && forum.cmid" | ||||
|                 [draftExtraParams]="{reply: post.id}" (contentChanged)="onMessageChange($event)"> | ||||
|             </core-rich-text-editor> | ||||
|                 [draftExtraParams]="{reply: post.id}" (contentChanged)="onMessageChange($event)" /> | ||||
|         </ion-item> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="accessInfo.canpostprivatereply"> | ||||
|             <ion-label>{{ 'addon.mod_forum.privatereply' | translate }}</ion-label> | ||||
|             <ion-checkbox slot="end" [(ngModel)]="formData.isprivatereply" name="isprivatereply"></ion-checkbox> | ||||
|             <ion-checkbox slot="end" [(ngModel)]="formData.isprivatereply" name="isprivatereply" /> | ||||
|         </ion-item> | ||||
|         <ng-container *ngIf="forum.id && forum.maxattachments > 0"> | ||||
|             <ion-item button class="divider ion-text-wrap" (click)="toggleAdvanced()" [detail]="false" [attr.aria-expanded]="advanced" | ||||
|                 [attr.aria-controls]="'addon-forum-reply-edit-form-advanced-' + uniqueId" | ||||
|                 [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate"> | ||||
|                 <ion-icon *ngIf="!advanced" name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" | ||||
|                     class="expandable-status-icon"></ion-icon> | ||||
|                 <ion-icon *ngIf="advanced" name="fas-chevron-down" slot="start" aria-hidden="true" class="expandable-status-icon"> | ||||
|                 </ion-icon> | ||||
|                     class="expandable-status-icon" /> | ||||
|                 <ion-icon *ngIf="advanced" name="fas-chevron-down" slot="start" aria-hidden="true" class="expandable-status-icon" /> | ||||
|                 <ion-label> | ||||
|                     <h3 class="item-heading">{{ 'addon.mod_forum.advanced' | translate }}</h3> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <div *ngIf="advanced" [id]="'addon-forum-reply-edit-form-advanced-' + uniqueId"> | ||||
|                 <core-attachments [files]="formData.files" [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments" | ||||
|                     [component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId"> | ||||
|                 </core-attachments> | ||||
|                     [component]="component" [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId" /> | ||||
|             </div> | ||||
|         </ng-container> | ||||
|         <ion-grid> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <ion-button fill="clear" (click)="closeModal()" [attr.aria-label]="'core.close' | translate"> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-xmark" slot="icon-only" aria-hidden="true" /> | ||||
|             </ion-button> | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
|  | ||||
| @ -1,72 +1,59 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1 *ngIf="startingPost"> | ||||
|                 <core-format-text contextLevel="module" [text]="startingPost.subject" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text contextLevel="module" [text]="startingPost.subject" [contextInstanceId]="cmId" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The context menu will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </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" | ||||
|             (action)="doRefresh(null, $event)"> | ||||
|         </core-context-menu-item> | ||||
|             (action)="doRefresh(null, $event)" /> | ||||
|         <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> | ||||
|             (action)="doRefresh(null, $event, true)" /> | ||||
|         <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> | ||||
|             [content]="'addon.mod_forum.modeflatoldestfirst' | translate" iconAction="fas-arrow-down" | ||||
|             (action)="changeSort('flat-oldest')" /> | ||||
|         <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> | ||||
|             [content]="'addon.mod_forum.modeflatnewestfirst' | translate" iconAction="fas-arrow-up" (action)="changeSort('flat-newest')" /> | ||||
|         <core-context-menu-item [hidden]="sort === 'nested'" [priority]="400" [content]="'addon.mod_forum.modenested' | translate" | ||||
|             iconAction="fas-right-left" (action)="changeSort('nested')"> | ||||
|         </core-context-menu-item> | ||||
|             iconAction="fas-right-left" (action)="changeSort('nested')" /> | ||||
|         <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> | ||||
|             [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.unlockdiscussion' | translate" iconAction="fas-unlock" (action)="setLockState(false)"> | ||||
|         </core-context-menu-item> | ||||
|             [content]="'addon.mod_forum.unlockdiscussion' | translate" iconAction="fas-unlock" (action)="setLockState(false)" /> | ||||
|         <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> | ||||
|             [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.unpindiscussion' | translate" [iconSlash]="true" iconAction="fas-map-pin" | ||||
|             (action)="setPinState(false)"> | ||||
|         </core-context-menu-item> | ||||
|             (action)="setPinState(false)" /> | ||||
|         <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> | ||||
|             [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.removefromfavourites' | translate" iconAction="fas-star" [iconSlash]="true" | ||||
|             (action)="toggleFavouriteState(false)"> | ||||
|         </core-context-menu-item> | ||||
|             (action)="toggleFavouriteState(false)" /> | ||||
|         <core-context-menu-item [hidden]="!externalUrl" [priority]="100" [content]="'core.openinbrowser' | translate" [href]="externalUrl" | ||||
|             iconAction="fas-up-right-from-square" [showBrowserWarning]="false"></core-context-menu-item> | ||||
|             iconAction="fas-up-right-from-square" [showBrowserWarning]="false" /> | ||||
|     </core-context-menu> | ||||
| </core-navbar-buttons> | ||||
| <ion-content [core-swipe-navigation]="discussions" class="limited-width"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!discussionLoaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|     <core-loading [hideUntil]="discussionLoaded"> | ||||
|         <!-- Discussion replies found to be synchronized --> | ||||
|         <ion-card class="core-warning-card" *ngIf="postHasOffline || hasOfflineRatings"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-triangle-exclamation" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate:{$a: discussionStr} }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -74,14 +61,14 @@ | ||||
|         <!-- Cut-off date or due date message --> | ||||
|         <ion-card class="core-info-card" *ngIf="availabilityMessage"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ availabilityMessage }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ion-card class="core-info-card" *ngIf="discussion && discussion.locked"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-lock" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-lock" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.mod_forum.discussionlocked' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -89,7 +76,7 @@ | ||||
|         <!-- Q&A message. --> | ||||
|         <ion-card class="core-info-card" *ngIf="showQAMessage"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label>{{ 'addon.mod_forum.qandanotify' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| @ -98,24 +85,22 @@ | ||||
|             <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> | ||||
|                 [leavingPage]="leavingPage" (onPostChange)="postListChanged()" /> | ||||
|         </div> | ||||
| 
 | ||||
|         <ion-card *ngIf="sort !== 'nested' && posts.length"> | ||||
|             <ng-container *ngFor="let post of posts; first as first"> | ||||
|                 <core-spacer *ngIf="!first"></core-spacer> | ||||
|                 <core-spacer *ngIf="!first" /> | ||||
|                 <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> | ||||
|                     [leavingPage]="leavingPage" (onPostChange)="postListChanged()" /> | ||||
|             </ng-container> | ||||
|         </ion-card> | ||||
| 
 | ||||
|         <ng-container *ngIf="sort === 'nested' && posts.length"> | ||||
|             <ng-container *ngFor="let post of posts"> | ||||
|                 <ng-container *ngTemplateOutlet="nestedPosts; context: {post: post}"></ng-container> | ||||
|                 <ng-container *ngTemplateOutlet="nestedPosts; context: {post: post}" /> | ||||
|             </ng-container> | ||||
|         </ng-container> | ||||
| 
 | ||||
| @ -124,12 +109,11 @@ | ||||
|                 <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> | ||||
|                     [leavingPage]="leavingPage" (onPostChange)="postListChanged()" /> | ||||
|             </ion-card> | ||||
|             <div class="ion-padding-start" *ngIf="post.children && post.children.length && post.children[0].subject"> | ||||
|                 <ng-container *ngFor="let child of post.children"> | ||||
|                     <ng-container *ngTemplateOutlet="nestedPosts; context: {post: child}"></ng-container> | ||||
|                     <ng-container *ngTemplateOutlet="nestedPosts; context: {post: child}" /> | ||||
|                 </ng-container> | ||||
|             </div> | ||||
|         </ng-template> | ||||
|  | ||||
| @ -1,20 +1,17 @@ | ||||
| <ion-header collapsible> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </ion-buttons> | ||||
|         <ion-title> | ||||
|             <h1> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId"> | ||||
|                 </core-format-text> | ||||
|                 <core-format-text [text]="title" contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" /> | ||||
|             </h1> | ||||
|         </ion-title> | ||||
|         <ion-buttons slot="end"> | ||||
|             <!-- The buttons defined by the component will be added in here. --> | ||||
|         </ion-buttons> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| 
 | ||||
| <ion-content> | ||||
|     <addon-mod-forum-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-forum-index> | ||||
|     <addon-mod-forum-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)" /> | ||||
| </ion-content> | ||||
|  | ||||
| @ -1,41 +1,37 @@ | ||||
| <ion-header> | ||||
|     <ion-toolbar> | ||||
|         <ion-buttons slot="start"> | ||||
|             <ion-back-button [text]="'core.back' | translate"></ion-back-button> | ||||
|             <ion-back-button [text]="'core.back' | translate" /> | ||||
|         </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> | ||||
|         <ion-buttons slot="end" /> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content [core-swipe-navigation]="discussions"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!groupsLoaded" (ionRefresh)="refreshGroups($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" /> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="groupsLoaded"> | ||||
|         <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> | ||||
|                     name="subject" /> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label> | ||||
|                 <core-rich-text-editor name="addon_mod_forum_new_discussion" contextLevel="module" elementId="message" | ||||
|                     [control]="messageControl" [placeholder]="'addon.mod_forum.message' | translate" [component]="component" | ||||
|                     [componentId]="forum.cmid" [autoSave]="true" [contextInstanceId]="forum.cmid" | ||||
|                     (contentChanged)="onMessageChange($event)"> | ||||
|                 </core-rich-text-editor> | ||||
|                     (contentChanged)="onMessageChange($event)" /> | ||||
|             </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-icon name="fas-chevron-right" flip-rtl slot="start" aria-hidden="true" class="expandable-status-icon" | ||||
|                     [class.expandable-status-icon-expanded]="advanced"></ion-icon> | ||||
|                     [class.expandable-status-icon-expanded]="advanced" /> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_forum.advanced' | translate }}</h2> | ||||
|                 </ion-label> | ||||
| @ -43,7 +39,7 @@ | ||||
|             <div *ngIf="advanced" id="addon-mod-forum-new-discussion-advanced"> | ||||
|                 <ion-item *ngIf="showGroups && groupIds.length > 1 && accessInfo.cancanposttomygroups"> | ||||
|                     <ion-label>{{ 'addon.mod_forum.posttomygroups' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.postToAllGroups" name="postallgroups" slot="end"></ion-toggle> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.postToAllGroups" name="postallgroups" slot="end" /> | ||||
|                 </ion-item> | ||||
|                 <ion-item *ngIf="showGroups" class="core-edit-set-group"> | ||||
|                     <ion-label>{{ 'addon.mod_forum.group' | translate }}</ion-label> | ||||
| @ -52,29 +48,27 @@ | ||||
|                         [cancelText]="'core.cancel' | translate" (ionChange)="calculateGroupName()"> | ||||
|                         <ion-select-option *ngFor="let group of groups" [value]="group.id"> | ||||
|                             <core-format-text [text]="group.name" contextLevel="course" [contextInstanceId]="courseId" | ||||
|                                 [wsNotFiltered]="true"></core-format-text> | ||||
|                                 [wsNotFiltered]="true" /> | ||||
|                         </ion-select-option> | ||||
|                     </ion-select> | ||||
|                 </ion-item> | ||||
|                 <ion-item> | ||||
|                     <ion-label>{{ 'addon.mod_forum.discussionsubscription' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.subscribe" name="subscribe" slot="end"></ion-toggle> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.subscribe" name="subscribe" slot="end" /> | ||||
|                 </ion-item> | ||||
|                 <ion-item *ngIf="canPin"> | ||||
|                     <ion-label>{{ 'addon.mod_forum.discussionpinned' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.pin" name="pin" slot="end"></ion-toggle> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.pin" name="pin" slot="end" /> | ||||
|                 </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> | ||||
|                     [allowOffline]="true" [courseId]="courseId" /> | ||||
|             </div> | ||||
|             <ion-item *ngIf="showGroups && postInGroupMessage && !newDiscussion.postToAllGroups" class="addon-forum-group-info"> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon name="fas-circle-info" slot="start" aria-hidden="true" /> | ||||
|                 <ion-label> | ||||
|                     <core-format-text [text]="postInGroupMessage" contextLevel="course" [contextInstanceId]="courseId" | ||||
|                         [wsNotFiltered]="true"> | ||||
|                     </core-format-text> | ||||
|                         [wsNotFiltered]="true" /> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="addon-forum-new-discussion-buttons"> | ||||
|  | ||||
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