forked from EVOgeek/Vmeda.Online
		
	
						commit
						f2c19b0a6b
					
				| @ -18,7 +18,7 @@ | ||||
| 
 | ||||
|             <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" | ||||
|                     (click)="badges.select(badge)" [attr.aria-current]="badges.getItemAriaCurrent(badge)"> | ||||
|                     (click)="badges.select(badge)" [attr.aria-current]="badges.getItemAriaCurrent(badge)" detail="true"> | ||||
|                     <ion-avatar slot="start"> | ||||
|                         <img [src]="badge.badgeurl" [alt]="badge.name" core-external-content> | ||||
|                     </ion-avatar> | ||||
|  | ||||
| @ -3,8 +3,8 @@ | ||||
|         <h2>{{ 'addon.block_activitymodules.pluginname' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
|     <ion-item class="ion-text-wrap item-media" *ngFor="let entry of entries" detail="false" button | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="margin"> | ||||
|     <ion-item class="ion-text-wrap item-media" *ngFor="let entry of entries" detail="true" button | ||||
|         (click)="gotoCoureListModType(entry)"> | ||||
|         <img slot="start" [src]="entry.icon" alt="" role="presentation" class="core-module-icon"> | ||||
|         <ion-label>{{ entry.name }}</ion-label> | ||||
|  | ||||
| @ -36,7 +36,7 @@ | ||||
|         </core-context-menu-item> | ||||
|     </core-context-menu> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="margin"> | ||||
|     <div class="safe-padding-horizontal" [hidden]="showFilter || !showSelectorFilter"> | ||||
|         <!-- "Time" selector. --> | ||||
|         <core-combobox [label]="'core.show' | translate" [selection]="selectedFilter" (onChange)="selectedChanged($event)"> | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
|         </core-horizontal-scroll-controls> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page margin"> | ||||
|     <core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg" inline="true" | ||||
|         [message]="'addon.block_recentlyaccessedcourses.nocourses' | translate"></core-empty-box> | ||||
|     <!-- List of courses. --> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|         </core-horizontal-scroll-controls> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page margin"> | ||||
|     <div | ||||
|         [id]="scrollElementId" | ||||
|         [hidden]="!items || items.length === 0" | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
|         <h2>{{ 'addon.block_sitemainmenu.pluginname' | translate }}</h2> | ||||
|     </ion-label> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="margin"> | ||||
|     <ng-container *ngIf="mainMenuBlock"> | ||||
|         <ion-item class="ion-text-wrap" *ngIf="mainMenuBlock.summary"> | ||||
|             <ion-label> | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
|         </core-horizontal-scroll-controls> | ||||
|     </div> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="safe-area-page margin"> | ||||
|     <core-empty-box *ngIf="courses.length == 0" image="assets/img/icons/courses.svg" inline="true" | ||||
|         [message]="'addon.block_starredcourses.nocourses' | translate"></core-empty-box> | ||||
|     <!-- List of courses. --> | ||||
|  | ||||
| @ -9,7 +9,7 @@ | ||||
|         </core-context-menu-item> | ||||
|     </core-context-menu> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="margin"> | ||||
|     <div class="safe-padding-horizontal"> | ||||
|         <core-combobox [selection]="filter" (onChange)="switchFilter($event)"> | ||||
|             <ion-select-option class="ion-text-wrap" value="all"> | ||||
| @ -35,12 +35,12 @@ | ||||
|             </ion-select-option> | ||||
|         </core-combobox> | ||||
|     </div> | ||||
|     <core-loading [hideUntil]="timeline.loaded" [hidden]="sort != 'sortbydates'" [fullscreen]="false"> | ||||
|     <core-loading [hideUntil]="timeline.loaded" [hidden]="sort != 'sortbydates'" [fullscreen]="false" class="margin"> | ||||
|         <addon-block-timeline-events [events]="timeline.events" showCourse="true" [canLoadMore]="timeline.canLoadMore" | ||||
|             (loadMore)="loadMoreTimeline()" [from]="dataFrom" [to]="dataTo"></addon-block-timeline-events> | ||||
|     </core-loading> | ||||
|     <core-loading [hideUntil]="timelineCourses.loaded" [hidden]="sort != 'sortbycourses'" | ||||
|         [fullscreen]="false" class="safe-area-page"> | ||||
|         [fullscreen]="false" class="safe-area-page margin"> | ||||
|         <ion-grid class="ion-no-padding"> | ||||
|             <ion-row class="ion-no-padding"> | ||||
|                 <ion-col *ngFor="let course of timelineCourses.courses" class="ion-no-padding" size="12" size-md="6"> | ||||
|  | ||||
| @ -54,22 +54,18 @@ | ||||
|                             <core-tag-list [tags]="entry.tags"></core-tag-list> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item *ngIf="commentsEnabled" detail="true"> | ||||
|                         <ion-label> | ||||
|                             <core-comments [component]="this.component" [itemId]="entry.id" area="format_blog" | ||||
|                                 [instanceId]="entry.userid" contextLevel="user"> | ||||
|                     <core-comments *ngIf="commentsEnabled" [component]="this.component" [itemId]="entry.id" area="format_blog" | ||||
|                         [instanceId]="entry.userid" contextLevel="user" [showItem]="true"> | ||||
|                     </core-comments> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <core-file *ngFor="let file of entry.attachmentfiles" [file]="file" [component]="this.component" | ||||
|                         [componentId]="entry.id"> | ||||
|                     </core-file> | ||||
|                     <ion-item *ngIf="entry.uniquehash" [href]="entry.uniquehash" core-link> | ||||
|                     <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> | ||||
|                 <ion-row class="ion-text-center"> | ||||
|                     <ion-col *ngIf="entry.lastmodified > entry.created"> | ||||
|                 <ion-row class="ion-text-center" *ngIf="entry.lastmodified > entry.created"> | ||||
|                     <ion-col> | ||||
|                         <ion-note> | ||||
|                             <ion-icon name="fas-clock" | ||||
|                                 [attr.aria-label]="'core.lastmodified' | translate"></ion-icon> {{entry.lastmodified | coreTimeAgo}} | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
|     <ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin"> | ||||
|         <ng-container *ngFor="let event of filteredEvents"> | ||||
|             <ion-item class="ion-text-wrap addon-calendar-event" [attr.aria-label]="event.name" (click)="eventClicked(event)" button | ||||
|                 [ngClass]="['addon-calendar-eventtype-'+event.eventtype]"> | ||||
|                 [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" detail="true"> | ||||
|                 <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt="" | ||||
|                     role="presentation"> | ||||
|                 <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true"> | ||||
|  | ||||
| @ -60,7 +60,7 @@ | ||||
|         <ion-list *ngIf="filteredEvents && filteredEvents.length" class="ion-no-margin"> | ||||
|             <ng-container *ngFor="let event of filteredEvents"> | ||||
|                 <ion-item class="addon-calendar-event ion-text-wrap" [attr.aria-label]="event.name" (click)="gotoEvent(event.id)" | ||||
|                 [class.item-dimmed]="event.ispast" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button> | ||||
|                 [class.item-dimmed]="event.ispast" [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button detail="true"> | ||||
|                     <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt="" | ||||
|                         role="presentation"> | ||||
|                     <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" aria-hidden="true"> | ||||
|  | ||||
| @ -101,7 +101,7 @@ | ||||
|             </ng-container> | ||||
| 
 | ||||
|             <!-- Advanced options. --> | ||||
|             <ion-item button class="ion-text-wrap core-expandable divider" (click)="toggleAdvanced()"> | ||||
|             <ion-item button class="ion-text-wrap core-expandable divider" (click)="toggleAdvanced()" detail="false"> | ||||
|                 <ion-icon *ngIf="!advanced" name="fas-caret-right" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon *ngIf="advanced" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label> | ||||
| @ -138,7 +138,7 @@ | ||||
|                             <ion-radio slot="end" value="0"></ion-radio> | ||||
|                             <ion-label>{{ 'addon.calendar.durationnone' | translate }}</ion-label> | ||||
|                         </ion-item> | ||||
|                         <ion-item button (click)="selectDuration('1')"> | ||||
|                         <ion-item button (click)="selectDuration('1')" detail="false"> | ||||
|                             <ion-radio slot="end" value="1"></ion-radio> | ||||
|                             <ion-label>{{ 'addon.calendar.durationuntil' | translate }}</ion-label> | ||||
|                             <ion-datetime formControlName="timedurationuntil" [max]="maxDate" [min]="minDate" | ||||
| @ -146,7 +146,7 @@ | ||||
|                                 [displayFormat]="dateFormat" [disabled]="form.controls.duration.value != 1"> | ||||
|                             </ion-datetime> | ||||
|                         </ion-item> | ||||
|                         <ion-item button (click)="selectDuration('2')"> | ||||
|                         <ion-item button (click)="selectDuration('2')" detail="false"> | ||||
|                             <ion-radio slot="end" value="2"></ion-radio> | ||||
|                             <ion-label>{{ 'addon.calendar.durationminutes' | translate }}</ion-label> | ||||
|                             <ion-input type="number" name="timedurationminutes" slot="end" | ||||
|  | ||||
| @ -166,12 +166,13 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy { | ||||
|     ngOnInit(): void { | ||||
|         this.notificationsEnabled = CoreLocalNotifications.isAvailable(); | ||||
| 
 | ||||
|         this.loadUpcoming = !!CoreNavigator.getRouteBooleanParam('upcoming'); | ||||
|         this.showCalendar = !this.loadUpcoming; | ||||
| 
 | ||||
|         this.route.queryParams.subscribe(async () => { | ||||
|             this.filter.courseId = CoreNavigator.getRouteNumberParam('courseId'); | ||||
|             this.year = CoreNavigator.getRouteNumberParam('year'); | ||||
|             this.month = CoreNavigator.getRouteNumberParam('month'); | ||||
|             this.loadUpcoming = !!CoreNavigator.getRouteBooleanParam('upcoming'); | ||||
|             this.showCalendar = !this.loadUpcoming; | ||||
|             this.filter.filtered = !!this.filter.courseId; | ||||
| 
 | ||||
|             this.fetchData(true, false); | ||||
|  | ||||
| @ -44,7 +44,7 @@ | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="addon-calendar-event ion-text-wrap" [attr.aria-label]="event.name" (click)="gotoEvent(event.id)" | ||||
|                         [attr.aria-current]="event.id == eventId ? 'page' : 'false'" | ||||
|                         [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button> | ||||
|                         [ngClass]="['addon-calendar-eventtype-'+event.eventtype]" button detail="true"> | ||||
|                         <img *ngIf="event.moduleIcon" src="{{event.moduleIcon}}" slot="start" class="core-module-icon" alt="" | ||||
|                             role="presentation"> | ||||
|                         <ion-icon *ngIf="event.eventIcon && !event.moduleIcon" [name]="event.eventIcon" slot="start" | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|             <ion-list> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let competency of competencies.items" | ||||
|                     [attr.aria-label]="competency.competency.shortname" (click)="competencies.select(competency)" | ||||
|                     [attr.aria-current]="competencies.getItemAriaCurrent(competency)" button> | ||||
|                     [attr.aria-current]="competencies.getItemAriaCurrent(competency)" button detail="true"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ competency.competency.shortname }} <em>{{competency.competency.idnumber}}</em></p> | ||||
|                     </ion-label> | ||||
|  | ||||
| @ -28,47 +28,50 @@ | ||||
|                     </core-format-text> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|             <ion-item class="ion-text-wrap only-links"> | ||||
|                 <ion-label> | ||||
|                     <strong>{{ 'addon.competency.path' | translate }}</strong> | ||||
|                     <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
|                     <p> | ||||
|                         <a *ngIf="competency.competency.comppath.showlinks" | ||||
|                             [href]="competency.competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + | ||||
|                             competency.competency.comppath.framework.id + '&pagecontextid=' + | ||||
|                             competency.competency.comppath.pagecontextid" | ||||
|                         core-link [title]="competency.competency.comppath.framework.name"> | ||||
|                             core-link> | ||||
|                             {{ competency.competency.comppath.framework.name }} | ||||
|                         </a> | ||||
|                         <ng-container *ngIf="!competency.competency.comppath.showlinks"> | ||||
|                             {{ competency.competency.comppath.framework.name }} | ||||
|                         </ng-container> | ||||
|                          /  | ||||
|                     <span *ngFor="let ancestor of competency.competency.comppath.ancestors"> | ||||
|                         <a *ngIf="competency.competency.comppath.showlinks" (click)="openCompetencySummary(ancestor.id)"> | ||||
|                         <ng-container *ngFor="let ancestor of competency.competency.comppath.ancestors"> | ||||
|                             <button *ngIf="competency.competency.comppath.showlinks" (click)="openCompetencySummary(ancestor.id)" | ||||
|                                 class="as-link"> | ||||
|                                 {{ ancestor.name }} | ||||
|                         </a> | ||||
|                             </button> | ||||
|                             <ng-container *ngIf="!competency.competency.comppath.showlinks">{{ ancestor.name }}</ng-container> | ||||
|                             <ng-container *ngIf="!ancestor.last"> / </ng-container> | ||||
|                     </span> | ||||
|                         </ng-container> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <strong>{{ 'addon.competency.crossreferencedcompetencies' | translate }}</strong>: | ||||
|                     <div *ngIf="!competency.competency.hasrelatedcompetencies"> | ||||
|                     <p class="item-heading">{{ 'addon.competency.crossreferencedcompetencies' | translate }}</p> | ||||
|                     <p *ngIf="!competency.competency.hasrelatedcompetencies"> | ||||
|                         {{ 'addon.competency.nocrossreferencedcompetencies' | translate }} | ||||
|                     </div> | ||||
|                     <div *ngIf="competency.competency.hasrelatedcompetencies"> | ||||
|                         <p *ngFor="let relatedcomp of competency.competency.relatedcompetencies"> | ||||
|                             <a (click)="openCompetencySummary(relatedcomp.id)"> | ||||
|                                 {{ relatedcomp.shortname }} - {{ relatedcomp.idnumber }} | ||||
|                             </a> | ||||
|                     </p> | ||||
|                     </div> | ||||
|                     <ng-container *ngIf="competency.competency.hasrelatedcompetencies"> | ||||
|                         <p *ngFor="let relatedcomp of competency.competency.relatedcompetencies"> | ||||
|                             <button (click)="openCompetencySummary(relatedcomp.id)" class="as-link"> | ||||
|                                 {{ relatedcomp.shortname }} - {{ relatedcomp.idnumber }} | ||||
|                             </button> | ||||
|                         </p> | ||||
|                     </ng-container> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="coursemodules"> | ||||
|                 <ion-label> | ||||
|                     <strong>{{ 'addon.competency.activities' | translate }}</strong> | ||||
|                     <p class="item-heading">{{ 'addon.competency.activities' | translate }}</p> | ||||
|                     <p *ngIf="coursemodules.length == 0"> | ||||
|                         {{ 'addon.competency.noactivities' | translate }} | ||||
|                     </p> | ||||
| @ -87,13 +90,13 @@ | ||||
|             <ng-container *ngIf="userCompetency"> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="competency.usercompetency && competency.usercompetency!.status"> | ||||
|                     <ion-label> | ||||
|                         <strong>{{ 'addon.competency.reviewstatus' | translate }}</strong> | ||||
|                         {{ competency.usercompetency!.statusname }} | ||||
|                         <p class="item-heading">{{ 'addon.competency.reviewstatus' | translate }}</p> | ||||
|                         <p>{{ competency.usercompetency!.statusname }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label> | ||||
|                         <strong>{{ 'addon.competency.proficient' | translate }}</strong> | ||||
|                         <p class="item-heading">{{ 'addon.competency.proficient' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" color="success" *ngIf="userCompetency.proficiency"> | ||||
|                         {{ 'core.yes' | translate }} | ||||
| @ -104,7 +107,7 @@ | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label> | ||||
|                         <strong>{{ 'addon.competency.rating' | translate }}</strong> | ||||
|                         <p class="item-heading">{{ 'addon.competency.rating' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge color="dark" slot="end">{{ userCompetency.gradename }}</ion-badge> | ||||
|                 </ion-item> | ||||
|  | ||||
| @ -23,11 +23,15 @@ | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <strong>{{ 'addon.competency.path' | translate }}</strong> | ||||
|                     {{ competency.comppath.framework.name }} | ||||
|                     <span *ngFor="let ancestor of competency.comppath.ancestors"> | ||||
|                          / <a (click)="openCompetencySummary(ancestor.id)">{{ ancestor.name }}</a> | ||||
|                     </span> | ||||
|                     <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
|                     <p>{{ competency.comppath.framework.name }} | ||||
|                         <ng-container *ngFor="let ancestor of competency.comppath.ancestors"> | ||||
|                              /  | ||||
|                             <button class="as-link" (click)="openCompetencySummary(ancestor.id)"> | ||||
|                                 {{ ancestor.name }} | ||||
|                             </button> | ||||
|                         </ng-container> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|  | ||||
| @ -34,11 +34,11 @@ | ||||
|             <ion-item class="ion-text-wrap" | ||||
|                 *ngIf="competencies.statistics.canmanagecoursecompetencies && competencies.statistics.leastproficientcount > 0"> | ||||
|                 <ion-label> | ||||
|                     <strong>{{ 'addon.competency.competenciesmostoftennotproficientincourse' | translate }}</strong>: | ||||
|                     <p class="item-heading">{{ 'addon.competency.competenciesmostoftennotproficientincourse' | translate }}</p> | ||||
|                     <p *ngFor="let comp of competencies.statistics.leastproficient"> | ||||
|                         <a (click)="openCompetencySummary(comp.id)"> | ||||
|                         <button class="as-link" (click)="openCompetencySummary(comp.id)"> | ||||
|                             {{ comp.shortname }} - {{ comp.idnumber }} | ||||
|                         </a> | ||||
|                         </button> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| @ -63,7 +63,7 @@ | ||||
|                     [attr.aria-label]="competency.competency.shortname" detail="true" button> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <strong>{{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em></strong> | ||||
|                             {{competency.competency.shortname}} <em>{{competency.competency.idnumber}}</em> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" *ngIf="competency.usercompetencycourse && competency.usercompetencycourse.gradename" | ||||
| @ -79,7 +79,8 @@ | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                         <div> | ||||
|                             <strong>{{ 'addon.competency.path' | translate }}</strong> | ||||
|                             <p class="item-heading">{{ 'addon.competency.path' | translate }}</p> | ||||
|                             <p> | ||||
|                                 <a *ngIf="competency.comppath.showlinks" | ||||
|                                     [href]="competency.comppath.pluginbaseurl + '/competencies.php?competencyframeworkid=' + | ||||
|                                     competency.comppath.framework.id + '&pagecontextid=' + competency.comppath.pagecontextid" | ||||
| @ -90,22 +91,24 @@ | ||||
|                                     {{ competency.comppath.framework.name }} | ||||
|                                 </ng-container> | ||||
|                                  /  | ||||
|                             <span *ngFor="let ancestor of competency.comppath.ancestors"> | ||||
|                                 <a *ngIf="competency.comppath.showlinks" (click)="openCompetencySummary(ancestor.id)"> | ||||
|                                 <ng-container *ngFor="let ancestor of competency.comppath.ancestors"> | ||||
|                                     <button class="as-link" *ngIf="competency.comppath.showlinks" | ||||
|                                         (click)="openCompetencySummary(ancestor.id)"> | ||||
|                                         {{ ancestor.name }} | ||||
|                                 </a> | ||||
|                                     </button> | ||||
|                                     <ng-container *ngIf="!competency.comppath.showlinks">{{ ancestor.name }}</ng-container> | ||||
|                                     <ng-container *ngIf="!ancestor.last"> / </ng-container> | ||||
|                             </span> | ||||
|                                 </ng-container> | ||||
|                             </p> | ||||
|                         </div> | ||||
|                         <div *ngIf="competencies.statistics.canmanagecoursecompetencies"> | ||||
|                             <strong>{{ 'addon.competency.uponcoursecompletion' | translate }}</strong> | ||||
|                             <p class="item-heading">{{ 'addon.competency.uponcoursecompletion' | translate }}</p> | ||||
|                              <ng-container *ngFor="let ruleoutcome of competency.ruleoutcomeoptions"> | ||||
|                                 <span *ngIf="ruleoutcome.selected">{{ ruleoutcome.text }}</span> | ||||
|                             </ng-container> | ||||
|                         </div> | ||||
|                         <div> | ||||
|                             <strong>{{ 'addon.competency.activities' | translate }}</strong> | ||||
|                             <p class="item-heading">{{ 'addon.competency.activities' | translate }}</p> | ||||
|                             <p *ngIf="competency.coursemodules.length == 0"> | ||||
|                                 {{ 'addon.competency.noactivities' | translate }} | ||||
|                             </p> | ||||
| @ -121,7 +124,7 @@ | ||||
|                             </ion-item> | ||||
|                         </div> | ||||
|                         <div *ngIf="competency.plans"> | ||||
|                             <strong>{{ 'addon.competency.userplans' | translate }}</strong> | ||||
|                             <p class="item-heading">{{ 'addon.competency.userplans' | translate }}</p> | ||||
|                             <p *ngIf="competency.plans.length == 0"> | ||||
|                                 {{ 'addon.competency.nouserplanswithcompetency' | translate }} | ||||
|                             </p> | ||||
|  | ||||
| @ -23,37 +23,35 @@ | ||||
|             <ion-list> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="plan.plan.description" lines="none"> | ||||
|                     <ion-label> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="plan.plan.description" contextLevel="user" | ||||
|                                 [contextInstanceId]="plan.plan.userid"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" lines="none"> | ||||
|                     <ion-label> | ||||
|                         <p> | ||||
|                             <strong>{{ 'addon.competency.status' | translate }}</strong>: {{ plan.plan.statusname }} | ||||
|                         </p> | ||||
|                         <p class="item-heading">{{ 'addon.competency.status' | translate }}</p> | ||||
|                         <p>{{ plan.plan.statusname }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="plan.plan.duedate > 0" lines="none"> | ||||
|                     <ion-label> | ||||
|                         <p> | ||||
|                             <strong>{{ 'addon.competency.duedate' | translate }}</strong>: | ||||
|                             {{ plan.plan.duedate * 1000 | coreFormatDate }} | ||||
|                         </p> | ||||
|                         <p class="item-heading">{{ 'addon.competency.duedate' | translate }}</p> | ||||
|                         <p>{{ plan.plan.duedate * 1000 | coreFormatDate }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="plan.plan.template" lines="none"> | ||||
|                     <ion-label> | ||||
|                         <p> | ||||
|                             <strong>{{ 'addon.competency.template' | translate }}</strong>: {{ plan.plan.template.shortname }} | ||||
|                         </p> | ||||
|                         <p class="item-heading">{{ 'addon.competency.template' | translate }}</p> | ||||
|                         <p>{{ plan.plan.template.shortname }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" lines="none"> | ||||
|                     <ion-label> | ||||
|                         <p id="addon-competency-plan-{{plan.plan.id}}-progress"> | ||||
|                             <strong>{{ 'addon.competency.progress' | translate }}</strong>: | ||||
|                     <ion-label id="addon-competency-plan-{{plan.plan.id}}-progress"> | ||||
|                         <p class="item-heading">{{ 'addon.competency.progress' | translate }}</p> | ||||
|                         <p> | ||||
|                             {{ 'addon.competency.xcompetenciesproficientoutofy' | translate: | ||||
|                                 {$a: {x: plan.proficientcompetencycount, y: plan.competencycount} } }} | ||||
|                         </p> | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
|             </core-empty-box> | ||||
|             <ion-list *ngIf="!plans.empty" class="ion-no-margin"> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let plan of plans.items" [attr.aria-label]="plan.name" | ||||
|                     (click)="plans.select(plan)" [attr.aria-current]="plans.getItemAriaCurrent(plan)" button> | ||||
|                     (click)="plans.select(plan)" [attr.aria-current]="plans.getItemAriaCurrent(plan)" button detail="true"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ plan.name }}</p> | ||||
|                         <p *ngIf="plan.duedate > 0"> | ||||
|  | ||||
| @ -8,10 +8,9 @@ | ||||
|                 alt="" onError="this.src='assets/img/group-avatar.png'" core-external-content role="presentation" | ||||
|                 [siteId]="siteId || null"> | ||||
|             <core-user-avatar *ngIf="loaded && otherMember" class="core-bar-button-image" [user]="otherMember" | ||||
|                 [linkProfile]="false" [checkOnline]="otherMember.showonlinestatus" (click)="showInfo && viewInfo()"> | ||||
|                 [linkProfile]="false" [checkOnline]="otherMember.showonlinestatus"> | ||||
|             </core-user-avatar> | ||||
|             <core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0" | ||||
|                 (click)="showInfo && !isGroup && viewInfo()"></core-format-text> | ||||
|             <core-format-text [text]="title" contextLevel="system" [contextInstanceId]="0"></core-format-text> | ||||
|             <ion-icon *ngIf="conversation && conversation.isfavourite" name="fas-star" | ||||
|                 [attr.aria-label]="'core.favourites' | translate"> | ||||
|             </ion-icon> | ||||
| @ -93,12 +92,16 @@ | ||||
|                     [@coreSlideInOut]="message.useridfrom == currentUserId ? '' : 'fromLeft'"> | ||||
|                     <ion-label> | ||||
|                         <!-- User data. --> | ||||
|                         <div class="item-heading addon-message-user" [attr.aria-label]="message.useridfrom == currentUserId ? | ||||
|                             ('addon.messages.you' | translate) : members[message.useridfrom].fullname"> | ||||
|                         <div *ngIf="message.showUserData" class="item-heading addon-message-user"> | ||||
|                             <core-user-avatar slot="start" [user]="members[message.useridfrom]" [linkProfile]="false" | ||||
|                                 *ngIf="message.showUserData"></core-user-avatar> | ||||
| 
 | ||||
|                             <div *ngIf="message.showUserData">{{ members[message.useridfrom].fullname }}</div> | ||||
|                                 aria-hidden="true"> | ||||
|                             </core-user-avatar> | ||||
|                             {{ members[message.useridfrom].fullname }} | ||||
|                         </div> | ||||
|                         <div *ngIf="!message.showUserData" class="sr-only"> | ||||
|                             {{ message.useridfrom == currentUserId | ||||
|                             ? ('addon.messages.you' | translate) | ||||
|                             : members[message.useridfrom].fullname }} | ||||
|                         </div> | ||||
| 
 | ||||
|                         <!-- Some messages have <p> and some others don't. Add a <p> so they all have same styles. --> | ||||
|  | ||||
| @ -250,6 +250,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView | ||||
|                     this.title = user.fullname; | ||||
|                 } | ||||
|                 this.conversationImage = user.profileimageurl; | ||||
|                 this.members[user.id] = <AddonMessagesConversationMember>user; | ||||
| 
 | ||||
|                 return; | ||||
|             }).catch(() => { | ||||
| @ -1302,7 +1303,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView | ||||
|     async viewInfo(): Promise<void> { | ||||
|         if (this.isGroup) { | ||||
|             // Display the group information.
 | ||||
|             const userId = await CoreDomUtils.openModal<number>({ | ||||
|             const userId = await CoreDomUtils.openSideModal<number>({ | ||||
|                 component: AddonMessagesConversationInfoComponent, | ||||
|                 componentProps: { | ||||
|                     conversationId: this.conversationId, | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
| 
 | ||||
|         <core-search-box *ngIf="search.enabled" (onSubmit)="searchMessage($event)" (onClear)="clearSearch()" | ||||
|             [placeholder]=" 'addon.messages.message' | translate" autocorrect="off" spellcheck="false" lengthCheck="2" | ||||
|             [disabled]="!loaded" searchArea="AddonMessagesDiscussions"></core-search-box> | ||||
|             [disabled]="!loaded" searchArea="AddonMessagesDiscussions" [autoFocus]="false"></core-search-box> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded" [message]="loadingMessage"> | ||||
| 
 | ||||
| @ -40,7 +40,7 @@ | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let result of search.results" button | ||||
|                         [attr.aria-label]="result.fullname" (click)="gotoDiscussion(result.userid, result.messageid)" | ||||
|                         [attr.aria-current]="result.userid == discussionUserId ? 'page' : 'false'"> | ||||
|                         [attr.aria-current]="result.userid == discussionUserId ? 'page' : 'false'" detail="false"> | ||||
|                         <core-user-avatar [user]="result" slot="start" [checkOnline]="result.showonlinestatus"></core-user-avatar> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading">{{ result.fullname }}</p> | ||||
|  | ||||
| @ -40,7 +40,8 @@ | ||||
|         <ion-item class="ion-text-wrap"> | ||||
|             <ion-label> | ||||
|                 <core-format-text [text]="description" [component]="component" [componentId]="componentId" maxHeight="120" | ||||
|                     contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" (click)="expandDescription($event)"> | ||||
|                     contextLevel="module" [contextInstanceId]="module.id" [courseId]="courseId" | ||||
|                     (onClick)="expandDescription($event)"> | ||||
|                 </core-format-text> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
| <core-loading [hideUntil]="loaded" class="margin"> | ||||
| 
 | ||||
|     <!-- User and status of the submission. --> | ||||
|     <ion-item class="ion-text-wrap" *ngIf="!blindMarking && user" core-user-link [userId]="submitId" [courseId]="courseId" | ||||
|  | ||||
| @ -40,7 +40,7 @@ | ||||
|                 <!-- 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)"> | ||||
|                         [attr.aria-current]="submissions.getItemAriaCurrent(submission)" detail="true"> | ||||
|                         <core-user-avatar [user]="submission" [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                         <ion-label> | ||||
|                             <p class="item-heading" *ngIf="submission.userfullname">{{submission.userfullname}}</p> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="false" button> | ||||
| <ion-item *ngIf="commentsEnabled" class="ion-text-wrap" (click)="showComments($event)" detail="true" button> | ||||
|     <ion-label> | ||||
|         <h2>{{plugin.name}}</h2> | ||||
|         <core-comments contextLevel="module" [instanceId]="assign.cmid" component="assignsubmission_comments" | ||||
|  | ||||
| @ -13,11 +13,11 @@ | ||||
|         <ion-list> | ||||
|             <ion-item class="ion-text-wrap" *ngFor="let chapter of chapters" (click)="loadChapter(chapter.id)" | ||||
|                 [attr.aria-current]="selected == chapter.id ? 'page' : 'false'" button | ||||
|                 [class.item-dimmed]="chapter.hidden"> | ||||
|                 [class.item-dimmed]="chapter.hidden" detail="false"> | ||||
|                 <ion-label> | ||||
|                     <p [class.ion-padding-left]="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> | ||||
|                     <p [class.ion-padding-left]="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> | ||||
|  | ||||
| @ -30,7 +30,7 @@ | ||||
|                 <ion-toggle [(ngModel)]="showAll" (ionChange)="fetchSessions(true)"></ion-toggle> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <ion-card *ngFor="let session of sessions.items" (click)="sessions.select(session)" | ||||
|             <ion-card *ngFor="let session of sessions.items" (click)="sessions.select(session)" button | ||||
|                 [attr.aria-current]="sessions.getItemAriaCurrent(session)" | ||||
|                 [class.addon-mod-chat-session-show-more]="session.sessionusers.length < session.allsessionusers.length"> | ||||
| 
 | ||||
| @ -47,11 +47,10 @@ | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-card-content> | ||||
|                 <div *ngIf="session.sessionusers.length < session.allsessionusers.length"> | ||||
|                     <ion-button fill="clear" (click)="showMoreUsers(session, $event)"> | ||||
|                 <ion-button *ngIf="session.sessionusers.length < session.allsessionusers.length" fill="clear" expand="block" | ||||
|                     (click)="showMoreUsers(session, $event)"> | ||||
|                     {{ 'core.showmore' | translate }} | ||||
|                 </ion-button> | ||||
|                 </div> | ||||
|             </ion-card> | ||||
| 
 | ||||
|             <core-empty-box *ngIf="sessions.empty" icon="far-comments" [message]="'addon.mod_chat.nosessionsfound' | translate"> | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| <core-dynamic-component [component]="fieldComponent" [data]="pluginData"> | ||||
|     <!-- This content will be replaced by the component if found. --> | ||||
|     <core-loading [hideUntil]="fieldLoaded"> | ||||
|     </core-loading> | ||||
|     <core-loading [hideUntil]="fieldLoaded" [fullscreen]="false"></core-loading> | ||||
| </core-dynamic-component> | ||||
|  | ||||
| @ -103,16 +103,18 @@ | ||||
| 
 | ||||
|     <!-- Reset search. --> | ||||
|     <ng-container *ngIf="search.searching && !isEmpty"> | ||||
|         <ion-item *ngIf="!foundRecordsTranslationData"> | ||||
|             <ion-label> | ||||
|                 <a (click)="searchReset()">{{ 'addon.mod_data.resetsettings' | translate}}</a> | ||||
|         <ion-item (click)="searchReset()" button detail="false"> | ||||
|             <ion-label color="primary"> | ||||
|                 {{ 'addon.mod_data.resetsettings' | translate}} | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <ion-card class="core-success-card" *ngIf="foundRecordsTranslationData" (click)="searchReset()"> | ||||
|             <ion-item><ion-label> | ||||
|         <ion-card class="core-success-card" *ngIf="foundRecordsTranslationData"> | ||||
|             <ion-item (click)="searchReset()" button detail="false"> | ||||
|                 <ion-label> | ||||
|                     <p [innerHTML]="'addon.mod_data.foundrecords' | translate:{$a: foundRecordsTranslationData}"></p> | ||||
|             </ion-label></ion-item> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|     </ng-container> | ||||
| 
 | ||||
| @ -144,7 +146,7 @@ | ||||
| 
 | ||||
|     <core-empty-box *ngIf="isEmpty && search.searching" icon="fas-database" [message]="'addon.mod_data.nomatch' | translate" | ||||
|         class="core-empty-box-clickable"> | ||||
|         <a (click)="searchReset()">{{ 'addon.mod_data.resetsettings' | translate}}</a> | ||||
|         <button class="as-link" (click)="searchReset()">{{ 'addon.mod_data.resetsettings' | translate}}</button> | ||||
|     </core-empty-box> | ||||
| 
 | ||||
| </core-loading> | ||||
|  | ||||
| @ -48,6 +48,8 @@ import { AddonModDataPrefetchHandler } from '../../services/handlers/prefetch'; | ||||
| import { AddonModDataComponentsCompileModule } from '../components-compile.module'; | ||||
| import { AddonModDataSearchComponent } from '../search/search'; | ||||
| 
 | ||||
| const contentToken = '<!-- CORE-DATABASE-CONTENT-GOES-HERE -->'; | ||||
| 
 | ||||
| /** | ||||
|  * Component that displays a data index page. | ||||
|  */ | ||||
| @ -318,12 +320,22 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp | ||||
|         if (!this.isEmpty) { | ||||
|             this.entries = (entries.offlineEntries || []).concat(entries.entries); | ||||
| 
 | ||||
|             let entriesHTML = AddonModDataHelper.getTemplate( | ||||
|             let headerAndFooter = AddonModDataHelper.getTemplate( | ||||
|                 this.database!, | ||||
|                 AddonModDataTemplateType.LIST_HEADER, | ||||
|                 this.fieldsArray, | ||||
|             ); | ||||
| 
 | ||||
|             headerAndFooter += contentToken; | ||||
| 
 | ||||
|             headerAndFooter += AddonModDataHelper.getTemplate( | ||||
|                 this.database!, | ||||
|                 AddonModDataTemplateType.LIST_FOOTER, | ||||
|                 this.fieldsArray, | ||||
|             ); | ||||
| 
 | ||||
|             headerAndFooter = CoreDomUtils.fixHtml(headerAndFooter); | ||||
| 
 | ||||
|             // Get first entry from the whole list.
 | ||||
|             if (!this.search.searching || !this.firstEntry) { | ||||
|                 this.firstEntry = this.entries[0].id; | ||||
| @ -331,6 +343,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp | ||||
| 
 | ||||
|             const template = AddonModDataHelper.getTemplate(this.database!, AddonModDataTemplateType.LIST, this.fieldsArray); | ||||
| 
 | ||||
|             let entriesHTML = ''; | ||||
| 
 | ||||
|             const entriesById: Record<number, AddonModDataEntry> = {}; | ||||
|             this.entries.forEach((entry, index) => { | ||||
|                 entriesById[entry.id] = entry; | ||||
| @ -349,9 +363,8 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp | ||||
|                     actions, | ||||
|                 ); | ||||
|             }); | ||||
|             entriesHTML += AddonModDataHelper.getTemplate(this.database!, AddonModDataTemplateType.LIST_FOOTER, this.fieldsArray); | ||||
| 
 | ||||
|             this.entriesRendered = CoreDomUtils.fixHtml(entriesHTML); | ||||
|             this.entriesRendered = headerAndFooter.replace(contentToken, entriesHTML); | ||||
| 
 | ||||
|             // Pass the input data to the component.
 | ||||
|             this.jsData = { | ||||
|  | ||||
| @ -12,6 +12,10 @@ $grid-column-paddings: ( | ||||
|   xl: var(--ion-grid-column-padding-xl, $grid-column-padding) | ||||
| ) !default; | ||||
| 
 | ||||
| :host { | ||||
|     --border-color: var(--gray); | ||||
| } | ||||
| 
 | ||||
| .addon-data-contents { | ||||
|     overflow: visible; | ||||
|     white-space: normal; | ||||
| @ -19,9 +23,7 @@ $grid-column-paddings: ( | ||||
|     padding: 16px; | ||||
| 
 | ||||
|     background-color: var(--ion-item-background); | ||||
|     border-width: 1px 0; | ||||
|     border-style: solid; | ||||
|     border-color: var(--gray-dark); | ||||
|     border-bottom: 1px solid var(--border-color); | ||||
| 
 | ||||
|     ::ng-deep { | ||||
|         table, tbody { | ||||
|  | ||||
| @ -14,9 +14,9 @@ | ||||
|     <ion-input type="text" [formControlName]="'f_'+field.id" [placeholder]="field.name"></ion-input> | ||||
| </span> | ||||
| 
 | ||||
| <span *ngIf="listMode && imageUrl" (click)="gotoEntry.emit(entryId)"> | ||||
| <button class="as-link" *ngIf="listMode && imageUrl" (click)="navigateEntry()"> | ||||
|     <img [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" core-external-content/> | ||||
| </span> | ||||
| </button> | ||||
| 
 | ||||
| <img *ngIf="showMode && imageUrl" [src]="imageUrl" [alt]="title" class="core-media-adapt-width listMode_picture" | ||||
|     [attr.width]="width" [attr.height]="height" core-external-content/> | ||||
|  | ||||
| @ -138,4 +138,11 @@ export class AddonModDataFieldPictureComponent extends AddonModDataFieldPluginCo | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Navigate to the entry. | ||||
|      */ | ||||
|     navigateEntry(): void { | ||||
|         this.gotoEntry.emit(this.entryId); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -37,7 +37,7 @@ | ||||
|             </ion-select> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <div class="addon-data-contents addon-data-entries-{{database.id}}" *ngIf="database && entry"> | ||||
|         <div class="addon-data-contents addon-data-entry addon-data-entries-{{database.id}}" *ngIf="database && entry"> | ||||
|             <core-style [css]="database.csstemplate" prefix=".addon-data-entries-{{database.id}}"></core-style> | ||||
| 
 | ||||
|             <core-compile-html [text]="entryHtml" [jsData]="jsData" [extraImports]="extraImports" | ||||
| @ -54,13 +54,10 @@ | ||||
|             [scaleId]="database.scale"> | ||||
|         </core-rating-aggregate> | ||||
| 
 | ||||
|         <ion-item *ngIf="database && database.comments && entry && entry.id > 0 && commentsEnabled"> | ||||
|             <ion-label> | ||||
|                 <core-comments contextLevel="module" [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" | ||||
|                     area="database_entry" [displaySpinner]="false" [courseId]="courseId" (onLoading)="setLoadingComments($event)"> | ||||
|         <core-comments *ngIf="database && database.comments && entry && entry.id > 0 && commentsEnabled" | ||||
|             contextLevel="module" [instanceId]="database.coursemodule" component="mod_data" [itemId]="entry.id" | ||||
|             area="database_entry" [courseId]="courseId" (onLoading)="setLoadingComments($event)" [showItem]="true"> | ||||
|         </core-comments> | ||||
|             </ion-label> | ||||
|         </ion-item> | ||||
| 
 | ||||
|         <ion-grid *ngIf="hasPrevious || hasNext"> | ||||
|             <ion-row class="ion-align-items-center"> | ||||
|  | ||||
| @ -658,7 +658,7 @@ export class AddonModDataHelperProvider { | ||||
|         // Add core-link directive to links.
 | ||||
|         template = template.replace( | ||||
|             /<a ([^>]*href="[^>]*)>/ig, | ||||
|             (match, attributes) => '<a core-link capture="true" ' + attributes + '>', | ||||
|             (match, attributes) => '<button class="as-link" core-link capture="true" ' + attributes + '>', | ||||
|         ); | ||||
| 
 | ||||
|         return template; | ||||
|  | ||||
| @ -1,36 +1,38 @@ | ||||
| <ion-item class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked"> | ||||
| <ion-item button class="ion-text-wrap" (click)="setLockState(true)" *ngIf="discussion.canlock && !discussion.locked" detail="false"> | ||||
|     <ion-icon name="fa-lock" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.mod_forum.lockdiscussion' | translate }}</h2> | ||||
|         <p class="item-heading">{{ 'addon.mod_forum.lockdiscussion' | translate }}</p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked"> | ||||
| <ion-item button class="ion-text-wrap" (click)="setLockState(false)" *ngIf="discussion.canlock && discussion.locked" detail="false"> | ||||
|     <ion-icon name="fa-unlock" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.mod_forum.unlockdiscussion' | translate }}</h2> | ||||
|         <p class="item-heading">{{ 'addon.mod_forum.unlockdiscussion' | translate }}</p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned"> | ||||
| <ion-item button class="ion-text-wrap" (click)="setPinState(true)" *ngIf="canPin && !discussion.pinned" detail="false"> | ||||
|     <ion-icon name="fa-map-pin" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.mod_forum.pindiscussion' | translate }}</h2> | ||||
|         <p class="item-heading">{{ 'addon.mod_forum.pindiscussion' | translate }}</p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned"> | ||||
| <ion-item button class="ion-text-wrap" (click)="setPinState(false)" *ngIf="canPin && discussion.pinned" detail="false"> | ||||
|     <ion-icon name="fa-map-pin" slot="start" class="icon-slash" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.mod_forum.unpindiscussion' | translate }}</h2> | ||||
|         <p class="item-heading">{{ 'addon.mod_forum.unpindiscussion' | translate }}</p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred"> | ||||
| <ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(true)" *ngIf="discussion.canfavourite && !discussion.starred" | ||||
|     detail="false"> | ||||
|     <ion-icon name="fa-star" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.mod_forum.addtofavourites' | translate }}</h2> | ||||
|         <p class="item-heading">{{ 'addon.mod_forum.addtofavourites' | translate }}</p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
| <ion-item class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred"> | ||||
| <ion-item button class="ion-text-wrap" (click)="toggleFavouriteState(false)" *ngIf="discussion.canfavourite && discussion.starred" | ||||
|     detail="false"> | ||||
|     <ion-icon name="fa-star" slot="start" class="icon-slash" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <h2>{{ 'addon.mod_forum.removefromfavourites' | translate }}</h2> | ||||
|         <p class="item-heading">{{ 'addon.mod_forum.removefromfavourites' | translate }}</p> | ||||
|     </ion-label> | ||||
| </ion-item> | ||||
|  | ||||
| @ -23,7 +23,7 @@ | ||||
|             (action)="prefetch($event)"> | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item *ngIf="size" | ||||
|             iconDescription="cube" iconAction="trash" | ||||
|             iconDescription="fas-archive" iconAction="trash" | ||||
|             [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [closeOnClick]="false" | ||||
|             (action)="removeFiles($event)"> | ||||
|         </core-context-menu-item> | ||||
|  | ||||
| @ -1,26 +1,26 @@ | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
|     <ion-item class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || (canEdit && isOnline)"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="margin"> | ||||
|     <ion-item button class="ion-text-wrap" (click)="editPost()" *ngIf="offlinePost || (canEdit && isOnline)" detail="false"> | ||||
|         <ion-icon name="fas-pen" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <h2>{{ 'addon.mod_forum.edit' | translate }}</h2> | ||||
|             <p class="item-heading">{{ 'addon.mod_forum.edit' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || (canDelete && isOnline)"> | ||||
|     <ion-item button class="ion-text-wrap" (click)="deletePost()" *ngIf="offlinePost || (canDelete && isOnline)" detail="false"> | ||||
|         <ion-icon name="fas-trash" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <h2 *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</h2> | ||||
|             <h2 *ngIf="offlinePost">{{ 'core.discard' | translate }}</h2> | ||||
|             <p  class="item-heading" *ngIf="!offlinePost">{{ 'addon.mod_forum.delete' | translate }}</p> | ||||
|             <p  class="item-heading" *ngIf="offlinePost">{{ 'core.discard' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item class="ion-text-wrap" (click)="dismiss()" *ngIf="wordCount"> | ||||
|     <ion-item class="ion-text-wrap" *ngIf="wordCount"> | ||||
|         <ion-label> | ||||
|             <h2>{{ 'core.numwords' | translate: {'$a': wordCount} }}</h2> | ||||
|             <p  class="item-heading">{{ 'core.numwords' | translate: {'$a': wordCount} }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
|     <ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false"> | ||||
|     <ion-item class="ion-text-wrap" [href]="url" *ngIf="url" core-link capture="false" button detail="false"> | ||||
|         <ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon> | ||||
|         <ion-label> | ||||
|             <h2>{{ 'core.openinbrowser' | translate }}</h2> | ||||
|             <p  class="item-heading">{{ 'core.openinbrowser' | translate }}</p> | ||||
|         </ion-label> | ||||
|     </ion-item> | ||||
| </core-loading> | ||||
|  | ||||
| @ -58,13 +58,10 @@ | ||||
|             <ion-item class="ion-text-wrap" *ngIf="!entry.approved"> | ||||
|                 <ion-label><p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p></ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item *ngIf="glossary && glossary.allowcomments && entry && entry.id > 0 && commentsEnabled"> | ||||
|                 <ion-label> | ||||
|                     <core-comments contextLevel="module" [instanceId]="glossary.coursemodule" component="mod_glossary" | ||||
|                         [itemId]="entry.id" area="glossary_entry" [courseId]="glossary.course"> | ||||
|             <core-comments *ngIf="glossary && glossary.allowcomments && entry && entry.id > 0 && commentsEnabled" | ||||
|                 contextLevel="module" [instanceId]="glossary.coursemodule" component="mod_glossary" | ||||
|                 [itemId]="entry.id" area="glossary_entry" [courseId]="glossary.course" [showItem]="true"> | ||||
|             </core-comments> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <core-rating-rate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="glossary.course" | ||||
|                 [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale" [userId]="entry.userid" | ||||
|  | ||||
| @ -63,7 +63,7 @@ | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.mod_h5pactivity.outcome' | translate }}</h2> | ||||
|                             <p *ngIf="attempt.success !== null && attempt.success" > | ||||
|                                 <ion-icon name="fa-check-circle" aria-hidden="true"></ion-icon> | ||||
|                                 <ion-icon name="fas-check-circle" aria-hidden="true"></ion-icon> | ||||
|                                 {{ 'addon.mod_h5pactivity.attempt_success_pass' | translate }} | ||||
|                             </p> | ||||
|                             <p *ngIf="attempt.success !== null && !attempt.success" > | ||||
| @ -166,12 +166,12 @@ | ||||
| <!-- Template to render an answer. --> | ||||
| <ng-template #answerTemplate let-answer="answer"> | ||||
|     <p *ngIf="answer.correct"> | ||||
|         <ion-icon name="fa-check" [attr.aria-label]="'addon.mod_h5pactivity.answer_correct' | translate" color="success"> | ||||
|         <ion-icon name="fas-check" [attr.aria-label]="'addon.mod_h5pactivity.answer_correct' | translate" color="success"> | ||||
|         </ion-icon> | ||||
|         {{ answer.answer }} | ||||
|     </p> | ||||
|     <p *ngIf="answer.incorrect"> | ||||
|         <ion-icon name="fa-remove" [attr.aria-label]="'addon.mod_h5pactivity.answer_incorrect' | translate" color="danger"> | ||||
|         <ion-icon name="fas-times" [attr.aria-label]="'addon.mod_h5pactivity.answer_incorrect' | translate" color="danger"> | ||||
|         </ion-icon> | ||||
|         {{ answer.answer }} | ||||
|     </p> | ||||
| @ -179,15 +179,15 @@ | ||||
|         {{ answer.answer }} | ||||
|     </p> | ||||
|     <p *ngIf="answer.checked"> | ||||
|         <ion-icon name="fa-check-circle" [attr.aria-label]="'addon.mod_h5pactivity.answer_checked' | translate"> | ||||
|         <ion-icon name="fas-check-circle" [attr.aria-label]="'addon.mod_h5pactivity.answer_checked' | translate"> | ||||
|         </ion-icon> | ||||
|     </p> | ||||
|     <p *ngIf="answer.pass"> | ||||
|         <ion-icon name="fa-check" [attr.aria-label]="'addon.mod_h5pactivity.answer_pass' | translate" color="success"> | ||||
|         <ion-icon name="fas-check" [attr.aria-label]="'addon.mod_h5pactivity.answer_pass' | translate" color="success"> | ||||
|         </ion-icon> | ||||
|     </p> | ||||
|     <p *ngIf="answer.fail"> | ||||
|         <ion-icon name="fa-remove" [attr.aria-label]="'addon.mod_h5pactivity.answer_fail' | translate" color="danger"> | ||||
|         <ion-icon name="fas-times" [attr.aria-label]="'addon.mod_h5pactivity.answer_fail' | translate" color="danger"> | ||||
|         </ion-icon> | ||||
|     </p> | ||||
| </ng-template> | ||||
|  | ||||
| @ -99,7 +99,7 @@ | ||||
|                         [alt]="'addon.mod_h5pactivity.attempt_completion_no' | translate"> | ||||
|                 </ion-col> | ||||
|                 <ion-col class="ion-text-center addon-mod_h5pactivity-table-success-col"> | ||||
|                     <ion-icon *ngIf="attempt.success !== null && attempt.success" name="fa-check-circle" | ||||
|                     <ion-icon *ngIf="attempt.success !== null && attempt.success" name="fas-check-circle" | ||||
|                         [attr.aria-label]="'addon.mod_h5pactivity.attempt_success_pass' | translate"> | ||||
|                     </ion-icon> | ||||
|                     <ion-icon *ngIf="attempt.success !== null && !attempt.success" name="far-circle" | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| <!-- Buttons to add to the header. --> | ||||
| <core-navbar-buttons slot="end"> | ||||
|     <ion-button (click)="showToc()" aria-haspopup="true" [attr.aria-label]="'addon.mod_imscp.toc' | translate"> | ||||
|     <ion-button *ngIf="loaded" (click)="showToc()" aria-haspopup="true" [attr.aria-label]="'addon.mod_imscp.toc' | translate"> | ||||
|         <ion-icon name="fas-bookmark" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|     </ion-button> | ||||
|     <core-context-menu> | ||||
|  | ||||
| @ -12,9 +12,12 @@ | ||||
|     <nav> | ||||
|         <ion-list> | ||||
|             <ion-item *ngFor="let item of items" (click)="loadItem(item.href)" | ||||
|                 [attr.aria-current]="selected == item.href ? 'page' : 'false'" button> | ||||
|                 [attr.aria-current]="selected == item.href ? 'page' : 'false'" button detail="false"> | ||||
|                 <ion-label [class.core-bold]="!item.href"> | ||||
|                     <span class="ion-padding-left" *ngFor="let i of getNumberForPadding(item.level)"></span>{{item.title}} | ||||
|                     <p class="item-heading"> | ||||
|                         <span class="ion-padding-left" *ngFor="let i of getNumberForPadding(item.level)"></span> | ||||
|                         {{item.title}} | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-list> | ||||
|  | ||||
| @ -296,7 +296,7 @@ | ||||
|                         </ion-card-header> | ||||
| 
 | ||||
|                         <ion-item class="ion-text-wrap" *ngFor="let student of overview.students" button | ||||
|                             (click)="openRetake(student.id)"> | ||||
|                             (click)="openRetake(student.id)" detail="true"> | ||||
|                             <core-user-avatar [user]="student" slot="start" [userId]="student.id" [courseId]="courseId"> | ||||
|                             </core-user-avatar> | ||||
|                             <ion-label> | ||||
|  | ||||
| @ -27,7 +27,7 @@ | ||||
| 
 | ||||
|             <ion-item button class="ion-text-wrap {{question.stateClass}}" *ngFor="let question of navigation" | ||||
|                 [attr.aria-current]="!summaryShown && currentPage == question.page ? 'page' : 'false'" | ||||
|                 (click)="loadPage(question.page, question.slot)" detail="true"> | ||||
|                 (click)="loadPage(question.page, question.slot)" detail="false"> | ||||
| 
 | ||||
|                 <ion-label> | ||||
|                     <span *ngIf="question.number">{{ 'core.question.questionno' | translate:{$a: question.number} }}</span> | ||||
|  | ||||
| @ -158,11 +158,11 @@ | ||||
|                                 <ion-icon *ngIf="sco.icon" [name]="sco.icon.icon" [attr.aria-label]="sco.icon.description" | ||||
|                                     slot="start"> | ||||
|                                 </ion-icon> | ||||
|                                 <a *ngIf="sco.prereq && sco.launch" (click)="open($event, false, sco.id)" tappable="true"> | ||||
|                                 <button class="as-link" *ngIf="sco.prereq && sco.launch" (click)="open($event, false, sco.id)"> | ||||
|                                     <core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" | ||||
|                                         [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </a> | ||||
|                                 </button> | ||||
|                                 <span *ngIf="!sco.prereq || !sco.launch"> | ||||
|                                     <core-format-text [text]="sco.title" contextLevel="module" [contextInstanceId]="module.id" | ||||
|                                         [courseId]="courseId"> | ||||
|  | ||||
| @ -12,7 +12,7 @@ | ||||
|     <nav> | ||||
|         <ion-list> | ||||
|             <!-- Go to "home". --> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="homeView" (click)="goToWikiHome()" button> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="homeView" (click)="goToWikiHome()" button detail="true"> | ||||
|                 <ion-icon name="fas-home" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'addon.mod_wiki.gowikihome' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
| @ -21,7 +21,7 @@ | ||||
|                     <ion-label><h2>{{ letter.label }}</h2></ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let page of letter.pages" (click)="goToPage(page)" | ||||
|                     [attr.aria-current]="selectedTitle == page.title ? 'page' : 'false'" button> | ||||
|                     [attr.aria-current]="selectedTitle == page.title ? 'page' : 'false'" button detail="false"> | ||||
|                     <ion-icon name="fas-home" slot="start" *ngIf="page.firstpage" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [text]="page.title" contextLevel="module" [contextInstanceId]="moduleId" | ||||
|  | ||||
| @ -21,7 +21,7 @@ import { HttpClient, HttpClientModule } from '@angular/common/http'; | ||||
| import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; | ||||
| import { TranslateHttpLoader } from '@ngx-translate/http-loader'; | ||||
| 
 | ||||
| import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; | ||||
| import { IonicModule, IonicRouteStrategy, iosTransitionAnimation } from '@ionic/angular'; | ||||
| 
 | ||||
| import { CoreModule } from '@/core/core.module'; | ||||
| import { AddonsModule } from '@/addons/addons.module'; | ||||
| @ -42,7 +42,11 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader { | ||||
|     imports: [ | ||||
|         BrowserModule, | ||||
|         BrowserAnimationsModule, | ||||
|         IonicModule.forRoot(), | ||||
|         IonicModule.forRoot( | ||||
|             { | ||||
|                 navAnimation: iosTransitionAnimation, | ||||
|             }, | ||||
|         ), | ||||
|         HttpClientModule, // HttpClient is used to make JSON requests. It fails for HEAD requests because there is no content.
 | ||||
|         TranslateModule.forRoot({ | ||||
|             loader: { | ||||
|  | ||||
							
								
								
									
										58
									
								
								src/core/classes/modal-lateral-transition.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/core/classes/modal-lateral-transition.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,58 @@ | ||||
| // (C) Copyright 2015 Moodle Pty Ltd.
 | ||||
| //
 | ||||
| // Licensed under the Apache License, Version 2.0 (the "License");
 | ||||
| // you may not use this file except in compliance with the License.
 | ||||
| // You may obtain a copy of the License at
 | ||||
| //
 | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| //
 | ||||
| // Unless required by applicable law or agreed to in writing, software
 | ||||
| // distributed under the License is distributed on an "AS IS" BASIS,
 | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { createAnimation } from '@ionic/angular'; | ||||
| import { Animation } from '@ionic/core'; | ||||
| import { Platform } from '@singletons'; | ||||
| 
 | ||||
| /** | ||||
|  * Sliding transition for lateral modals. | ||||
|  */ | ||||
| export function CoreModalLateralTransitionEnter(baseEl: HTMLElement): Animation { | ||||
|     const OFF_RIGHT = Platform.isRTL ? '-100%' : '100%'; | ||||
| 
 | ||||
|     const backdropAnimation = createAnimation() | ||||
|         .addElement(baseEl.querySelector('ion-backdrop')!) | ||||
|         .fromTo('opacity', 0.01, 0.4); | ||||
| 
 | ||||
|     const wrapperAnimation = createAnimation() | ||||
|         .addElement(baseEl.querySelector('.modal-wrapper')!) | ||||
|         .fromTo('transform', 'translateX(' + OFF_RIGHT + ')', 'translateX(0)') | ||||
|         .fromTo('opacity', 0.8, 1); | ||||
| 
 | ||||
|     return createAnimation() | ||||
|         .addElement(baseEl) | ||||
|         .easing('cubic-bezier(0.36,0.66,0.04,1)') | ||||
|         .duration(300) | ||||
|         .addAnimation([backdropAnimation, wrapperAnimation]); | ||||
| } | ||||
| 
 | ||||
| export function CoreModalLateralTransitionLeave(baseEl: HTMLElement): Animation { | ||||
|     const OFF_RIGHT = Platform.isRTL ? '-100%' : '100%'; | ||||
| 
 | ||||
|     const backdropAnimation = createAnimation() | ||||
|         .addElement(baseEl.querySelector('ion-backdrop')!) | ||||
|         .fromTo('opacity', 0.4, 0.0); | ||||
| 
 | ||||
|     const wrapperAnimation = createAnimation() | ||||
|         .addElement(baseEl.querySelector('.modal-wrapper')!) | ||||
|         .beforeStyles({ opacity: 1 }) | ||||
|         .fromTo('transform', 'translateX(0)', 'translateX(' + OFF_RIGHT + ')'); | ||||
| 
 | ||||
|     return createAnimation() | ||||
|         .addElement(baseEl) | ||||
|         .easing('cubic-bezier(0.36,0.66,0.04,1)') | ||||
|         .duration(300) | ||||
|         .addAnimation([backdropAnimation, wrapperAnimation]); | ||||
| } | ||||
| @ -84,6 +84,7 @@ ion-button { | ||||
|         text-transform: none; | ||||
|         font-weight: 400; | ||||
|         font-size: 16px; | ||||
|         line-height: 20px; | ||||
|     } | ||||
| 
 | ||||
|     .select-text { | ||||
|  | ||||
| @ -1,5 +1,11 @@ | ||||
| :host { | ||||
|     ion-list { | ||||
| @import "~theme/globals"; | ||||
| 
 | ||||
| ion-list { | ||||
|     padding: 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ion-icon[slot=start] { | ||||
|     @include margin-horizontal(0, 10px); | ||||
|     width: 0.8em; | ||||
|     height: 0.8em; | ||||
| } | ||||
|  | ||||
| @ -7,7 +7,9 @@ | ||||
|         [detail]="(item.href && !item.iconAction) || null" role="menuitem" [button]="(item.href && !item.iconAction)"> | ||||
|         <ion-icon *ngIf="item.iconDescription" [name]="item.iconDescription" [attr.aria-label]="item.ariaDescription" slot="start"> | ||||
|         </ion-icon> | ||||
|         <ion-label><core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text></ion-label> | ||||
|         <ion-label> | ||||
|             <p class="item-heading"><core-format-text [clean]="true" [text]="item.content" [filter]="false"></core-format-text></p> | ||||
|         </ion-label> | ||||
|         <ion-icon *ngIf="(item.href || item.action) && item.iconAction && item.iconAction != 'spinner'" [name]="item.iconAction" | ||||
|             [class.icon-slash]="item.iconSlash" slot="end"> | ||||
|         </ion-icon> | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| <div class="core-loading-container" *ngIf="!hideUntil" role="status" [@coreShowHideAnimation]> | ||||
|     <span class="core-loading-spinner"> | ||||
|     <ion-spinner color="primary"></ion-spinner> | ||||
|     <p class="core-loading-message" *ngIf="message" role="status">{{message}}</p> | ||||
|     </span> | ||||
| </div> | ||||
| <div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="hideUntil" [@coreShowHideAnimation]> | ||||
|     <ng-content *ngIf="hideUntil"> | ||||
|  | ||||
| @ -4,35 +4,44 @@ | ||||
|     --loading-background: var(--ion-background-color); | ||||
|     --loading-spinner: var(--ion-color-primary); | ||||
|     --loading-text-color: var(--ion-text-color); | ||||
|     --loading-inline-margin: 0; | ||||
|     --loading-inline-min-height: 28px; | ||||
| 
 | ||||
|     position: static; | ||||
|     color: var(--loading-text-color); | ||||
| 
 | ||||
|     &.margin { | ||||
|         --loading-inline-margin: 10px; | ||||
|     } | ||||
| 
 | ||||
|     &.core-loading-loaded { | ||||
|         --loading-inline-margin: 0; | ||||
|         --loading-inline-min-height: 0; | ||||
|     } | ||||
| 
 | ||||
|     ion-spinner { | ||||
|         --color: var(--loading-spinner); | ||||
|         color: var(--color); | ||||
|     } | ||||
| 
 | ||||
|     > .core-loading-container { | ||||
|     .core-loading-container { | ||||
|         position: absolute; | ||||
|         @include position(0, 0, 0, 0); | ||||
|         display: table; | ||||
|         display: flex; | ||||
|         height: 100%; | ||||
|         width: 100%; | ||||
|         text-align: center; | ||||
|         clear: both; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|         flex-direction: column; | ||||
|         z-index: 3; | ||||
|         margin: 0; | ||||
|         padding: 10px 0 0 0; | ||||
|         padding: 0; | ||||
|         background-color: var(--loading-background); | ||||
|         -webkit-transition: all 200ms ease-in-out; | ||||
|         transition: all 200ms ease-in-out; | ||||
| 
 | ||||
|         .core-loading-spinner { | ||||
|             display: table-cell; | ||||
|             text-align: center; | ||||
|             vertical-align: middle; | ||||
|         @include core-transition(all, 200ms); | ||||
|     } | ||||
| 
 | ||||
|     .core-loading-message { | ||||
|         @include margin(10px, 0, 0, 0); | ||||
|     } | ||||
| 
 | ||||
|     .core-loading-content { | ||||
| @ -48,21 +57,26 @@ | ||||
|     } | ||||
| 
 | ||||
|     &.core-loading-inline { | ||||
|         --loading-background: transparent; | ||||
|         position: relative; | ||||
|         display: block; | ||||
|         min-height: var(--loading-inline-min-height); | ||||
|         margin-top: var(--loading-inline-margin); | ||||
|         margin-bottom: var(--loading-inline-margin); | ||||
| 
 | ||||
|         .core-loading-container { | ||||
|             padding-top: 20px; | ||||
|             position: relative; | ||||
|         } | ||||
|         .core-loading-message { | ||||
|             @include margin(0, 0, 0, 10px); | ||||
|         } | ||||
| 
 | ||||
|     &.core-loading-loaded.core-loading-inline { | ||||
|         position: relative; | ||||
|         min-height: 102px; | ||||
| 
 | ||||
|         .core-loading-container { | ||||
|             padding-top: 10px; | ||||
|             position: absolute; | ||||
|             flex-direction: row; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| :host-context(ion-item) { | ||||
|     &.core-loading-inline { | ||||
|         position: static; | ||||
|         display: block; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
|     <ion-tab-bar slot="top" class="core-tabs-bar" [hidden]="!tabs || numTabsShown <= 1" #tabBar> | ||||
|         <ion-spinner *ngIf="!hideUntil"></ion-spinner> | ||||
|         <ion-row *ngIf="hideUntil"> | ||||
|             <ion-col class="col-with-arrow ion-no-padding" (click)="slidePrev()" size="1"> | ||||
|             <ion-col class="col-with-arrow ion-no-padding" (click)="slidePrev()" size="1" [class.clickable]="showPrevButton"> | ||||
|                 <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> | ||||
|             </ion-col> | ||||
|             <ion-col class="ion-no-padding" size="10"> | ||||
| @ -41,7 +41,7 @@ | ||||
|                     </ng-container> | ||||
|                 </ion-slides> | ||||
|             </ion-col> | ||||
|             <ion-col class="col-with-arrow ion-no-padding" (click)="slideNext()" size="1"> | ||||
|             <ion-col class="col-with-arrow ion-no-padding" (click)="slideNext()" size="1" [class.clickable]="showNextButton"> | ||||
|                 <ion-icon *ngIf="showNextButton" name="fas-chevron-right" [attr.aria-label]="'core.next' | translate"></ion-icon> | ||||
|             </ion-col> | ||||
|         </ion-row> | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <ion-tab-bar slot="top" class="core-tabs-bar" [hidden]="!tabs || numTabsShown <= 1" #tabBar> | ||||
|     <ion-spinner *ngIf="!hideUntil"></ion-spinner> | ||||
|     <ion-row *ngIf="hideUntil"> | ||||
|         <ion-col class="col-with-arrow ion-no-padding" (click)="slidePrev()" size="1"> | ||||
|         <ion-col class="col-with-arrow ion-no-padding" (click)="slidePrev()" size="1" [class.clickable]="showPrevButton"> | ||||
|             <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> | ||||
|         </ion-col> | ||||
|         <ion-col class="ion-no-padding" size="10"> | ||||
| @ -39,7 +39,7 @@ | ||||
|                 </ng-container> | ||||
|             </ion-slides> | ||||
|         </ion-col> | ||||
|         <ion-col class="col-with-arrow ion-no-padding" (click)="slideNext()" size="1"> | ||||
|         <ion-col class="col-with-arrow ion-no-padding" (click)="slideNext()" size="1" [class.clickable]="showNextButton"> | ||||
|             <ion-icon *ngIf="showNextButton" name="fas-chevron-right" [attr.aria-label]="'core.next' | translate"></ion-icon> | ||||
|         </ion-col> | ||||
|     </ion-row> | ||||
|  | ||||
| @ -80,6 +80,7 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|     @Input() maxHeight?: number; | ||||
| 
 | ||||
|     @Output() afterRender: EventEmitter<void>; // Called when the data is rendered.
 | ||||
|     @Output() onClick: EventEmitter<void> = new EventEmitter(); // Called when clicked.
 | ||||
| 
 | ||||
|     protected element: HTMLElement; | ||||
|     protected showMoreDisplayed = false; | ||||
| @ -286,6 +287,13 @@ export class CoreFormatTextDirective implements OnChanges { | ||||
|             // Ignore it if the event was prevented by some other listener.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (this.onClick.observers.length > 0) { | ||||
|             this.onClick.emit(); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (!this.text) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
| @ -57,7 +57,36 @@ export class CoreLinkDirective implements OnInit { | ||||
|     ngOnInit(): void { | ||||
|         this.inApp = typeof this.inApp == 'undefined' ? this.inApp : CoreUtils.isTrueOrOne(this.inApp); | ||||
| 
 | ||||
|         if (this.element.tagName != 'BUTTON' && this.element.tagName != 'A') { | ||||
|             this.element.setAttribute('tabindex', '0'); | ||||
|             this.element.setAttribute('role', 'button'); | ||||
|         } | ||||
| 
 | ||||
|         this.element.addEventListener('click', async (event) => { | ||||
|             this.performAction(event); | ||||
|         }); | ||||
| 
 | ||||
|         this.element.addEventListener('keydown', (event: KeyboardEvent) => { | ||||
|             if ((event.key == ' ' || event.key == 'Enter')) { | ||||
|                 event.preventDefault(); | ||||
|                 event.stopPropagation(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         this.element.addEventListener('keyup', (event: KeyboardEvent) => { | ||||
|             if ((event.key == ' ' || event.key == 'Enter')) { | ||||
|                 this.performAction(event); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Perform "click" action. | ||||
|      * | ||||
|      * @param event Event. | ||||
|      * @returns Resolved when done. | ||||
|      */ | ||||
|     protected async performAction(event: Event): Promise<void> { | ||||
|         if (event.defaultPrevented) { | ||||
|             return; // Link already treated, stop.
 | ||||
|         } | ||||
| @ -84,7 +113,6 @@ export class CoreLinkDirective implements OnInit { | ||||
|         } else { | ||||
|             this.navigate(href, openIn); | ||||
|         } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| </div> | ||||
| 
 | ||||
| <div *ngIf="blocks && blocks.length > 0 && !hideBlocks" [class.core-hide-blocks]="hideBottomBlocks" class="core-course-blocks-side"> | ||||
|     <core-loading [hideUntil]="dataLoaded" [fullscreen]="false"> | ||||
|     <core-loading [hideUntil]="dataLoaded" [fullscreen]="false" class="margin"> | ||||
|         <ion-list> | ||||
|             <!-- Course expand="block"s. --> | ||||
|             <ng-container *ngFor="let block of blocks"> | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|         </h2> | ||||
|     </ion-label> | ||||
| </ion-item-divider> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false"> | ||||
| <core-loading [hideUntil]="loaded" [fullscreen]="false" class="margin"> | ||||
|     <ion-item *ngIf="block.contents?.content" class="ion-text-wrap core-block-content"> | ||||
|         <ion-label> | ||||
|             <core-format-text [text]="block.contents?.content" contextLevel="block" [contextInstanceId]="block.instanceid" | ||||
|  | ||||
| @ -1,4 +0,0 @@ | ||||
| .core-comments-clickable { | ||||
|     pointer-events: auto; | ||||
|     cursor: pointer; | ||||
| } | ||||
| @ -29,7 +29,6 @@ import { ContextLevel } from '@/core/constants'; | ||||
| @Component({ | ||||
|     selector: 'core-comments', | ||||
|     templateUrl: 'core-comments.html', | ||||
|     styleUrls: ['comments.scss'], | ||||
| }) | ||||
| export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestroy { | ||||
| 
 | ||||
| @ -39,9 +38,9 @@ export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestr | ||||
|     @Input() itemId!: number; | ||||
|     @Input() area = ''; | ||||
|     @Input() title?: string; | ||||
|     @Input() displaySpinner = true; // Whether to display the loading spinner.
 | ||||
|     @Output() onLoading: EventEmitter<boolean>; // Eevent that indicates whether the component is loading data.
 | ||||
|     @Output() onLoading: EventEmitter<boolean>; // Event that indicates whether the component is loading data.
 | ||||
|     @Input() courseId?: number; // Course ID the comments belong to. It can be used to improve performance with filters.
 | ||||
|     @Input() showItem = false; // Show button as an item.
 | ||||
| 
 | ||||
|     commentsLoaded = false; | ||||
|     commentsCount = ''; | ||||
|  | ||||
| @ -1,8 +1,27 @@ | ||||
| <core-loading *ngIf="!disabled" [hideUntil]="commentsLoaded || !displaySpinner"> | ||||
|     <div *ngIf="!countError" (click)="openComments($event)" [class.core-comments-clickable]="!disabled"> | ||||
| <ng-container *ngIf="!disabled"> | ||||
|     <core-loading *ngIf="!showItem" [hideUntil]="commentsLoaded" [fullscreen]="false" class="margin"> | ||||
|         <button *ngIf="!countError" (click)="openComments($event)" class="as-link"> | ||||
|             {{ 'core.comments.commentscount' | translate : {'$a': commentsCount} }} | ||||
|     </div> | ||||
|         </button> | ||||
|         <div *ngIf="countError"> | ||||
|             {{ 'core.comments.commentsnotworking' | translate }} | ||||
|         </div> | ||||
| </core-loading> | ||||
|     </core-loading> | ||||
|     <ion-item | ||||
|         *ngIf="showItem" | ||||
|         button | ||||
|         [detail]="!countError && commentsLoaded" | ||||
|         (click)="openComments($event)" | ||||
|         [disabled]="countError"> | ||||
|         <core-loading [hideUntil]="commentsLoaded" [fullscreen]="false"> | ||||
|             <ion-label> | ||||
|                 <p *ngIf="!countError" class="item-heading"> | ||||
|                     {{ 'core.comments.commentscount' | translate : {'$a': commentsCount} }} | ||||
|                 </p> | ||||
|                 <p *ngIf="countError"> | ||||
|                     {{ 'core.comments.commentsnotworking' | translate }} | ||||
|                 </p> | ||||
|             </ion-label> | ||||
|         </core-loading> | ||||
|     </ion-item> | ||||
| </ng-container> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <ion-item class="ion-text-wrap" *ngFor="let item of items" (click)="openCourse(item.courseId)" [attr.aria-label]="item.courseName" | ||||
|     button> | ||||
|     button detail="true"> | ||||
|     <ion-icon name="fas-graduation-cap" slot="start" aria-hidden="true"></ion-icon> | ||||
|     <ion-label> | ||||
|         <p class="item-heading">{{ item.courseName }}</p> | ||||
|  | ||||
| @ -114,11 +114,12 @@ | ||||
|                 <ion-spinner *ngIf="prefetchCourseData.loading" slot="start"></ion-spinner> | ||||
|                 <ion-label><h2>{{ 'core.course.downloadcourse' | translate }}</h2></ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item button (click)="openCourse()" [attr.aria-label]="course.fullname" *ngIf="!avoidOpenCourse && canAccessCourse"> | ||||
|             <ion-item button (click)="openCourse()" [attr.aria-label]="course.fullname" *ngIf="!avoidOpenCourse && canAccessCourse" | ||||
|                 detail="true"> | ||||
|                 <ion-icon name="fas-briefcase" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label><h2>{{ 'core.course.contents' | translate }}</h2></ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item [href]="courseUrl" core-link [attr.aria-label]="course.fullname"> | ||||
|             <ion-item [href]="courseUrl" core-link [attr.aria-label]="course.fullname" button detail="false"> | ||||
|                 <ion-icon name="fas-external-link-alt" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label><h2>{{ 'core.openinbrowser' | translate }}</h2></ion-label> | ||||
|             </ion-item> | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <ion-item class="ion-text-wrap" (click)="openCourse()" [class.item-disabled]="course.visible == 0" | ||||
| [attr.aria-label]="course.displayname || course.fullname" detail="true" button> | ||||
|     [attr.aria-label]="course.displayname || course.fullname" detail="true" button> | ||||
|     <ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" slot="start" class="course-icon" | ||||
|         [attr.course-color]="course.color ? null : course.colorNumber" [style.color]="course.color"></ion-icon> | ||||
|     <ion-avatar *ngIf="course.courseImage" slot="start"> | ||||
|  | ||||
| @ -32,7 +32,9 @@ | ||||
|                     <tbody> | ||||
|                         <tr | ||||
|                             *ngFor="let row of grades.rows" | ||||
|                             (click)="row.itemtype != 'category' && grades.select(row)" | ||||
|                             role="button row" | ||||
|                             [attr.tabindex]="row.itemtype != 'category' ? 0 : null" | ||||
|                             (ariaButtonClick)="row.itemtype != 'category' && grades.select(row)" | ||||
|                             [class]="row.rowclass" | ||||
|                             [ngClass]='{"core-grades-grade-clickable": row.itemtype != "category"}' | ||||
|                         > | ||||
|  | ||||
| @ -4,13 +4,28 @@ | ||||
|     --header-background: var(--white); | ||||
|     --odd-cell-background: var(--gray-lighter); | ||||
|     --even-cell-background: var(--white); | ||||
|     --odd-cell-hover: var(--gray-light); | ||||
|     --even-cell-hover: var(--gray-lighter); | ||||
|     --icon-color: #999999; | ||||
| 
 | ||||
|     .odd { | ||||
|         --cell-background: var(--odd-cell-background); | ||||
|         --cell-hover: var(--odd-cell-hover); | ||||
|     } | ||||
| 
 | ||||
|     .even { | ||||
|         --cell-background: var(--even-cell-background); | ||||
|         --cell-hover: var(--even-cell-hover); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| :host-context(body.dark) { | ||||
|     --header-background: var(--black); | ||||
|     --odd-cell-background: var(--gray-darker); | ||||
|     --even-cell-background: var(--black); | ||||
|     --odd-cell-hover: var(--gray-dark); | ||||
|     --even-cell-hover: var(--gray-darker); | ||||
|     --icon-color: #eeeeee; | ||||
| } | ||||
| 
 | ||||
| @ -91,21 +106,19 @@ | ||||
|         opacity: .7; | ||||
|     } | ||||
| 
 | ||||
|     .odd { | ||||
|     .odd, .even { | ||||
|         td, th, th[aria-current="page"] { | ||||
|             background-color: var(--odd-cell-background); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     .even { | ||||
|         td, th, th[aria-current="page"] { | ||||
|             background-color: var(--even-cell-background); | ||||
|             background-color: var(--cell-background); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     .core-grades-grade-clickable { | ||||
|         cursor: pointer; | ||||
|         &:hover { | ||||
|             td, th, th[aria-current="page"] { | ||||
|                 background-color: var(--cell-hover); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -78,7 +78,7 @@ | ||||
|                 <ion-label><h3 class="item-heading">{{ 'core.login.potentialidps' | translate }}</h3></ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item button *ngFor="let provider of identityProviders" class="ion-text-wrap core-oauth-icon" | ||||
|                 (click)="oauthClicked(provider)" [attr.aria-label]="provider.name"> | ||||
|                 (click)="oauthClicked(provider)" [attr.aria-label]="provider.name" detail="false"> | ||||
|                 <img [src]="provider.iconurl" alt="" width="32" height="32" slot="start"> | ||||
|                 <ion-label>{{provider.name}}</ion-label> | ||||
|             </ion-item> | ||||
|  | ||||
| @ -88,7 +88,7 @@ | ||||
|             <ion-label><h3 class="item-heading">{{ 'core.login.potentialidps' | translate }}</h3></ion-label> | ||||
|         </ion-item> | ||||
|         <ion-item button *ngFor="let provider of identityProviders" class="ion-text-wrap core-oauth-icon" | ||||
|             (click)="oauthClicked(provider)"> | ||||
|             (click)="oauthClicked(provider)" detail="false"> | ||||
|             <img [src]="provider.iconurl" alt="" role="presentation" width="32" height="32" slot="start"> | ||||
|             <ion-label>{{provider.name}}</ion-label> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -19,7 +19,7 @@ | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <ion-list> | ||||
|         <ion-item button (click)="login(site.id)" *ngFor="let site of sites"> | ||||
|         <ion-item button (click)="login(site.id)" *ngFor="let site of sites" detail="true"> | ||||
|             <ion-avatar slot="start"> | ||||
|                 <img [src]="site.avatar" core-external-content [siteId]="site.id" | ||||
|                     alt="{{ 'core.pictureof' | translate:{$a: site.fullName} }}" onError="this.src='assets/img/user-avatar.png'"> | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-loading [hideUntil]="!loggedOut"> | ||||
|         <ion-list> | ||||
|             <ion-item button *ngIf="siteInfo" class="ion-text-wrap" core-user-link [userId]="siteInfo.userid"> | ||||
|                 <core-user-avatar [user]="siteInfo" slot="start"></core-user-avatar> | ||||
| @ -25,7 +26,7 @@ | ||||
|                 <ion-label><ion-spinner></ion-spinner></ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item button *ngFor="let handler of handlers" [ngClass]="['core-moremenu-handler', handler.class || '']" | ||||
|             (click)="openHandler(handler)" [attr.aria-label]="handler.title | translate" detail="true" detail="true"> | ||||
|                 (click)="openHandler(handler)" [attr.aria-label]="handler.title | translate" detail="true"> | ||||
|                 <ion-icon [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ handler.title | translate}}</p> | ||||
| @ -94,4 +95,5 @@ | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-list> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -50,6 +50,7 @@ export class CoreMainMenuMorePage implements OnInit, OnDestroy { | ||||
|     docsUrl?: string; | ||||
|     customItems?: CoreMainMenuCustomItem[]; | ||||
|     siteUrl?: string; | ||||
|     loggedOut = false; | ||||
| 
 | ||||
|     protected subscription!: Subscription; | ||||
|     protected langObserver: CoreEventObserver; | ||||
| @ -203,6 +204,7 @@ export class CoreMainMenuMorePage implements OnInit, OnDestroy { | ||||
|      * Logout the user. | ||||
|      */ | ||||
|     logout(): void { | ||||
|         this.loggedOut = true; | ||||
|         CoreSites.logout(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -17,7 +17,7 @@ | ||||
|             <ion-list> | ||||
|                 <ion-item *ngIf="siteInfo" class="ion-text-wrap"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{siteInfo!.fullname}}</h2> | ||||
|                         <p class="item-heading">{{siteInfo!.fullname}}</p> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="siteName" contextLevel="system" [contextInstanceId]="0" | ||||
|                                 [wsNotFiltered]="true"></core-format-text> | ||||
| @ -33,19 +33,19 @@ | ||||
|                     <ion-icon [name]="handler.icon" slot="start" *ngIf="handler.icon" aria-hidden="true"> | ||||
|                     </ion-icon> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ handler.title | translate}}</h2> | ||||
|                         <p class="item-heading">{{ handler.title | translate}}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| 
 | ||||
|                 <ion-card> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="spaceUsage"> | ||||
|                         <ion-label> | ||||
|                             <h2 class="ion-text-wrap">{{ 'core.settings.spaceusage' | translate }} <ion-icon | ||||
|                                     name="fas-info-circle" color="info" [attr.aria-label]="'core.info' | translate" | ||||
|                                     (click)="showSpaceInfo()"></ion-icon> | ||||
|                             </h2> | ||||
|                             <p class="item-heading ion-text-wrap">{{ 'core.settings.spaceusage' | translate }}</p> | ||||
|                             <p *ngIf="spaceUsage.spaceUsage">{{ spaceUsage.spaceUsage | coreBytesToSize }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-button fill="clear" [attr.aria-label]="'core.info' | translate" (click)="showSpaceInfo()" slot="end"> | ||||
|                             <ion-icon name="fas-info-circle" color="info" slot="icon-only"></ion-icon> | ||||
|                         </ion-button> | ||||
|                         <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage()" | ||||
|                             [hidden]="spaceUsage.spaceUsage! + spaceUsage.cacheEntries! <= 0" | ||||
|                             [attr.aria-label]="'core.settings.deletesitefilestitle' | translate"> | ||||
| @ -54,13 +54,13 @@ | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'core.settings.synchronizenow' | translate }} <ion-icon name="fas-info-circle" | ||||
|                                     color="info" [attr.aria-label]="'core.info' | translate" (click)="showSyncInfo()"> | ||||
|                                 </ion-icon> | ||||
|                             </h2> | ||||
|                             <p class="item-heading">{{ 'core.settings.synchronizenow' | translate }}</p> | ||||
|                         </ion-label> | ||||
|                         <ion-button fill="clear" [attr.aria-label]="'core.info' | translate" (click)="showSyncInfo()" slot="end"> | ||||
|                             <ion-icon name="fas-info-circle" color="info" slot="icon-only"></ion-icon> | ||||
|                         </ion-button> | ||||
|                         <ion-button fill="clear" slot="end" *ngIf="!isSynchronizing()" (click)="synchronize()" | ||||
|                             [title]="siteName" [attr.aria-label]="'core.settings.synchronizenow' | translate"> | ||||
|                             [attr.aria-label]="'core.settings.synchronizenow' | translate"> | ||||
|                             <ion-icon name="fas-sync-alt" slot="icon-only" aria-hidden="true"></ion-icon> | ||||
|                         </ion-button> | ||||
|                         <ion-spinner slot="end" *ngIf="isSynchronizing()"></ion-spinner> | ||||
|  | ||||
| @ -13,7 +13,7 @@ | ||||
|                 (onClick)="filePicked(file)" (onDelete)="fileDeleted(idx)" (onRename)="fileRenamed(idx, $event)"> | ||||
|             </core-local-file> | ||||
| 
 | ||||
|             <ion-item button *ngIf="!file.isFile" class="ion-text-wrap item-file" (click)="openFolder(file)"> | ||||
|             <ion-item button *ngIf="!file.isFile" class="ion-text-wrap item-file" (click)="openFolder(file)" detail="true"> | ||||
|                 <ion-thumbnail slot="start" aria-hidden="true"> | ||||
|                     <img src="assets/img/files/folder-64.png" alt=""> | ||||
|                 </ion-thumbnail> | ||||
|  | ||||
| @ -20,7 +20,7 @@ | ||||
|         </core-context-menu-item> | ||||
|         <core-context-menu-item [hidden]="!displaySize || !size || ( | ||||
|             content?.compileComponent?.componentInstance?.displaySize === false)" [priority]="500" | ||||
|             [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles()" | ||||
|             [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'fas-archive'" (action)="removeFiles()" | ||||
|             iconAction="fas-trash" [closeOnClick]="false"> | ||||
|         </core-context-menu-item> | ||||
|     </core-context-menu> | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| <core-loading [hideUntil]="dataLoaded" [fullscreen]="false"> | ||||
| <core-loading [hideUntil]="dataLoaded" [fullscreen]="false" class="margin"> | ||||
|     <core-compile-html [text]="content" [javascript]="javascript" [jsData]="jsData" [forceCompile]="forceCompile" #compile> | ||||
|     </core-compile-html> | ||||
| </core-loading> | ||||
|  | ||||
| @ -19,7 +19,8 @@ | ||||
|                     <ion-label class="ion-text-wrap">{{ 'core.tag.warningareasnotsupported' | translate }}</ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let area of areas" [attr.aria-label]="area.nameKey | translate" | ||||
|                     (click)="openArea(area)" [attr.aria-current]="area!.id == selectedAreaId ? 'page' : 'false'" button> | ||||
|                     (click)="openArea(area)" [attr.aria-current]="area!.id == selectedAreaId ? 'page' : 'false'" button | ||||
|                     detail="true"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ area!.nameKey | translate }}</h2> | ||||
|                     </ion-label> | ||||
|  | ||||
| @ -29,7 +29,7 @@ | ||||
|             <ion-list *ngIf="!participants.empty"> | ||||
|                 <ion-item *ngFor="let participant of participants.items" | ||||
|                     class="ion-text-wrap" [attr.aria-current]="participants.getItemAriaCurrent(participant)" | ||||
|                     [attr.aria-label]="participant.fullname" (click)="participants.select(participant)" button> | ||||
|                     [attr.aria-label]="participant.fullname" (click)="participants.select(participant)" button detail="true"> | ||||
| 
 | ||||
|                     <core-user-avatar [user]="participant" [linkProfile]="false" [checkOnline]="true" slot="start"> | ||||
|                     </core-user-avatar> | ||||
|  | ||||
| @ -37,6 +37,7 @@ import { CoreNetworkError } from '@classes/errors/network-error'; | ||||
| import { CoreBSTooltipComponent } from '@components/bs-tooltip/bs-tooltip'; | ||||
| import { CoreViewerImageComponent } from '@features/viewer/components/image/image'; | ||||
| import { CoreFormFields, CoreForms } from '../../singletons/form'; | ||||
| import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition'; | ||||
| 
 | ||||
| /* | ||||
|  * "Utils" service with helper functions for UI, DOM elements and HTML code. | ||||
| @ -1721,8 +1722,8 @@ export class CoreDomUtilsProvider { | ||||
|             cssClass: 'core-modal-lateral', | ||||
|             showBackdrop: true, | ||||
|             backdropDismiss: true, | ||||
|             // @todo enterAnimation: 'core-modal-lateral-transition',
 | ||||
|             // @todo leaveAnimation: 'core-modal-lateral-transition',
 | ||||
|             enterAnimation: CoreModalLateralTransitionEnter, | ||||
|             leaveAnimation: CoreModalLateralTransitionLeave, | ||||
|         }); | ||||
| 
 | ||||
|         return await this.openModal<T>(modalOptions); | ||||
|  | ||||
| @ -78,6 +78,8 @@ core-format-text { | ||||
|         } | ||||
| 
 | ||||
|         &.core-expand-in-fullview { | ||||
|             cursor: pointer; | ||||
| 
 | ||||
|             .core-show-more { | ||||
|                 @include push-arrow-color(626262, true); | ||||
|                 @include padding-horizontal(null, 5px); | ||||
|  | ||||
| @ -137,16 +137,6 @@ ion-item.ion-text-wrap ion-label { | ||||
|     white-space: normal !important; | ||||
| } | ||||
| 
 | ||||
| // It fixes the click on links where ion-ripple-effect is present. | ||||
| .ion-activatable ion-label, | ||||
| .item-multiple-items ion-label { | ||||
|     z-index: 3; | ||||
|     pointer-events: none; | ||||
|     ion-anchor, ion-button, a, button { | ||||
|         pointer-events: visible; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @each $color-name, $value in $colors { | ||||
|     $value: map-get($colors, $color-name); | ||||
|     $base: map-get($value, base); | ||||
| @ -195,6 +185,8 @@ ion-header ion-toolbar { | ||||
| 
 | ||||
| // Ionic icon. | ||||
| ion-icon { | ||||
|     position: relative; | ||||
| 
 | ||||
|     &.icon-slash::after, | ||||
|     &.icon-backslash::after { | ||||
|         content: " "; | ||||
| @ -238,7 +230,8 @@ button, | ||||
|     min-width: var(--a11y-min-target-size); | ||||
| } | ||||
| 
 | ||||
| [role="button"] { | ||||
| [role="button"], | ||||
| .clickable { | ||||
|     cursor: pointer; | ||||
| 
 | ||||
|     [disabled], | ||||
| @ -256,6 +249,21 @@ ion-button.core-button-as-link { | ||||
|     white-space: break-spaces; | ||||
| } | ||||
| 
 | ||||
| button.as-link { | ||||
|     display: inline; | ||||
|     min-height: auto; | ||||
|     min-width: auto; | ||||
|     color: var(--core-link-color); | ||||
|     background: none; | ||||
|     border: 0; | ||||
|     line-height: inherit; | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|     text-align: start; | ||||
|     font-size: inherit; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // Ionic alert. | ||||
| ion-alert.core-alert-network-error .alert-head, | ||||
| div.core-iframe-network-error { | ||||
| @ -658,8 +666,11 @@ audio.core-media-adapt-width { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // It fixes the click on links where ion-ripple-effect is present. | ||||
| // Make links clickable when inside radio or checkbox items. Pointer and cursor part. | ||||
| ion-item.item-multiple-inputs { | ||||
| ion-item.item-multiple-inputs:not(.only-links), | ||||
| ion-item.ion-activatable:not(.only-links) { | ||||
|     cursor: pointer; | ||||
|     ion-label { | ||||
|         z-index: 3; | ||||
| @ -677,6 +688,12 @@ ion-item.item-multiple-inputs { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| ion-item.item-multiple-inputs.only-links { | ||||
|     a { | ||||
|         cursor: pointer; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Case with ion-input + ion-select inside. | ||||
| ion-item.item-input.item-multiple-inputs { | ||||
|     .flex-row { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user