commit
						1793ddc818
					
				| @ -9,242 +9,240 @@ | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="badges"> | ||||
|         <ion-refresher slot="fixed" [disabled]="!badgeLoaded" (ionRefresh)="refreshBadges($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="badgeLoaded"> | ||||
|             <ion-item-group *ngIf="badge"> | ||||
|                 <ion-item class="ion-text-wrap ion-text-center"> | ||||
|                     <ion-label> | ||||
|                         <img *ngIf="badge.badgeurl" class="large-avatar" [src]="badge.badgeurl" core-external-content [alt]="badge.name" /> | ||||
|                         <ion-badge color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire"> | ||||
|                             {{ 'addon.badges.expired' | translate }} | ||||
|                         </ion-badge> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
| <ion-content [core-swipe-navigation]="badges"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!badgeLoaded" (ionRefresh)="refreshBadges($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="badgeLoaded"> | ||||
|         <ion-item-group *ngIf="badge"> | ||||
|             <ion-item class="ion-text-wrap ion-text-center"> | ||||
|                 <ion-label> | ||||
|                     <img *ngIf="badge.badgeurl" class="large-avatar" [src]="badge.badgeurl" core-external-content [alt]="badge.name" /> | ||||
|                     <ion-badge color="danger" *ngIf="badge.dateexpire && currentTime >= badge.dateexpire"> | ||||
|                         {{ 'addon.badges.expired' | translate }} | ||||
|                     </ion-badge> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-item-group> | ||||
| 
 | ||||
|             <ion-item-group *ngIf="user"> | ||||
|         <ion-item-group *ngIf="user"> | ||||
|             <ion-item-divider> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.badges.recipientdetails' | translate}}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'core.name' | translate}}</h2> | ||||
|                     <p>{{ user.fullname }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-item-group> | ||||
| 
 | ||||
|         <ng-container *ngIf="badge"> | ||||
|             <ion-item-group> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.recipientdetails' | translate}}</h2> | ||||
|                         <h2>{{ 'addon.badges.issuerdetails' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.issuername"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.name' | translate}}</h2> | ||||
|                         <p>{{ user.fullname }}</p> | ||||
|                         <h2>{{ 'addon.badges.issuername' | translate}}</h2> | ||||
|                         <p>{{ badge.issuername }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.issuercontact"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.contact' | translate}}</h2> | ||||
|                         <p><a href="mailto:{{badge.issuercontact}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                 {{ badge.issuercontact }} | ||||
|                             </a></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
| 
 | ||||
|             <ng-container *ngIf="badge"> | ||||
|                 <ion-item-group> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.issuerdetails' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.issuername"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.issuername' | translate}}</h2> | ||||
|                             <p>{{ badge.issuername }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.issuercontact"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.contact' | translate}}</h2> | ||||
|                             <p><a href="mailto:{{badge.issuercontact}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                     {{ badge.issuercontact }} | ||||
|                                 </a></p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-item-group> | ||||
|             <ion-item-group> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.badgedetails' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.name"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.name' | translate}}</h2> | ||||
|                         <p>{{ badge.name }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.version"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.version' | translate}}</h2> | ||||
|                         <p>{{ badge.version }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.language"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.language' | translate}}</h2> | ||||
|                         <p>{{ badge.language }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.description"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.description' | translate}}</h2> | ||||
|                         <p>{{ badge.description }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.imageauthorname"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.imageauthorname' | translate}}</h2> | ||||
|                         <p>{{ badge.imageauthorname }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.imageauthoremail"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.imageauthoremail' | translate}}</h2> | ||||
|                         <p><a href="mailto:{{badge.imageauthoremail}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                 {{ badge.imageauthoremail }} | ||||
|                             </a></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.imageauthorurl"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.imageauthorurl' | translate}}</h2> | ||||
|                         <p><a [href]="badge.imageauthorurl" core-link auto-login="no"> {{ badge.imageauthorurl }} </a></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.imagecaption"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.imagecaption' | translate}}</h2> | ||||
|                         <p>{{ badge.imagecaption }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="course"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'core.course' | translate}}</h2> | ||||
|                         <p> | ||||
|                             <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <!-- Criteria (not yet available) --> | ||||
|             </ion-item-group> | ||||
| 
 | ||||
|                 <ion-item-group> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.badgedetails' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.name"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'core.name' | translate}}</h2> | ||||
|                             <p>{{ badge.name }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.version"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.version' | translate}}</h2> | ||||
|                             <p>{{ badge.version }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.language"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.language' | translate}}</h2> | ||||
|                             <p>{{ badge.language }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.description"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'core.description' | translate}}</h2> | ||||
|                             <p>{{ badge.description }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.imageauthorname"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.imageauthorname' | translate}}</h2> | ||||
|                             <p>{{ badge.imageauthorname }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.imageauthoremail"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.imageauthoremail' | translate}}</h2> | ||||
|                             <p><a href="mailto:{{badge.imageauthoremail}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                     {{ badge.imageauthoremail }} | ||||
|                                 </a></p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.imageauthorurl"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.imageauthorurl' | translate}}</h2> | ||||
|                             <p><a [href]="badge.imageauthorurl" core-link auto-login="no"> {{ badge.imageauthorurl }} </a></p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.imagecaption"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.imagecaption' | translate}}</h2> | ||||
|                             <p>{{ badge.imagecaption }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="course"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'core.course' | translate}}</h2> | ||||
|                             <p> | ||||
|                                 <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="courseId"> | ||||
|                                 </core-format-text> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <!-- Criteria (not yet available) --> | ||||
|                 </ion-item-group> | ||||
|             <ion-item-group> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.issuancedetails' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.dateissued"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.dateawarded' | translate}}</h2> | ||||
|                         <p>{{badge.dateissued * 1000 | coreFormatDate }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.dateexpire"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.expirydate' | translate}}</h2> | ||||
|                         <p> | ||||
|                             {{ badge.dateexpire * 1000 | coreFormatDate }} | ||||
|                             <span class="text-danger" *ngIf="currentTime >= badge.dateexpire"> | ||||
|                                 {{ 'addon.badges.warnexpired' | translate }} | ||||
|                             </span> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <!-- Evidence (not yet available) --> | ||||
|             </ion-item-group> | ||||
| 
 | ||||
|                 <ion-item-group> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.issuancedetails' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.dateissued"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.dateawarded' | translate}}</h2> | ||||
|                             <p>{{badge.dateissued * 1000 | coreFormatDate }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.dateexpire"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.expirydate' | translate}}</h2> | ||||
|                             <p> | ||||
|                                 {{ badge.dateexpire * 1000 | coreFormatDate }} | ||||
|                                 <span class="text-danger" *ngIf="currentTime >= badge.dateexpire"> | ||||
|                                     {{ 'addon.badges.warnexpired' | translate }} | ||||
|                                 </span> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <!-- Evidence (not yet available) --> | ||||
|                 </ion-item-group> | ||||
|             <!-- Endorsement --> | ||||
|             <ion-item-group *ngIf="badge.endorsement"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.bendorsement' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issuername"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.issuername' | translate}}</h2> | ||||
|                         <p>{{ badge.endorsement.issuername }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issueremail"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.issueremail' | translate}}</h2> | ||||
|                         <p> | ||||
|                             <a href="mailto:{{badge.endorsement.issueremail}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                 {{ badge.endorsement.issueremail }} | ||||
|                             </a> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issuerurl"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.issuerurl' | translate}}</h2> | ||||
|                         <p><a [href]="badge.endorsement.issuerurl" core-link auto-login="no"> {{ badge.endorsement.issuerurl }} </a></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.dateissued"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.dateawarded' | translate}}</h2> | ||||
|                         <p>{{ badge.endorsement.dateissued * 1000 | coreFormatDate }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.claimid"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.claimid' | translate}}</h2> | ||||
|                         <p><a [href]="badge.endorsement.claimid" core-link auto-login="no"> {{ badge.endorsement.claimid }} </a></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.claimcomment"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.claimcomment' | translate}}</h2> | ||||
|                         <p>{{ badge.endorsement.claimcomment }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
| 
 | ||||
|                 <!-- Endorsement --> | ||||
|                 <ion-item-group *ngIf="badge.endorsement"> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.bendorsement' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issuername"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.issuername' | translate}}</h2> | ||||
|                             <p>{{ badge.endorsement.issuername }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issueremail"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.issueremail' | translate}}</h2> | ||||
|                             <p> | ||||
|                                 <a href="mailto:{{badge.endorsement.issueremail}}" core-link auto-login="no" [showBrowserWarning]="false"> | ||||
|                                     {{ badge.endorsement.issueremail }} | ||||
|                                 </a> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.issuerurl"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.issuerurl' | translate}}</h2> | ||||
|                             <p><a [href]="badge.endorsement.issuerurl" core-link auto-login="no"> {{ badge.endorsement.issuerurl }} </a></p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.dateissued"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.dateawarded' | translate}}</h2> | ||||
|                             <p>{{ badge.endorsement.dateissued * 1000 | coreFormatDate }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.claimid"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.claimid' | translate}}</h2> | ||||
|                             <p><a [href]="badge.endorsement.claimid" core-link auto-login="no"> {{ badge.endorsement.claimid }} </a></p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.endorsement.claimcomment"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.claimcomment' | translate}}</h2> | ||||
|                             <p>{{ badge.endorsement.claimcomment }}</p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-item-group> | ||||
|             <!-- Related badges --> | ||||
|             <ion-item-group *ngIf="badge.relatedbadges"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.relatedbages' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let relatedBadge of badge.relatedbadges"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ relatedBadge.name }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.relatedbadges.length == 0"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.norelated' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
| 
 | ||||
|                 <!-- Related badges --> | ||||
|                 <ion-item-group *ngIf="badge.relatedbadges"> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.relatedbages' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap" *ngFor="let relatedBadge of badge.relatedbadges"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ relatedBadge.name }}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.relatedbadges.length == 0"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.norelated' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-item-group> | ||||
| 
 | ||||
|                 <!-- Competencies alignment --> | ||||
|                 <ion-item-group *ngIf="badge.alignment"> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.alignment' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap" *ngFor="let alignment of badge.alignment" [href]="alignment.targeturl" core-link | ||||
|                         auto-login="no"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ alignment.targetname }}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="badge.alignment.length == 0"> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.badges.noalignment' | translate}}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ion-item-group> | ||||
|             </ng-container> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|             <!-- Competencies alignment --> | ||||
|             <ion-item-group *ngIf="badge.alignment"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.alignment' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <ion-item class="ion-text-wrap" *ngFor="let alignment of badge.alignment" [href]="alignment.targeturl" core-link | ||||
|                     auto-login="no"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ alignment.targetname }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="badge.alignment.length == 0"> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.badges.noalignment' | translate}}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-item-group> | ||||
|         </ng-container> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -19,15 +19,12 @@ | ||||
|         </ion-button> | ||||
|     </core-navbar-buttons> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="submissions"> | ||||
|         <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshSubmission($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="loaded"> | ||||
|             <addon-mod-assign-submission *ngIf="loaded" | ||||
|                 [courseId]="courseId" [moduleId]="moduleId" [submitId]="submitId" [blindId]="blindId"> | ||||
|             </addon-mod-assign-submission> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
| <ion-content [core-swipe-navigation]="submissions"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="refreshSubmission($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <addon-mod-assign-submission *ngIf="loaded" [courseId]="courseId" [moduleId]="moduleId" [submitId]="submitId" [blindId]="blindId"> | ||||
|         </addon-mod-assign-submission> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -9,47 +9,45 @@ | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="attempts"> | ||||
|         <core-loading [hideUntil]="loaded"> | ||||
|             <ion-list class="ion-no-margin" *ngIf="attempt || anonAttempt"> | ||||
|                 <ion-item *ngIf="attempt" class="ion-text-wrap" core-user-link [userId]="attempt.userid" | ||||
|                     [attr.aria-label]="'core.user.viewprofile' | translate" [courseId]="attempt.courseid"> | ||||
|                     <core-user-avatar [user]="attempt" slot="start"></core-user-avatar> | ||||
|                     <ion-label> | ||||
|                         <h2>{{attempt.fullname}}</h2> | ||||
|                         <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| <ion-content [core-swipe-navigation]="attempts"> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ion-list class="ion-no-margin" *ngIf="attempt || anonAttempt"> | ||||
|             <ion-item *ngIf="attempt" class="ion-text-wrap" core-user-link [userId]="attempt.userid" | ||||
|                 [attr.aria-label]="'core.user.viewprofile' | translate" [courseId]="attempt.courseid"> | ||||
|                 <core-user-avatar [user]="attempt" slot="start"></core-user-avatar> | ||||
|                 <ion-label> | ||||
|                     <h2>{{attempt.fullname}}</h2> | ||||
|                     <p *ngIf="attempt.timemodified">{{attempt.timemodified * 1000 | coreFormatDate }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="anonAttempt"> | ||||
|                     <core-user-avatar [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.mod_feedback.anonymous_user' |translate }}</h2> | ||||
|                         <p>{{ 'addon.mod_feedback.response_nr' | translate }}: {{anonAttempt.number}}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ng-container *ngIf="items && items.length"> | ||||
|                     <ng-container *ngFor="let item of items"> | ||||
|                         <core-spacer *ngIf="item.typ == 'pagebreak'"></core-spacer> | ||||
|                         <ion-item class="ion-text-wrap" *ngIf="item.typ != 'pagebreak'" [color]="item.dependitem > 0 ? 'light' : ''"> | ||||
|                             <ion-label> | ||||
|                                 <h2 *ngIf="item.name" [core-mark-required]="item.required"> | ||||
|                                     <span *ngIf="feedback!.autonumbering && item.itemnumber">{{item.itemnumber}}. </span> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="item.name" contextLevel="module" | ||||
|                                         [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </h2> | ||||
|                                 <p *ngIf="item.submittedValue"> | ||||
|                                     <core-format-text [component]="component" [componentId]="cmId" [text]="item.submittedValue" | ||||
|                                         contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                     </core-format-text> | ||||
|                                 </p> | ||||
|                             </ion-label> | ||||
|                         </ion-item> | ||||
|                     </ng-container> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="anonAttempt"> | ||||
|                 <core-user-avatar [linkProfile]="false" slot="start"></core-user-avatar> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_feedback.anonymous_user' |translate }}</h2> | ||||
|                     <p>{{ 'addon.mod_feedback.response_nr' | translate }}: {{anonAttempt.number}}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ng-container *ngIf="items && items.length"> | ||||
|                 <ng-container *ngFor="let item of items"> | ||||
|                     <core-spacer *ngIf="item.typ == 'pagebreak'"></core-spacer> | ||||
|                     <ion-item class="ion-text-wrap" *ngIf="item.typ != 'pagebreak'" [color]="item.dependitem > 0 ? 'light' : ''"> | ||||
|                         <ion-label> | ||||
|                             <h2 *ngIf="item.name" [core-mark-required]="item.required"> | ||||
|                                 <span *ngIf="feedback!.autonumbering && item.itemnumber">{{item.itemnumber}}. </span> | ||||
|                                 <core-format-text [component]="component" [componentId]="cmId" [text]="item.name" contextLevel="module" | ||||
|                                     [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                 </core-format-text> | ||||
|                             </h2> | ||||
|                             <p *ngIf="item.submittedValue"> | ||||
|                                 <core-format-text [component]="component" [componentId]="cmId" [text]="item.submittedValue" | ||||
|                                     contextLevel="module" [contextInstanceId]="cmId" [courseId]="courseId"> | ||||
|                                 </core-format-text> | ||||
|                             </p> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                 </ng-container> | ||||
|             </ion-list> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|             </ng-container> | ||||
|         </ion-list> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -55,75 +55,73 @@ | ||||
|         </core-context-menu-item> | ||||
|     </core-context-menu> | ||||
| </core-navbar-buttons> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="discussions"> | ||||
|         <ion-refresher slot="fixed" [disabled]="!discussionLoaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
| <ion-content [core-swipe-navigation]="discussions"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!discussionLoaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="discussionLoaded"> | ||||
|             <!-- Discussion replies found to be synchronized --> | ||||
|             <ion-card class="core-warning-card" *ngIf="postHasOffline || hasOfflineRatings"> | ||||
|                 <ion-item> | ||||
|                     <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label>{{ 'core.hasdatatosync' | translate:{$a: discussionStr} }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
|     <core-loading [hideUntil]="discussionLoaded"> | ||||
|         <!-- Discussion replies found to be synchronized --> | ||||
|         <ion-card class="core-warning-card" *ngIf="postHasOffline || hasOfflineRatings"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'core.hasdatatosync' | translate:{$a: discussionStr} }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|             <!-- Cut-off date or due date message --> | ||||
|             <ion-card class="core-info-card" *ngIf="availabilityMessage"> | ||||
|                 <ion-item> | ||||
|                     <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label>{{ availabilityMessage }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
|         <!-- Cut-off date or due date message --> | ||||
|         <ion-card class="core-info-card" *ngIf="availabilityMessage"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-info-circle" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ availabilityMessage }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|             <ion-card class="core-info-card" *ngIf="discussion && discussion.locked"> | ||||
|                 <ion-item> | ||||
|                     <ion-icon name="fas-lock" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label>{{ 'addon.mod_forum.discussionlocked' | translate }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
|         <ion-card class="core-info-card" *ngIf="discussion && discussion.locked"> | ||||
|             <ion-item> | ||||
|                 <ion-icon name="fas-lock" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label>{{ 'addon.mod_forum.discussionlocked' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
| 
 | ||||
|             <div *ngIf="startingPost" class="ion-margin-bottom"> | ||||
|                 <addon-mod-forum-post [post]="startingPost" [discussion]="discussion" [courseId]="courseId" [highlight]="true" | ||||
|                     [discussionId]="discussionId" [component]="component" [componentId]="cmId" [formData]="formData" | ||||
|                     [originalData]="originalData" [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" | ||||
|                     [ratingInfo]="ratingInfo" [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|         <div *ngIf="startingPost" class="ion-margin-bottom"> | ||||
|             <addon-mod-forum-post [post]="startingPost" [discussion]="discussion" [courseId]="courseId" [highlight]="true" | ||||
|                 [discussionId]="discussionId" [component]="component" [componentId]="cmId" [formData]="formData" | ||||
|                 [originalData]="originalData" [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" | ||||
|                 [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|             </addon-mod-forum-post> | ||||
|         </div> | ||||
| 
 | ||||
|         <ion-card *ngIf="sort != 'nested'"> | ||||
|             <ng-container *ngFor="let post of posts; first as first"> | ||||
|                 <core-spacer *ngIf="!first"></core-spacer> | ||||
|                 <addon-mod-forum-post [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                     [componentId]="cmId" [formData]="formData" [originalData]="originalData" [parentSubject]="postSubjects[post.parentid]" | ||||
|                     [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" | ||||
|                     [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|                 </addon-mod-forum-post> | ||||
|             </div> | ||||
| 
 | ||||
|             <ion-card *ngIf="sort != 'nested'"> | ||||
|                 <ng-container *ngFor="let post of posts; first as first"> | ||||
|                     <core-spacer *ngIf="!first"></core-spacer> | ||||
|                     <addon-mod-forum-post [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                         [componentId]="cmId" [formData]="formData" [originalData]="originalData" | ||||
|                         [parentSubject]="postSubjects[post.parentid]" [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" | ||||
|                         [ratingInfo]="ratingInfo" [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|                     </addon-mod-forum-post> | ||||
|                 </ng-container> | ||||
|             </ion-card> | ||||
| 
 | ||||
|             <ng-container *ngIf="sort == 'nested'"> | ||||
|                 <ng-container *ngFor="let post of posts"> | ||||
|                     <ng-container *ngTemplateOutlet="nestedPosts; context: {post: post}"></ng-container> | ||||
|                 </ng-container> | ||||
|             </ng-container> | ||||
|         </ion-card> | ||||
| 
 | ||||
|             <ng-template #nestedPosts let-post="post"> | ||||
|                 <ion-card> | ||||
|                     <addon-mod-forum-post [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                         [componentId]="cmId" [formData]="formData" [originalData]="originalData" | ||||
|                         [parentSubject]="postSubjects[post.parentid]" [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" | ||||
|                         [ratingInfo]="ratingInfo" [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|                     </addon-mod-forum-post> | ||||
|                 </ion-card> | ||||
|                 <div class="ion-padding-start" *ngIf="post.children && post.children.length && post.children[0].subject"> | ||||
|                     <ng-container *ngFor="let child of post.children"> | ||||
|                         <ng-container *ngTemplateOutlet="nestedPosts; context: {post: child}"></ng-container> | ||||
|                     </ng-container> | ||||
|                 </div> | ||||
|             </ng-template> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|         <ng-container *ngIf="sort == 'nested'"> | ||||
|             <ng-container *ngFor="let post of posts"> | ||||
|                 <ng-container *ngTemplateOutlet="nestedPosts; context: {post: post}"></ng-container> | ||||
|             </ng-container> | ||||
|         </ng-container> | ||||
| 
 | ||||
|         <ng-template #nestedPosts let-post="post"> | ||||
|             <ion-card> | ||||
|                 <addon-mod-forum-post [post]="post" [courseId]="courseId" [discussionId]="discussionId" [component]="component" | ||||
|                     [componentId]="cmId" [formData]="formData" [originalData]="originalData" [parentSubject]="postSubjects[post.parentid]" | ||||
|                     [forum]="forum" [accessInfo]="accessInfo" [trackPosts]="trackPosts" [ratingInfo]="ratingInfo" | ||||
|                     [leavingPage]="leavingPage" (onPostChange)="postListChanged()"> | ||||
|                 </addon-mod-forum-post> | ||||
|             </ion-card> | ||||
|             <div class="ion-padding-start" *ngIf="post.children && post.children.length && post.children[0].subject"> | ||||
|                 <ng-container *ngFor="let child of post.children"> | ||||
|                     <ng-container *ngTemplateOutlet="nestedPosts; context: {post: child}"></ng-container> | ||||
|                 </ng-container> | ||||
|             </div> | ||||
|         </ng-template> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -11,78 +11,76 @@ | ||||
|         </ion-buttons> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="discussions"> | ||||
|         <ion-refresher slot="fixed" [disabled]="!groupsLoaded" (ionRefresh)="refreshGroups($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="groupsLoaded"> | ||||
|             <form *ngIf="showForm" #newDiscFormEl> | ||||
|                 <ion-item> | ||||
|                     <ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label> | ||||
|                     <ion-input [(ngModel)]="newDiscussion.subject" type="text" [placeholder]="'addon.mod_forum.subject' | translate" | ||||
|                         name="subject"> | ||||
|                     </ion-input> | ||||
| <ion-content [core-swipe-navigation]="discussions"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!groupsLoaded" (ionRefresh)="refreshGroups($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="groupsLoaded"> | ||||
|         <form *ngIf="showForm" #newDiscFormEl> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_forum.subject' | translate }}</ion-label> | ||||
|                 <ion-input [(ngModel)]="newDiscussion.subject" type="text" [placeholder]="'addon.mod_forum.subject' | translate" | ||||
|                     name="subject"> | ||||
|                 </ion-input> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label> | ||||
|                 <core-rich-text-editor name="addon_mod_forum_new_discussion" contextLevel="module" elementId="message" | ||||
|                     [control]="messageControl" [placeholder]="'addon.mod_forum.message' | translate" [component]="component" | ||||
|                     [componentId]="forum.cmid" [autoSave]="true" [contextInstanceId]="forum.cmid" | ||||
|                     (contentChanged)="onMessageChange($event)"> | ||||
|                 </core-rich-text-editor> | ||||
|             </ion-item> | ||||
|             <ion-item button class="divider ion-text-wrap" (click)="toggleAdvanced()" detail="false" [attr.aria-expanded]="advanced" | ||||
|                 [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate" role="heading" | ||||
|                 aria-controls="addon-mod-forum-new-discussion-advanced"> | ||||
|                 <ion-icon *ngIf="!advanced" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-icon *ngIf="advanced" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_forum.advanced' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <div *ngIf="advanced" id="addon-mod-forum-new-discussion-advanced"> | ||||
|                 <ion-item *ngIf="showGroups && groupIds.length > 1 && accessInfo.cancanposttomygroups"> | ||||
|                     <ion-label>{{ 'addon.mod_forum.posttomygroups' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.postToAllGroups" name="postallgroups"></ion-toggle> | ||||
|                 </ion-item> | ||||
|                 <ion-item *ngIf="showGroups"> | ||||
|                     <ion-label id="addon-mod-forum-groupslabel">{{ 'addon.mod_forum.group' | translate }}</ion-label> | ||||
|                     <ion-select [(ngModel)]="newDiscussion.groupId" [disabled]="newDiscussion.postToAllGroups" | ||||
|                         aria-labelledby="addon-mod-forum-groupslabel" interface="action-sheet" name="groupid" | ||||
|                         [interfaceOptions]="{header: 'addon.mod_forum.group' | translate}"> | ||||
|                         <ion-select-option *ngFor="let group of groups" [value]="group.id">{{ group.name }}</ion-select-option> | ||||
|                     </ion-select> | ||||
|                 </ion-item> | ||||
|                 <ion-item> | ||||
|                     <ion-label position="stacked">{{ 'addon.mod_forum.message' | translate }}</ion-label> | ||||
|                     <core-rich-text-editor name="addon_mod_forum_new_discussion" contextLevel="module" elementId="message" | ||||
|                         [control]="messageControl" [placeholder]="'addon.mod_forum.message' | translate" [component]="component" | ||||
|                         [componentId]="forum.cmid" [autoSave]="true" [contextInstanceId]="forum.cmid" | ||||
|                         (contentChanged)="onMessageChange($event)"> | ||||
|                     </core-rich-text-editor> | ||||
|                     <ion-label>{{ 'addon.mod_forum.discussionsubscription' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.subscribe" name="subscribe"></ion-toggle> | ||||
|                 </ion-item> | ||||
|                 <ion-item button class="divider ion-text-wrap" (click)="toggleAdvanced()" detail="false" [attr.aria-expanded]="advanced" | ||||
|                     [attr.aria-label]="(advanced ? 'core.hideadvanced' : 'core.showadvanced') | translate" role="heading" | ||||
|                     aria-controls="addon-mod-forum-new-discussion-advanced"> | ||||
|                     <ion-icon *ngIf="!advanced" name="fas-caret-right" flip-rtl slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-icon *ngIf="advanced" name="fas-caret-down" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.mod_forum.advanced' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 <ion-item *ngIf="canPin"> | ||||
|                     <ion-label>{{ 'addon.mod_forum.discussionpinned' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="newDiscussion.pin" name="pin"></ion-toggle> | ||||
|                 </ion-item> | ||||
|                 <div *ngIf="advanced" id="addon-mod-forum-new-discussion-advanced"> | ||||
|                     <ion-item *ngIf="showGroups && groupIds.length > 1 && accessInfo.cancanposttomygroups"> | ||||
|                         <ion-label>{{ 'addon.mod_forum.posttomygroups' | translate }}</ion-label> | ||||
|                         <ion-toggle [(ngModel)]="newDiscussion.postToAllGroups" name="postallgroups"></ion-toggle> | ||||
|                     </ion-item> | ||||
|                     <ion-item *ngIf="showGroups"> | ||||
|                         <ion-label id="addon-mod-forum-groupslabel">{{ 'addon.mod_forum.group' | translate }}</ion-label> | ||||
|                         <ion-select [(ngModel)]="newDiscussion.groupId" [disabled]="newDiscussion.postToAllGroups" | ||||
|                             aria-labelledby="addon-mod-forum-groupslabel" interface="action-sheet" name="groupid" | ||||
|                             [interfaceOptions]="{header: 'addon.mod_forum.group' | translate}"> | ||||
|                             <ion-select-option *ngFor="let group of groups" [value]="group.id">{{ group.name }}</ion-select-option> | ||||
|                         </ion-select> | ||||
|                     </ion-item> | ||||
|                     <ion-item> | ||||
|                         <ion-label>{{ 'addon.mod_forum.discussionsubscription' | translate }}</ion-label> | ||||
|                         <ion-toggle [(ngModel)]="newDiscussion.subscribe" name="subscribe"></ion-toggle> | ||||
|                     </ion-item> | ||||
|                     <ion-item *ngIf="canPin"> | ||||
|                         <ion-label>{{ 'addon.mod_forum.discussionpinned' | translate }}</ion-label> | ||||
|                         <ion-toggle [(ngModel)]="newDiscussion.pin" name="pin"></ion-toggle> | ||||
|                     </ion-item> | ||||
|                     <core-attachments *ngIf="canCreateAttachments && forum && forum.maxattachments > 0" [files]="newDiscussion.files" | ||||
|                         [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments" [component]="component" | ||||
|                         [componentId]="forum.cmid" [allowOffline]="true" [courseId]="courseId"> | ||||
|                     </core-attachments> | ||||
|                 </div> | ||||
|                 <ion-item> | ||||
|                     <ion-label> | ||||
|                         <ion-row> | ||||
|                             <ion-col> | ||||
|                                 <ion-button expand="block" [disabled]="newDiscussion.subject == '' || newDiscussion.message == null" | ||||
|                                     (click)="add()"> | ||||
|                                     {{ 'addon.mod_forum.posttoforum' | translate }} | ||||
|                                 </ion-button> | ||||
|                             </ion-col> | ||||
|                             <ion-col *ngIf="hasOffline"> | ||||
|                                 <ion-button expand="block" color="light" (click)="discard()">{{ 'core.discard' | translate }}</ion-button> | ||||
|                             </ion-col> | ||||
|                         </ion-row> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </form> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|                 <core-attachments *ngIf="canCreateAttachments && forum && forum.maxattachments > 0" [files]="newDiscussion.files" | ||||
|                     [maxSize]="forum.maxbytes" [maxSubmissions]="forum.maxattachments" [component]="component" [componentId]="forum.cmid" | ||||
|                     [allowOffline]="true" [courseId]="courseId"> | ||||
|                 </core-attachments> | ||||
|             </div> | ||||
|             <ion-item> | ||||
|                 <ion-label> | ||||
|                     <ion-row> | ||||
|                         <ion-col> | ||||
|                             <ion-button expand="block" [disabled]="newDiscussion.subject == '' || newDiscussion.message == null" | ||||
|                                 (click)="add()"> | ||||
|                                 {{ 'addon.mod_forum.posttoforum' | translate }} | ||||
|                             </ion-button> | ||||
|                         </ion-col> | ||||
|                         <ion-col *ngIf="hasOffline"> | ||||
|                             <ion-button expand="block" color="light" (click)="discard()">{{ 'core.discard' | translate }}</ion-button> | ||||
|                         </ion-col> | ||||
|                     </ion-row> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </form> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -11,76 +11,73 @@ | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="entries"> | ||||
|         <core-loading [hideUntil]="loaded"> | ||||
|             <form #editFormEl *ngIf="glossary"> | ||||
|                 <ion-item> | ||||
|                     <ion-label position="stacked">{{ 'addon.mod_glossary.concept' | translate }}</ion-label> | ||||
|                     <ion-input type="text" [placeholder]="'addon.mod_glossary.concept' | translate" [(ngModel)]="entry.concept" | ||||
|                         name="concept"> | ||||
|                     </ion-input> | ||||
|                 </ion-item> | ||||
|                 <ion-item> | ||||
|                     <ion-label position="stacked">{{ 'addon.mod_glossary.definition' | translate }}</ion-label> | ||||
|                     <core-rich-text-editor [control]="definitionControl" (contentChanged)="onDefinitionChange($event)" | ||||
|                         [placeholder]="'addon.mod_glossary.definition' | translate" name="addon_mod_glossary_edit" [component]="component" | ||||
|                         [componentId]="cmId" [autoSave]="true" contextLevel="module" [contextInstanceId]="cmId" | ||||
|                         elementId="definition_editor" [draftExtraParams]="editorExtraParams"> | ||||
|                     </core-rich-text-editor> | ||||
|                 </ion-item> | ||||
|                 <ion-item *ngIf="categories.length > 0"> | ||||
|                     <ion-label position="stacked" id="addon-mod-glossary-categories-label"> | ||||
|                         {{ 'addon.mod_glossary.categories' | translate }} | ||||
|                     </ion-label> | ||||
|                     <ion-select [(ngModel)]="options.categories" multiple="true" aria-labelledby="addon-mod-glossary-categories-label" | ||||
|                         interface="action-sheet" [placeholder]="'addon.mod_glossary.categories' | translate" name="categories" | ||||
|                         [interfaceOptions]="{header: 'addon.mod_glossary.categories' | translate}"> | ||||
|                         <ion-select-option *ngFor="let category of categories" [value]="category.id"> | ||||
|                             {{ category.name }} | ||||
|                         </ion-select-option> | ||||
|                     </ion-select> | ||||
|                 </ion-item> | ||||
|                 <ion-item> | ||||
|                     <ion-label position="stacked" id="addon-mod-glossary-aliases-label"> | ||||
|                         {{ 'addon.mod_glossary.aliases' | translate }} | ||||
|                     </ion-label> | ||||
|                     <ion-textarea [(ngModel)]="options.aliases" rows="1" [core-auto-rows]="options.aliases" | ||||
|                         aria-labelledby="addon-mod-glossary-aliases-label" name="aliases"> | ||||
|                     </ion-textarea> | ||||
|                 </ion-item> | ||||
| <ion-content [core-swipe-navigation]="entries"> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <form #editFormEl *ngIf="glossary"> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_glossary.concept' | translate }}</ion-label> | ||||
|                 <ion-input type="text" [placeholder]="'addon.mod_glossary.concept' | translate" [(ngModel)]="entry.concept" name="concept"> | ||||
|                 </ion-input> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked">{{ 'addon.mod_glossary.definition' | translate }}</ion-label> | ||||
|                 <core-rich-text-editor [control]="definitionControl" (contentChanged)="onDefinitionChange($event)" | ||||
|                     [placeholder]="'addon.mod_glossary.definition' | translate" name="addon_mod_glossary_edit" [component]="component" | ||||
|                     [componentId]="cmId" [autoSave]="true" contextLevel="module" [contextInstanceId]="cmId" elementId="definition_editor" | ||||
|                     [draftExtraParams]="editorExtraParams"> | ||||
|                 </core-rich-text-editor> | ||||
|             </ion-item> | ||||
|             <ion-item *ngIf="categories.length > 0"> | ||||
|                 <ion-label position="stacked" id="addon-mod-glossary-categories-label"> | ||||
|                     {{ 'addon.mod_glossary.categories' | translate }} | ||||
|                 </ion-label> | ||||
|                 <ion-select [(ngModel)]="options.categories" multiple="true" aria-labelledby="addon-mod-glossary-categories-label" | ||||
|                     interface="action-sheet" [placeholder]="'addon.mod_glossary.categories' | translate" name="categories" | ||||
|                     [interfaceOptions]="{header: 'addon.mod_glossary.categories' | translate}"> | ||||
|                     <ion-select-option *ngFor="let category of categories" [value]="category.id"> | ||||
|                         {{ category.name }} | ||||
|                     </ion-select-option> | ||||
|                 </ion-select> | ||||
|             </ion-item> | ||||
|             <ion-item> | ||||
|                 <ion-label position="stacked" id="addon-mod-glossary-aliases-label"> | ||||
|                     {{ 'addon.mod_glossary.aliases' | translate }} | ||||
|                 </ion-label> | ||||
|                 <ion-textarea [(ngModel)]="options.aliases" rows="1" [core-auto-rows]="options.aliases" | ||||
|                     aria-labelledby="addon-mod-glossary-aliases-label" name="aliases"> | ||||
|                 </ion-textarea> | ||||
|             </ion-item> | ||||
|             <ion-item-divider> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ 'addon.mod_glossary.attachment' | translate }}</h2> | ||||
|                 </ion-label> | ||||
|             </ion-item-divider> | ||||
|             <core-attachments [files]="attachments" [component]="component" [componentId]="glossary.coursemodule" [allowOffline]="true" | ||||
|                 [courseId]="courseId"> | ||||
|             </core-attachments> | ||||
|             <ng-container *ngIf="glossary.usedynalink"> | ||||
|                 <ion-item-divider> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ 'addon.mod_glossary.attachment' | translate }}</h2> | ||||
|                         <h2>{{ 'addon.mod_glossary.linking' | translate }}</h2> | ||||
|                     </ion-label> | ||||
|                 </ion-item-divider> | ||||
|                 <core-attachments [files]="attachments" [component]="component" [componentId]="glossary.coursemodule" [allowOffline]="true" | ||||
|                     [courseId]="courseId"> | ||||
|                 </core-attachments> | ||||
|                 <ng-container *ngIf="glossary.usedynalink"> | ||||
|                     <ion-item-divider> | ||||
|                         <ion-label> | ||||
|                             <h2>{{ 'addon.mod_glossary.linking' | translate }}</h2> | ||||
|                         </ion-label> | ||||
|                     </ion-item-divider> | ||||
|                     <ion-item class="ion-text-wrap"> | ||||
|                         <ion-label>{{ 'addon.mod_glossary.entryusedynalink' | translate }}</ion-label> | ||||
|                         <ion-toggle [(ngModel)]="options.usedynalink" name="usedynalink"></ion-toggle> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap"> | ||||
|                         <ion-label>{{ 'addon.mod_glossary.casesensitive' | translate }}</ion-label> | ||||
|                         <ion-toggle [disabled]="!options.usedynalink" [(ngModel)]="options.casesensitive" name="casesensitive"> | ||||
|                         </ion-toggle> | ||||
|                     </ion-item> | ||||
|                     <ion-item class="ion-text-wrap"> | ||||
|                         <ion-label>{{ 'addon.mod_glossary.fullmatch' | translate }}</ion-label> | ||||
|                         <ion-toggle [disabled]="!options.usedynalink" [(ngModel)]="options.fullmatch" name="fullmatch"></ion-toggle> | ||||
|                     </ion-item> | ||||
|                 </ng-container> | ||||
|                 <ion-button class="ion-margin" expand="block" [disabled]="!entry.concept || !entry.definition" (click)="save()"> | ||||
|                     {{ 'core.save' | translate }} | ||||
|                 </ion-button> | ||||
|             </form> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label>{{ 'addon.mod_glossary.entryusedynalink' | translate }}</ion-label> | ||||
|                     <ion-toggle [(ngModel)]="options.usedynalink" name="usedynalink"></ion-toggle> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label>{{ 'addon.mod_glossary.casesensitive' | translate }}</ion-label> | ||||
|                     <ion-toggle [disabled]="!options.usedynalink" [(ngModel)]="options.casesensitive" name="casesensitive"> | ||||
|                     </ion-toggle> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label>{{ 'addon.mod_glossary.fullmatch' | translate }}</ion-label> | ||||
|                     <ion-toggle [disabled]="!options.usedynalink" [(ngModel)]="options.fullmatch" name="fullmatch"></ion-toggle> | ||||
|                 </ion-item> | ||||
|             </ng-container> | ||||
|             <ion-button class="ion-margin" expand="block" [disabled]="!entry.concept || !entry.definition" (click)="save()"> | ||||
|                 {{ 'core.save' | translate }} | ||||
|             </ion-button> | ||||
|         </form> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -11,76 +11,74 @@ | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="entries"> | ||||
|         <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
| <ion-content [core-swipe-navigation]="entries"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
| 
 | ||||
|         <core-loading [hideUntil]="loaded"> | ||||
|             <ng-container *ngIf="entry && loaded"> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="showAuthor"> | ||||
|                     <core-user-avatar [user]="entry" slot="start"></core-user-avatar> | ||||
|                     <ion-label> | ||||
|                         <h2> | ||||
|                             <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId" | ||||
|                                 [courseId]="courseId"> | ||||
|                             </core-format-text> | ||||
|                         </h2> | ||||
|                         <p>{{ entry.userfullname }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-note slot="end" *ngIf="showDate">{{ entry.timemodified | coreDateDayOrTime }}</ion-note> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!showAuthor"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading"> | ||||
|                             <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId"> | ||||
|                             </core-format-text> | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                     <ion-note slot="end" *ngIf="showDate">{{ entry.timemodified | coreDateDayOrTime }}</ion-note> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap"> | ||||
|                     <ion-label> | ||||
|                         <core-format-text [component]="component" [componentId]="componentId" [text]="entry.definition" | ||||
|                             contextLevel="module" [contextInstanceId]="componentId" [courseId]="courseId"> | ||||
|     <core-loading [hideUntil]="loaded"> | ||||
|         <ng-container *ngIf="entry && loaded"> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="showAuthor"> | ||||
|                 <core-user-avatar [user]="entry" slot="start"></core-user-avatar> | ||||
|                 <ion-label> | ||||
|                     <h2> | ||||
|                         <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId" | ||||
|                             [courseId]="courseId"> | ||||
|                         </core-format-text> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <div *ngIf="entry.attachment" lines="none"> | ||||
|                     <core-file *ngFor="let file of entry.attachments" [file]="file" [component]="component" [componentId]="componentId"> | ||||
|                     </core-file> | ||||
|                 </div> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="tagsEnabled && entry && entry.tags && entry.tags.length > 0"> | ||||
|                     <ion-label> | ||||
|                         <div slot="start">{{ 'core.tag.tags' | translate }}:</div> | ||||
|                         <core-tag-list [tags]="entry.tags"></core-tag-list> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-wrap" *ngIf="!entry.approved"> | ||||
|                     <ion-label> | ||||
|                         <p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <core-comments *ngIf="glossary && glossary.allowcomments && entry && entry.id > 0 && commentsEnabled" contextLevel="module" | ||||
|                     [instanceId]="glossary.coursemodule" component="mod_glossary" [itemId]="entry.id" area="glossary_entry" | ||||
|                     [courseId]="glossary.course" [showItem]="true"> | ||||
|                 </core-comments> | ||||
|                 <core-rating-rate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                     [instanceId]="glossary.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="glossary.course" | ||||
|                     [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale" [userId]="entry.userid" (onUpdate)="ratingUpdated()"> | ||||
|                 </core-rating-rate> | ||||
|                 <core-rating-aggregate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                     [instanceId]="glossary.coursemodule" [itemId]="entry.id" [courseId]="glossary.course" | ||||
|                     [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale"> | ||||
|                 </core-rating-aggregate> | ||||
|             </ng-container> | ||||
|                     </h2> | ||||
|                     <p>{{ entry.userfullname }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-note slot="end" *ngIf="showDate">{{ entry.timemodified | coreDateDayOrTime }}</ion-note> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="!showAuthor"> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading"> | ||||
|                         <core-format-text [text]="entry.concept" contextLevel="module" [contextInstanceId]="componentId"> | ||||
|                         </core-format-text> | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|                 <ion-note slot="end" *ngIf="showDate">{{ entry.timemodified | coreDateDayOrTime }}</ion-note> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap"> | ||||
|                 <ion-label> | ||||
|                     <core-format-text [component]="component" [componentId]="componentId" [text]="entry.definition" contextLevel="module" | ||||
|                         [contextInstanceId]="componentId" [courseId]="courseId"> | ||||
|                     </core-format-text> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <div *ngIf="entry.attachment" lines="none"> | ||||
|                 <core-file *ngFor="let file of entry.attachments" [file]="file" [component]="component" [componentId]="componentId"> | ||||
|                 </core-file> | ||||
|             </div> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="tagsEnabled && entry && entry.tags && entry.tags.length > 0"> | ||||
|                 <ion-label> | ||||
|                     <div slot="start">{{ 'core.tag.tags' | translate }}:</div> | ||||
|                     <core-tag-list [tags]="entry.tags"></core-tag-list> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-wrap" *ngIf="!entry.approved"> | ||||
|                 <ion-label> | ||||
|                     <p><em>{{ 'addon.mod_glossary.entrypendingapproval' | translate }}</em></p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <core-comments *ngIf="glossary && glossary.allowcomments && entry && entry.id > 0 && commentsEnabled" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" component="mod_glossary" [itemId]="entry.id" area="glossary_entry" | ||||
|                 [courseId]="glossary.course" [showItem]="true"> | ||||
|             </core-comments> | ||||
|             <core-rating-rate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" [itemId]="entry.id" [itemSetId]="0" [courseId]="glossary.course" | ||||
|                 [aggregateMethod]="glossary.assessed" [scaleId]="glossary.scale" [userId]="entry.userid" (onUpdate)="ratingUpdated()"> | ||||
|             </core-rating-rate> | ||||
|             <core-rating-aggregate *ngIf="glossary && ratingInfo" [ratingInfo]="ratingInfo" contextLevel="module" | ||||
|                 [instanceId]="glossary.coursemodule" [itemId]="entry.id" [courseId]="glossary.course" [aggregateMethod]="glossary.assessed" | ||||
|                 [scaleId]="glossary.scale"> | ||||
|             </core-rating-aggregate> | ||||
|         </ng-container> | ||||
| 
 | ||||
|             <ion-card *ngIf="!entry" class="core-warning-card"> | ||||
|                 <ion-item> | ||||
|                     <ion-label>{{ 'addon.mod_glossary.errorloadingentry' | translate }}</ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-card> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|         <ion-card *ngIf="!entry" class="core-warning-card"> | ||||
|             <ion-item> | ||||
|                 <ion-label>{{ 'addon.mod_glossary.errorloadingentry' | translate }}</ion-label> | ||||
|             </ion-item> | ||||
|         </ion-card> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
| @ -49,6 +49,24 @@ export class CoreSwipeNavigationItemsManager< | ||||
|         await this.navigateToItemBy(1, 'forward'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Has a next item. | ||||
|      */ | ||||
|     async hasNextItem(): Promise<boolean> { | ||||
|         const item = await this.getItemBy(-1); | ||||
| 
 | ||||
|         return !!item; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Has a previous item. | ||||
|      */ | ||||
|     async hasPreviousItem(): Promise<boolean> { | ||||
|         const item = await this.getItemBy(1); | ||||
| 
 | ||||
|         return !!item; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|  | ||||
| @ -229,11 +229,19 @@ export const moodleTransitionAnimation = (navEl: HTMLElement, opts: TransitionOp | ||||
| 
 | ||||
|         rootAnimation.addAnimation(leavingContent); | ||||
| 
 | ||||
|         // Check if leaving content is being translated using transform styles and decide to use fromTo or only To animation.
 | ||||
|         const hasTransformStyle = !!leavingContentEl && (leavingContentEl as HTMLElement).style.transform !== ''; | ||||
|         if (backDirection) { | ||||
|             // leaving content, back direction
 | ||||
|             leavingContent | ||||
|                 .beforeClearStyles([OPACITY]) | ||||
|                 .fromTo('transform', `translateX(${CENTER})`, (isRTL ? 'translateX(-100%)' : 'translateX(100%)')); | ||||
|             if (hasTransformStyle) { | ||||
|                 leavingContent | ||||
|                     .to('transform', (isRTL ? 'translateX(-100%)' : 'translateX(100%)')) | ||||
|                     .fromTo(OPACITY, 1, OFF_OPACITY); | ||||
|             } else { | ||||
|                 leavingContent | ||||
|                     .beforeClearStyles([OPACITY]) | ||||
|                     .fromTo('transform', `translateX(${CENTER})`, (isRTL ? 'translateX(-100%)' : 'translateX(100%)')); | ||||
|             } | ||||
| 
 | ||||
|             const leavingPage = getIonPageElement(leavingEl) as HTMLElement; | ||||
|             rootAnimation.afterAddWrite(() => { | ||||
| @ -244,9 +252,15 @@ export const moodleTransitionAnimation = (navEl: HTMLElement, opts: TransitionOp | ||||
| 
 | ||||
|         } else { | ||||
|             // leaving content, forward direction
 | ||||
|             leavingContent | ||||
|                 .fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`) | ||||
|                 .fromTo(OPACITY, 1, OFF_OPACITY); | ||||
|             if (hasTransformStyle) { | ||||
|                 leavingContent | ||||
|                     .to('transform', (isRTL ? 'translateX(100%)' : 'translateX(-100%)')) | ||||
|                     .fromTo(OPACITY, 1, OFF_OPACITY); | ||||
|             } else { | ||||
|                 leavingContent | ||||
|                     .fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`) | ||||
|                     .fromTo(OPACITY, 1, OFF_OPACITY); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (leavingContentEl) { | ||||
|  | ||||
| @ -50,7 +50,6 @@ import { CoreShowPasswordComponent } from './show-password/show-password'; | ||||
| import { CoreSitePickerComponent } from './site-picker/site-picker'; | ||||
| import { CoreSplitViewComponent } from './split-view/split-view'; | ||||
| import { CoreStyleComponent } from './style/style'; | ||||
| import { CoreSwipeNavigationComponent } from './swipe-navigation/swipe-navigation'; | ||||
| import { CoreTabComponent } from './tabs/tab'; | ||||
| import { CoreTabsComponent } from './tabs/tabs'; | ||||
| import { CoreTabsOutletComponent } from './tabs-outlet/tabs-outlet'; | ||||
| @ -94,7 +93,6 @@ import { CoreSwipeSlidesComponent } from './swipe-slides/swipe-slides'; | ||||
|         CoreSitePickerComponent, | ||||
|         CoreSplitViewComponent, | ||||
|         CoreStyleComponent, | ||||
|         CoreSwipeNavigationComponent, | ||||
|         CoreSwipeSlidesComponent, | ||||
|         CoreTabComponent, | ||||
|         CoreTabsComponent, | ||||
| @ -144,7 +142,6 @@ import { CoreSwipeSlidesComponent } from './swipe-slides/swipe-slides'; | ||||
|         CoreSitePickerComponent, | ||||
|         CoreSplitViewComponent, | ||||
|         CoreStyleComponent, | ||||
|         CoreSwipeNavigationComponent, | ||||
|         CoreSwipeSlidesComponent, | ||||
|         CoreTabComponent, | ||||
|         CoreTabsComponent, | ||||
|  | ||||
| @ -1,5 +0,0 @@ | ||||
| <ion-slides [options]="{ allowTouchMove: enabled }" (swipeleft)="swipeLeft()" (swiperight)="swipeRight()"> | ||||
|     <ion-slide> | ||||
|         <ng-content></ng-content> | ||||
|     </ion-slide> | ||||
| </ion-slides> | ||||
| @ -1,24 +0,0 @@ | ||||
| ion-slides { | ||||
|     min-height: 100%; | ||||
| } | ||||
| 
 | ||||
| ion-slide { | ||||
|     align-items: start; | ||||
| } | ||||
| 
 | ||||
| :host ::ng-deep { | ||||
| 
 | ||||
|     .swiper-wrapper { | ||||
|         position: absolute; | ||||
|     } | ||||
| 
 | ||||
|     core-loading .core-loading-content { | ||||
|         display: block !important; | ||||
|         width: 100%; | ||||
|     } | ||||
| 
 | ||||
|     ion-refresher.refresher-native { | ||||
|         z-index: 2; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,54 +0,0 @@ | ||||
| // (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 { Component, Input } from '@angular/core'; | ||||
| import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager'; | ||||
| import { CoreScreen } from '@services/screen'; | ||||
| 
 | ||||
| @Component({ | ||||
|     selector: 'core-swipe-navigation', | ||||
|     templateUrl: 'swipe-navigation.html', | ||||
|     styleUrls: ['swipe-navigation.scss'], | ||||
| }) | ||||
| export class CoreSwipeNavigationComponent { | ||||
| 
 | ||||
|     @Input() manager?: CoreSwipeNavigationItemsManager; | ||||
| 
 | ||||
|     get enabled(): boolean { | ||||
|         return CoreScreen.isMobile && !!this.manager; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Swipe to previous item. | ||||
|      */ | ||||
|     swipeLeft(): void { | ||||
|         if (!this.enabled) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.manager?.navigateToPreviousItem(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Swipe to next item. | ||||
|      */ | ||||
|     swipeRight(): void { | ||||
|         if (!this.enabled) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.manager?.navigateToNextItem(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -28,6 +28,7 @@ import { CoreAriaButtonClickDirective } from './aria-button'; | ||||
| import { CoreOnResizeDirective } from './on-resize'; | ||||
| import { CoreDownloadFileDirective } from './download-file'; | ||||
| import { CoreCollapsibleHeaderDirective } from './collapsible-header'; | ||||
| import { CoreSwipeNavigationDirective } from './swipe-navigation'; | ||||
| 
 | ||||
| @NgModule({ | ||||
|     declarations: [ | ||||
| @ -45,6 +46,7 @@ import { CoreCollapsibleHeaderDirective } from './collapsible-header'; | ||||
|         CoreOnResizeDirective, | ||||
|         CoreDownloadFileDirective, | ||||
|         CoreCollapsibleHeaderDirective, | ||||
|         CoreSwipeNavigationDirective, | ||||
|     ], | ||||
|     exports: [ | ||||
|         CoreAutoFocusDirective, | ||||
| @ -61,6 +63,7 @@ import { CoreCollapsibleHeaderDirective } from './collapsible-header'; | ||||
|         CoreOnResizeDirective, | ||||
|         CoreDownloadFileDirective, | ||||
|         CoreCollapsibleHeaderDirective, | ||||
|         CoreSwipeNavigationDirective, | ||||
|     ], | ||||
| }) | ||||
| export class CoreDirectivesModule {} | ||||
|  | ||||
							
								
								
									
										158
									
								
								src/core/directives/swipe-navigation.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/core/directives/swipe-navigation.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| // (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 {  AfterViewInit, Directive, ElementRef, Input, OnDestroy } from '@angular/core'; | ||||
| import { CoreSwipeNavigationItemsManager } from '@classes/items-management/swipe-navigation-items-manager'; | ||||
| import { Gesture } from '@ionic/angular'; | ||||
| import { CoreScreen } from '@services/screen'; | ||||
| import { GestureController } from '@singletons'; | ||||
| 
 | ||||
| const ACTIVATION_THRESHOLD = 150; | ||||
| const SWIPE_FRICTION = 0.6; | ||||
| 
 | ||||
| /** | ||||
|  * Directive to enable content navigation with swipe. | ||||
|  * | ||||
|  * Example usage: | ||||
|  * | ||||
|  * <ion-content [core-swipe-navigation]="manager"> | ||||
|  */ | ||||
| @Directive({ | ||||
|     selector: 'ion-content[core-swipe-navigation]', | ||||
| }) | ||||
| export class CoreSwipeNavigationDirective implements AfterViewInit, OnDestroy { | ||||
| 
 | ||||
|     // eslint-disable-next-line @angular-eslint/no-input-rename
 | ||||
|     @Input('core-swipe-navigation') manager?: CoreSwipeNavigationItemsManager; | ||||
| 
 | ||||
|     protected element: HTMLElement; | ||||
|     protected swipeGesture?: Gesture; | ||||
| 
 | ||||
|     constructor(el: ElementRef) { | ||||
|         this.element = el.nativeElement; | ||||
|     } | ||||
| 
 | ||||
|     get enabled(): boolean { | ||||
|         return CoreScreen.isMobile && !!this.manager; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngAfterViewInit(): void { | ||||
|         const style = this.element.style; | ||||
|         this.swipeGesture = GestureController.create({ | ||||
|             el: this.element, | ||||
|             gestureName: 'swipe', | ||||
|             threshold: 10, | ||||
|             gesturePriority: 10, | ||||
|             canStart: () => this.enabled, | ||||
|             onStart: () => { | ||||
|                 style.transition = ''; | ||||
|             }, | ||||
|             onMove: (ev) => { | ||||
|                 style.transform = `translateX(${ev.deltaX * SWIPE_FRICTION }px)`; | ||||
|             }, | ||||
|             onEnd: (ev) => { | ||||
|                 style.transition = '.5s ease-out'; | ||||
| 
 | ||||
|                 if (ev.deltaX > ACTIVATION_THRESHOLD) { | ||||
|                     this.manager?.hasNextItem().then((hasNext) => { | ||||
|                         if (hasNext) { | ||||
|                             this.preventClickOnElement(); | ||||
| 
 | ||||
|                             style.transform = 'translateX(100%) !important'; | ||||
|                             this.swipeRight(); | ||||
|                         } else { | ||||
|                             style.transform = ''; | ||||
|                         } | ||||
| 
 | ||||
|                         return; | ||||
|                     }); | ||||
| 
 | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 if (ev.deltaX < -ACTIVATION_THRESHOLD) { | ||||
|                     this.manager?.hasPreviousItem().then((hasPrevious) => { | ||||
|                         if (hasPrevious) { | ||||
| 
 | ||||
|                             this.preventClickOnElement(); | ||||
| 
 | ||||
|                             style.transform = 'translateX(-100%) !important'; | ||||
|                             this.swipeLeft(); | ||||
|                         } else { | ||||
|                             style.transform = ''; | ||||
|                         } | ||||
| 
 | ||||
|                         return; | ||||
|                     }); | ||||
| 
 | ||||
|                     return; | ||||
|                 } | ||||
| 
 | ||||
|                 style.transform = ''; | ||||
| 
 | ||||
|             }, | ||||
|         }); | ||||
|         this.swipeGesture.enable(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Swipe to previous item. | ||||
|      */ | ||||
|     swipeLeft(): void { | ||||
|         if (!this.enabled) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.manager?.navigateToPreviousItem(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Swipe to next item. | ||||
|      */ | ||||
|     swipeRight(): void { | ||||
|         if (!this.enabled) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.manager?.navigateToNextItem(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prevent click event by capturing the click before happening. | ||||
|      */ | ||||
|     protected preventClickOnElement(): void { | ||||
|         this.element.addEventListener( | ||||
|             'click', | ||||
|             (ev: Event) => { | ||||
|                 ev.preventDefault(); | ||||
|                 ev.stopPropagation(); | ||||
| 
 | ||||
|                 return false; | ||||
|             }, | ||||
|             true, // Register event on the capture phase.
 | ||||
|         ); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnDestroy(): void { | ||||
|         this.swipeGesture?.destroy(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -8,89 +8,86 @@ | ||||
|         </ion-title> | ||||
|     </ion-toolbar> | ||||
| </ion-header> | ||||
| <ion-content> | ||||
|     <core-swipe-navigation [manager]="users"> | ||||
|         <ion-refresher slot="fixed" [disabled]="!userLoaded" (ionRefresh)="refreshUser($event.target)"> | ||||
|             <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|         </ion-refresher> | ||||
|         <core-loading [hideUntil]="userLoaded"> | ||||
|             <ion-list *ngIf="user && !isDeleted && isEnrolled"> | ||||
|                 <ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap"> | ||||
|                     <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true"> | ||||
|                     </core-user-avatar> | ||||
|                     <ion-label> | ||||
|                         <h2>{{ user.fullname }}</h2> | ||||
|                         <p *ngIf="user.address"> | ||||
|                             <ion-icon name="fas-map-marker-alt" [attr.aria-hidden]="true"></ion-icon> {{ user.address }} | ||||
|                         </p> | ||||
|                         <p *ngIf="rolesFormatted"> | ||||
|                             <strong>{{ 'core.user.roles' | translate}}</strong>{{'core.labelsep' | translate}} | ||||
|                             {{ rolesFormatted }} | ||||
|                         </p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
| <ion-content [core-swipe-navigation]="users"> | ||||
|     <ion-refresher slot="fixed" [disabled]="!userLoaded" (ionRefresh)="refreshUser($event.target)"> | ||||
|         <ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}"></ion-refresher-content> | ||||
|     </ion-refresher> | ||||
|     <core-loading [hideUntil]="userLoaded"> | ||||
|         <ion-list *ngIf="user && !isDeleted && isEnrolled"> | ||||
|             <ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap"> | ||||
|                 <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="true"> | ||||
|                 </core-user-avatar> | ||||
|                 <ion-label> | ||||
|                     <h2>{{ user.fullname }}</h2> | ||||
|                     <p *ngIf="user.address"> | ||||
|                         <ion-icon name="fas-map-marker-alt" [attr.aria-hidden]="true"></ion-icon> {{ user.address }} | ||||
|                     </p> | ||||
|                     <p *ngIf="rolesFormatted"> | ||||
|                         <strong>{{ 'core.user.roles' | translate}}</strong>{{'core.labelsep' | translate}} | ||||
|                         {{ rolesFormatted }} | ||||
|                     </p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
| 
 | ||||
|                 <div class="core-user-communication-handlers" | ||||
|                     *ngIf="(communicationHandlers && communicationHandlers.length) || isLoadingHandlers"> | ||||
|                     <ion-item *ngIf="communicationHandlers && communicationHandlers.length"> | ||||
|                         <ion-label> | ||||
|                             <ion-button *ngFor="let handler of communicationHandlers" expand="block" size="default" | ||||
|                                 [ngClass]="['core-user-profile-handler', handler.class || '']" (click)="handlerClicked($event, handler)" | ||||
|                                 [hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [disabled]="handler.spinner"> | ||||
|                                 <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|                                 {{ handler.title | translate }} | ||||
|                             </ion-button> | ||||
|                         </ion-label> | ||||
|                     </ion-item> | ||||
|                     <div *ngIf="isLoadingHandlers" class="ion-text-center core-loading-handlers"> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <ion-item button class="ion-text-wrap core-user-profile-handler" (click)="openUserDetails()" | ||||
|                     [attr.aria-label]="'core.user.details' | translate" detail="true"> | ||||
|                     <ion-icon name="fas-user" slot="start" aria-hidden="true"></ion-icon> | ||||
|             <div class="core-user-communication-handlers" | ||||
|                 *ngIf="(communicationHandlers && communicationHandlers.length) || isLoadingHandlers"> | ||||
|                 <ion-item *ngIf="communicationHandlers && communicationHandlers.length"> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ 'core.user.details' | translate }}</p> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item class="ion-text-center core-loading-handlers" *ngIf="isLoadingHandlers"> | ||||
|                     <ion-label> | ||||
|                         <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|                 <ion-item button *ngFor="let handler of newPageHandlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)" | ||||
|                     [ngClass]="['core-user-profile-handler', handler.class || '']" [hidden]="handler.hidden" | ||||
|                     [attr.aria-label]="handler.title | translate" detail="true"> | ||||
|                     <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|                     <ion-label> | ||||
|                         <p class="item-heading">{{ handler.title | translate }}</p> | ||||
|                     </ion-label> | ||||
|                     <ion-badge slot="end" *ngIf="handler.showBadge" [hidden]="handler.loading || !handler.badge" aria-hidden="true"> | ||||
|                         {{handler.badge}} | ||||
|                     </ion-badge> | ||||
|                     <span *ngIf="handler.showBadge && handler.badge && handler.badgeA11yText" class="sr-only"> | ||||
|                         {{ handler.badgeA11yText | translate: {$a : handler.badge } }} | ||||
|                     </span> | ||||
|                     <ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate"> | ||||
|                     </ion-spinner> | ||||
|                 </ion-item> | ||||
|                 <ion-item *ngIf="actionHandlers && actionHandlers.length"> | ||||
|                     <ion-label> | ||||
|                         <ion-button *ngFor="let handler of actionHandlers" expand="block" fill="outline" size="default" | ||||
|                         <ion-button *ngFor="let handler of communicationHandlers" expand="block" size="default" | ||||
|                             [ngClass]="['core-user-profile-handler', handler.class || '']" (click)="handlerClicked($event, handler)" | ||||
|                             [hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [disabled]="handler.spinner"> | ||||
|                             <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|                             {{ handler.title | translate }} | ||||
|                             <ion-spinner *ngIf="handler.spinner" slot="end" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                         </ion-button> | ||||
|                     </ion-label> | ||||
|                 </ion-item> | ||||
|             </ion-list> | ||||
|             <core-empty-box *ngIf="!user && !isDeleted && isEnrolled" icon="far-user" | ||||
|                 [message]=" 'core.user.detailsnotavailable' | translate"> | ||||
|             </core-empty-box> | ||||
|             <core-empty-box *ngIf="isDeleted" icon="far-user" [message]="'core.userdeleted' | translate"></core-empty-box> | ||||
|             <core-empty-box *ngIf="!isEnrolled" icon="far-user" [message]="'core.notenrolledprofile' | translate"></core-empty-box> | ||||
|         </core-loading> | ||||
|     </core-swipe-navigation> | ||||
|                 <div *ngIf="isLoadingHandlers" class="ion-text-center core-loading-handlers"> | ||||
|                     <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <ion-item button class="ion-text-wrap core-user-profile-handler" (click)="openUserDetails()" | ||||
|                 [attr.aria-label]="'core.user.details' | translate" detail="true"> | ||||
|                 <ion-icon name="fas-user" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ 'core.user.details' | translate }}</p> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item class="ion-text-center core-loading-handlers" *ngIf="isLoadingHandlers"> | ||||
|                 <ion-label> | ||||
|                     <ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|             <ion-item button *ngFor="let handler of newPageHandlers" class="ion-text-wrap" (click)="handlerClicked($event, handler)" | ||||
|                 [ngClass]="['core-user-profile-handler', handler.class || '']" [hidden]="handler.hidden" | ||||
|                 [attr.aria-label]="handler.title | translate" detail="true"> | ||||
|                 <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|                 <ion-label> | ||||
|                     <p class="item-heading">{{ handler.title | translate }}</p> | ||||
|                 </ion-label> | ||||
|                 <ion-badge slot="end" *ngIf="handler.showBadge" [hidden]="handler.loading || !handler.badge" aria-hidden="true"> | ||||
|                     {{handler.badge}} | ||||
|                 </ion-badge> | ||||
|                 <span *ngIf="handler.showBadge && handler.badge && handler.badgeA11yText" class="sr-only"> | ||||
|                     {{ handler.badgeA11yText | translate: {$a : handler.badge } }} | ||||
|                 </span> | ||||
|                 <ion-spinner slot="end" *ngIf="handler.showBadge && handler.loading" [attr.aria-label]="'core.loading' | translate"> | ||||
|                 </ion-spinner> | ||||
|             </ion-item> | ||||
|             <ion-item *ngIf="actionHandlers && actionHandlers.length"> | ||||
|                 <ion-label> | ||||
|                     <ion-button *ngFor="let handler of actionHandlers" expand="block" fill="outline" size="default" | ||||
|                         [ngClass]="['core-user-profile-handler', handler.class || '']" (click)="handlerClicked($event, handler)" | ||||
|                         [hidden]="handler.hidden" [attr.aria-label]="handler.title | translate" [disabled]="handler.spinner"> | ||||
|                         <ion-icon *ngIf="handler.icon" [name]="handler.icon" slot="start" aria-hidden="true"></ion-icon> | ||||
|                         {{ handler.title | translate }} | ||||
|                         <ion-spinner *ngIf="handler.spinner" slot="end" [attr.aria-label]="'core.loading' | translate"></ion-spinner> | ||||
|                     </ion-button> | ||||
|                 </ion-label> | ||||
|             </ion-item> | ||||
|         </ion-list> | ||||
|         <core-empty-box *ngIf="!user && !isDeleted && isEnrolled" icon="far-user" [message]=" 'core.user.detailsnotavailable' | translate"> | ||||
|         </core-empty-box> | ||||
|         <core-empty-box *ngIf="isDeleted" icon="far-user" [message]="'core.userdeleted' | translate"></core-empty-box> | ||||
|         <core-empty-box *ngIf="!isEnrolled" icon="far-user" [message]="'core.notenrolledprofile' | translate"></core-empty-box> | ||||
|     </core-loading> | ||||
| </ion-content> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user