Skip to content

Commit

Permalink
MOBILE-4653 html: Adapt new control flow on core components
Browse files Browse the repository at this point in the history
Some changes left untouched because in implies type checking
  • Loading branch information
crazyserver committed Jan 30, 2025
1 parent 2b45d21 commit c9467cd
Show file tree
Hide file tree
Showing 35 changed files with 758 additions and 493 deletions.
58 changes: 34 additions & 24 deletions src/core/components/attachments/core-attachments.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
<ion-item class="ion-text-wrap">
<ion-label>
<p class="item-heading">{{ title }} <span [core-mark-required]="required" class="core-mark-required"></span></p>
<span *ngIf="maxSubmissionsReadable">
{{ 'core.maxsizeandattachments' | translate:{$a: {size: maxSizeReadable, attachments: maxSubmissionsReadable} } }}
<span>
@if (maxSubmissionsReadable) {
{{ 'core.maxsizeandattachments' | translate:{$a: {size: maxSizeReadable, attachments: maxSubmissionsReadable} } }}
} @else {
{{ 'core.maxfilesize' | translate:{$a: maxSizeReadable} }}
}
</span>
<span *ngIf="!maxSubmissionsReadable">{{ 'core.maxfilesize' | translate:{$a: maxSizeReadable} }}</span>
</ion-label>
<ion-button slot="end" (click)="add()" [ariaLabel]="'core.fileuploader.addfiletext' | translate"
*ngIf="unlimitedFiles || (maxSubmissions !== undefined && maxSubmissions >= 0 && files && files.length < maxSubmissions)">
<ion-icon name="fas-plus" slot="icon-only" aria-hidden="true" />
</ion-button>
@if (unlimitedFiles || (maxSubmissions !== undefined && maxSubmissions >= 0 && files && files.length < maxSubmissions)) {
<ion-button slot="end" (click)="add()" [ariaLabel]="'core.fileuploader.addfiletext' | translate">
<ion-icon name="fas-plus" slot="icon-only" aria-hidden="true" />
</ion-button>
}
</ion-item>

@if (fileTypes && fileTypes.mimetypes && fileTypes.mimetypes.length) {
Expand All @@ -25,30 +29,36 @@
</ion-item>

<ul class="core-attachments" slot="content">
<li *ngFor="let typeInfo of fileTypes.info">
<strong *ngIf="typeInfo.name">{{typeInfo.name}} </strong>{{typeInfo.extlist}}
</li>
@for (typeInfo of fileTypes.info; track typeInfo.name) {
<li>
@if (typeInfo.name) {
<strong>{{typeInfo.name}} </strong>
}
{{typeInfo.extlist}}
</li>
}
</ul>
</ion-accordion>
</ion-accordion-group>
}



<ng-container *ngFor="let file of files; let index=index">
<!-- Files already attached to the submission, either in online or in offline. -->
<core-file *ngIf="!file.name" [file]="file" [component]="component" [componentId]="componentId" [canDelete]="true"
(onDelete)="delete(index, true)" [canDownload]="!file.offline" />

<!-- Files added to draft but not attached to submission yet. -->
<core-local-file *ngIf="file.name" [file]="file" [manage]="true" (onDelete)="delete(index, false)"
(onRename)="renamed(index, $event)" />
@if (file.name) {
<!-- Files added to draft but not attached to submission yet. -->
<core-local-file [file]="file" [manage]="true" (onDelete)="delete(index, false)" (onRename)="renamed(index, $event)" />
} @else {
<!-- Files already attached to the submission, either in online or in offline. -->
<core-file [file]="file" [component]="component" [componentId]="componentId" [canDelete]="true"
(onDelete)="delete(index, true)" [canDownload]="!file.offline" />
}
</ng-container>

<ion-item class="ion-text-wrap" *ngIf="!files || !files.length">
<ion-label>
<p>{{ 'core.fileuploader.nofilesattached' | translate }}</p>
</ion-label>
</ion-item>
@if (!files || !files.length) {
<ion-item class="ion-text-wrap">
<ion-label>
<p>{{ 'core.fileuploader.nofilesattached' | translate }}</p>
</ion-label>
</ion-item>
}
</ion-card>
</core-loading>
7 changes: 5 additions & 2 deletions src/core/components/bs-tooltip/core-bs-tooltip.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<ion-item class="ion-text-wrap">
<ion-label>
<p *ngIf="html" [innerHTML]="content"></p>
<p *ngIf="!html">{{content}}</p>
@if (html) {
<p [innerHTML]="content"></p>
} @else {
<p>{{content}}</p>
}
</ion-label>
</ion-item>
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<div *ngIf="!loading" @coreShowHideAnimation>
<ng-content />
</div>
@if (!loading) {
<div @coreShowHideAnimation>
<ng-content />
</div>
}

<!-- Spinner. -->
<ion-spinner *ngIf="loading" @coreShowHideAnimation [attr.aria-label]="loadingLabel | translate" />
@if (loading) {
<ion-spinner @coreShowHideAnimation [attr.aria-label]="loadingLabel | translate" />
}
16 changes: 10 additions & 6 deletions src/core/components/chart/core-chart.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<canvas #canvas [attr.height]="height"></canvas>

<ion-list *ngIf="chart">
<ion-item *ngFor="let data of legendItems">
<ion-icon name="fas-square" slot="start" [style.color]="data.fillStyle" aria-hidden="true" />
<ion-label>{{data.text}}</ion-label>
</ion-item>
</ion-list>
@if (chart) {
<ion-list>
@for (data of legendItems; track data) {
<ion-item>
<ion-icon name="fas-square" slot="start" [style.color]="data.fillStyle" aria-hidden="true" />
<ion-label>{{data.text}}</ion-label>
</ion-item>
}
</ion-list>
}
52 changes: 31 additions & 21 deletions src/core/components/combobox/core-combobox.html
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
<ion-select *ngIf="interface !== 'modal'" class="ion-text-start" [(ngModel)]="selection" (ngModelChange)="onValueChanged(selection)"
interface="popover" [disabled]="disabled" [class.combobox-icon-only]="icon"
[interfaceOptions]="{alignment: 'start', arrow: false, cssClass: 'core-combobox-select'}">
<div slot="label">
<span class="sr-only" *ngIf="label">{{ label }}</span>
<ion-icon *ngIf="icon" [name]="icon" aria-hidden="true" />
</div>
@if (interface !== 'modal') {
<ion-select class="ion-text-start" [(ngModel)]="selection" (ngModelChange)="onValueChanged(selection)" interface="popover"
[disabled]="disabled" [class.combobox-icon-only]="icon"
[interfaceOptions]="{alignment: 'start', arrow: false, cssClass: 'core-combobox-select'}">
<div slot="label">
@if (label) {
<span class="sr-only">{{ label }}</span>
}
@if (icon) {
<ion-icon [name]="icon" aria-hidden="true" />
}
</div>

<ng-content />
</ion-select>
<ng-content />
</ion-select>
} @else {
<ion-button aria-haspopup="listbox" [attr.aria-controls]="listboxId" [attr.aria-owns]="listboxId" [attr.aria-expanded]="expanded"
(click)="openModal()" [disabled]="disabled" expand="block" role="combobox">
@if (icon) {
<ion-icon [name]="icon" slot="start" aria-hidden="true" />
}

<ion-button *ngIf="interface === 'modal'" aria-haspopup="listbox" [attr.aria-controls]="listboxId" [attr.aria-owns]="listboxId"
[attr.aria-expanded]="expanded" (click)="openModal()" [disabled]="disabled" expand="block" role="combobox">
<ion-icon *ngIf="icon" [name]="icon" slot="start" aria-hidden="true" />
@if (label) {
<span class="sr-only">{{ label }},</span>
}
<div class="select-text">
<slot name="text"><core-format-text [text]="selection" /></slot>
</div>

<span class="sr-only" *ngIf="label">{{ label }},</span>
<div class="select-text">
<slot name="text"><core-format-text [text]="selection" /></slot>
</div>

<div class="select-icon" role="presentation" aria-hidden="true" slot="end">
<div class="select-icon-inner"></div>
</div>
</ion-button>
<div class="select-icon" role="presentation" aria-hidden="true" slot="end">
<div class="select-icon-inner"></div>
</div>
</ion-button>
}
58 changes: 34 additions & 24 deletions src/core/components/context-menu/core-context-menu-popover.html
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
<ion-content>
<ion-list [id]="uniqueId" role="menu">
<ion-item class="ion-text-wrap" lines="none" *ngFor="let item of items" core-link [capture]="item.captureLink"
[autoLogin]="item.autoLogin" [href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction"
[hidden]="item.hidden" [detail]="!!(item.href && !item.iconAction)" role="menuitem" [button]="!!(item.href && !item.iconAction)"
[showBrowserWarning]="item.showBrowserWarning">
<ion-toggle *ngIf="item.iconAction === 'toggle'" [(ngModel)]="item.toggle" (ionChange)="item.toggleChanged($event)">
<p class="item-heading">{{ item.content }}</p>
</ion-toggle>
<ng-container *ngIf="item.iconAction !== 'toggle'">
<ion-label>
<p class="item-heading">{{ item.content }}</p>
</ion-label>
<ng-container *ngIf="(item.href || item.action) && item.iconAction">
<ion-icon *ngIf="item.iconAction !== 'spinner'" [name]="item.iconAction" [class.icon-slash]="item.iconSlash" slot="end"
aria-hidden="true" />
<ion-spinner *ngIf="item.iconAction === 'spinner'" slot="end" [attr.aria-label]="'core.loading' | translate" />
</ng-container>
</ng-container>
<ion-badge class="{{item.badgeClass}}" slot="end" *ngIf="item.badge">
<span [attr.ara-hidden]="!!item.badgeA11yText">{{item.badge}}</span>
<span class="sr-only" *ngIf="item.badgeA11yText">
{{ item.badgeA11yText | translate: {$a : item.badge } }}
</span>
</ion-badge>
</ion-item>
@for (item of items; track item) {
<ion-item class="ion-text-wrap" lines="none" core-link [capture]="item.captureLink" [autoLogin]="item.autoLogin"
[href]="item.href" (click)="itemClicked($event, item)" [attr.aria-label]="item.ariaAction" [hidden]="item.hidden"
[detail]="!!(item.href && !item.iconAction)" role="menuitem" [button]="!!(item.href && !item.iconAction)"
[showBrowserWarning]="item.showBrowserWarning">
@if (item.iconAction === 'toggle') {
<ion-toggle [(ngModel)]="item.toggle" (ionChange)="item.toggleChanged($event)">
<p class="item-heading">{{ item.content }}</p>
</ion-toggle>
} @else {
<ion-label>
<p class="item-heading">{{ item.content }}</p>
</ion-label>
@if ((item.href || item.action) && item.iconAction) {
@if (item.iconAction === 'spinner') {
<ion-spinner slot="end" [attr.aria-label]="'core.loading' | translate" />
} @else {
<ion-icon [name]="item.iconAction" [class.icon-slash]="item.iconSlash" slot="end" aria-hidden="true" />
}
}
}

@if (item.badge) {
<ion-badge class="{{item.badgeClass}}" slot="end">
<span [attr.ara-hidden]="!!item.badgeA11yText">{{item.badge}}</span>
@if (item.badgeA11yText) {
<span class="sr-only">
{{ item.badgeA11yText | translate: {$a : item.badge } }}
</span>
}
</ion-badge>
}
</ion-item>
}
</ion-list>
</ion-content>
8 changes: 6 additions & 2 deletions src/core/components/course-image/course-image.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<ion-icon *ngIf="!course().courseimage" name="fas-graduation-cap" slot="start" aria-hidden="true" />
<ion-avatar *ngIf="course().courseimage" slot="start">
@if (!course().courseimage) {
<ion-icon name="fas-graduation-cap" slot="start" aria-hidden="true" />
}
@if (course().courseimage) {
<ion-avatar slot="start">
<img [url]="course().courseimage" core-external-content alt="" (error)="loadFallbackCourseIcon()" />
</ion-avatar>
}
42 changes: 25 additions & 17 deletions src/core/components/download-refresh/core-download-refresh.html
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
<ng-container *ngIf="enabled && !loading">
@if (enabled && !loading) {

<!-- Download button. -->
<ion-button *ngIf="status === statusNotDownloaded" fill="clear" (click)="download($event, false)" @coreShowHideAnimation
[ariaLabel]="(statusTranslatable || translates.notdownloaded) | translate: { name : statusSubject }">
<ion-icon slot="icon-only" name="fas-cloud-arrow-down" aria-hidden="true" />
</ion-button>
@if (status === statusNotDownloaded) {
<ion-button fill="clear" (click)="download($event, false)" @coreShowHideAnimation
[ariaLabel]="(statusTranslatable || translates.notdownloaded) | translate: { name : statusSubject }">
<ion-icon slot="icon-only" name="fas-cloud-arrow-down" aria-hidden="true" />
</ion-button>
}

<!-- Refresh button. -->
<ion-button *ngIf="status === statusOutdated || (status === statusDownloaded && !canTrustDownload)" fill="clear"
(click)="download($event, true)" @coreShowHideAnimation
[ariaLabel]="(statusTranslatable || translates.outdated) | translate: { name : statusSubject }">
<ion-icon slot="icon-only" name="fam-cloud-refresh" aria-hidden="true" />
</ion-button>
@if (status === statusOutdated || (status === statusDownloaded && !canTrustDownload)) {
<ion-button fill="clear" (click)="download($event, true)" @coreShowHideAnimation
[ariaLabel]="(statusTranslatable || translates.outdated) | translate: { name : statusSubject }">
<ion-icon slot="icon-only" name="fam-cloud-refresh" aria-hidden="true" />
</ion-button>
}

<!-- Downloaded status icon. -->
<ion-icon *ngIf="status === statusDownloaded && canTrustDownload" class="core-icon-downloaded ion-padding-horizontal" color="success"
name="fam-cloud-done" [attr.aria-label]="(statusTranslatable || translates.downloaded) | translate: { name : statusSubject }"
role="status" />
@if (status === statusDownloaded && canTrustDownload) {
<ion-icon class="core-icon-downloaded ion-padding-horizontal" color="success" name="fam-cloud-done"
[attr.aria-label]="(statusTranslatable || translates.downloaded) | translate: { name : statusSubject }" role="status" />
} @else if (status === statusDownloading) {
<ion-spinner @coreShowHideAnimation
[attr.aria-label]="(statusTranslatable || translates.downloading) | translate: { name : statusSubject }" />
}

<ion-spinner *ngIf="status === statusDownloading" @coreShowHideAnimation
[attr.aria-label]="(statusTranslatable || translates.downloading) | translate: { name : statusSubject }" />
</ng-container>
}

<!-- Spinner. -->
<ion-spinner *ngIf="loading" @coreShowHideAnimation [attr.aria-label]="translates.loading | translate: { name : statusSubject }" />
@if (loading) {
<ion-spinner @coreShowHideAnimation [attr.aria-label]="translates.loading | translate: { name : statusSubject }" />
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<!-- Content to display if no dynamic component. -->
<ng-content *ngIf="!instance" />
@if (!instance) {
<ng-content />
}

<!-- Container of the dynamic component -->
<ng-container #dynamicComponent />
4 changes: 3 additions & 1 deletion src/core/components/empty-box/core-empty-box.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
} @else if (image) {
<img [src]="image" role="presentation" alt="">
}
<p *ngIf="message">{{ message }}</p>
@if (message) {
<p>{{ message }}</p>
}
<ng-content />
65 changes: 38 additions & 27 deletions src/core/components/file/core-file.html
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
<ion-card class="card-file ion-activatable">
<ion-item *ngIf="file" tappable class="ion-text-wrap item-file" (click)="download($event, true)" [detail]="false">
<ion-thumbnail slot="start">
<img [src]="fileIcon" alt="" role="presentation" />
</ion-thumbnail>
<ion-label>
<p class="item-heading">
<span (ariaButtonClick)="download($event, true)">{{fileName}}</span>
</p>
<p *ngIf="fileSizeReadable || showTime">
<ng-container *ngIf="fileSizeReadable">{{ fileSizeReadable }}</ng-container>
<ng-container *ngIf="fileSizeReadable && showTime"> · </ng-container>
<ng-container *ngIf="showTime">{{ timemodified * 1000 | coreFormatDate }}</ng-container>
</p>
</ion-label>
<div slot="end" class="flex-row">
<core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" [canTrustDownload]="!alwaysDownload"
(action)="download()" />
@if (file) {
<ion-item tappable class="ion-text-wrap item-file" (click)="download($event, true)" [detail]="false">
<ion-thumbnail slot="start">
<img [src]="fileIcon" alt="" role="presentation" />
</ion-thumbnail>
<ion-label>
<p class="item-heading">
<span (ariaButtonClick)="download($event, true)">{{fileName}}</span>
</p>
@if (fileSizeReadable || showTime) {
<p>
@if (fileSizeReadable) {
{{ fileSizeReadable }}
}
@if (fileSizeReadable && showTime) {
·
}
@if (showTime) {
{{ timemodified * 1000 | coreFormatDate }}
}
</p>
}
</ion-label>
<div slot="end" class="flex-row">
<core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading"
[canTrustDownload]="!alwaysDownload" (action)="download()" />

<ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" [title]="openButtonLabel | translate">
<ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true" />
</ion-button>

<ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" [ariaLabel]="'core.delete' | translate"
color="danger">
<ion-icon slot="icon-only" name="fas-trash" aria-hidden="true" />
</ion-button>
</div>
</ion-item>
@if (isDownloaded && isIOS) {
<ion-button fill="clear" (click)="openFile($event, true)" [title]="openButtonLabel | translate">
<ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true" />
</ion-button>
} @else if (!isDownloading && canDelete) {
<ion-button fill="clear" (click)="delete($event)" [ariaLabel]="'core.delete' | translate" color="danger">
<ion-icon slot="icon-only" name="fas-trash" aria-hidden="true" />
</ion-button>
}
</div>
</ion-item>
}
<ion-ripple-effect />
</ion-card>
Loading

0 comments on commit c9467cd

Please sign in to comment.