commit
f965fcc94d
|
@ -128,7 +128,7 @@
|
||||||
[attr.aria-label]="'addon.messages.newmessages' | translate">
|
[attr.aria-label]="'addon.messages.newmessages' | translate">
|
||||||
<ion-icon name="fas-arrow-down" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-arrow-down" aria-hidden="true"></ion-icon>
|
||||||
<span class="sr-only">{{ 'addon.messages.newmessages' | translate }}</span>
|
<span class="sr-only">{{ 'addon.messages.newmessages' | translate }}</span>
|
||||||
<span class="core-discussion-messages-badge">{{ newMessages }}</span>
|
<ion-badge class="core-discussion-messages-badge">{{ newMessages }}</ion-badge>
|
||||||
</ion-fab-button>
|
</ion-fab-button>
|
||||||
</ion-fab>
|
</ion-fab>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
|
@ -27,13 +27,9 @@
|
||||||
|
|
||||||
.core-discussion-messages-badge {
|
.core-discussion-messages-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border-radius: 50%;
|
|
||||||
color: var(--addon-messages-discussion-badge-text);
|
color: var(--addon-messages-discussion-badge-text);
|
||||||
background-color: var(--addon-messages-discussion-badge);
|
background-color: var(--addon-messages-discussion-badge);
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 20px;
|
|
||||||
height: 20px;
|
|
||||||
width: 20px;
|
|
||||||
@include position(-6px, -6px, null, null);
|
@include position(-6px, -6px, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
<div *ngIf="downloadEnabled" slot="end" class="core-button-spinner">
|
<div *ngIf="downloadEnabled" slot="end" class="core-button-spinner">
|
||||||
<core-download-refresh *ngIf="!section.isDownloading" [status]="section.downloadStatus" [enabled]="true"
|
<core-download-refresh *ngIf="!section.isDownloading" [status]="section.downloadStatus" [enabled]="true"
|
||||||
(action)="prefecthSection(section)" [loading]="section.isDownloading || section.isCalculating"
|
(action)="prefecthSection(section)" [loading]="section.isDownloading || section.isCalculating"
|
||||||
[canTrustDownload]="true" size="small">
|
[canTrustDownload]="true">
|
||||||
</core-download-refresh>
|
</core-download-refresh>
|
||||||
|
|
||||||
<ion-badge class="core-course-download-section-progress"
|
<ion-badge class="core-course-download-section-progress"
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<core-download-refresh *ngIf="downloadEnabled && module.handlerData?.showDownloadButton"
|
<core-download-refresh *ngIf="downloadEnabled && module.handlerData?.showDownloadButton"
|
||||||
[status]="module.downloadStatus" [enabled]="true" [canTrustDownload]="true" size="small"
|
[status]="module.downloadStatus" [enabled]="true" [canTrustDownload]="true"
|
||||||
[loading]="module.spinner || module.handlerData.spinner" (action)="prefetchModule(module, section)">
|
[loading]="module.spinner || module.handlerData.spinner" (action)="prefetchModule(module, section)">
|
||||||
</core-download-refresh>
|
</core-download-refresh>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<ng-container *ngIf="enabled && !loading">
|
<ng-container *ngIf="enabled && !loading">
|
||||||
<!-- Download button. -->
|
<!-- Download button. -->
|
||||||
<ion-button *ngIf="status == statusNotDownloaded" fill="clear" (click)="download($event, false)" color="dark" @coreShowHideAnimation
|
<ion-button *ngIf="status == statusNotDownloaded" fill="clear" (click)="download($event, false)" color="dark" @coreShowHideAnimation
|
||||||
[attr.aria-label]="(statusTranslatable || 'core.download') | translate" [size]="size">
|
[attr.aria-label]="(statusTranslatable || 'core.download') | translate">
|
||||||
<ion-icon slot="icon-only" name="cloud-download" aria-hidden="true"></ion-icon>
|
<ion-icon slot="icon-only" name="cloud-download" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<!-- Refresh button. -->
|
<!-- Refresh button. -->
|
||||||
<ion-button *ngIf="status == statusOutdated || (status == statusDownloaded && !canTrustDownload)" fill="clear"
|
<ion-button *ngIf="status == statusOutdated || (status == statusDownloaded && !canTrustDownload)" fill="clear"
|
||||||
(click)="download($event, true)" color="dark" @coreShowHideAnimation
|
(click)="download($event, true)" color="dark" @coreShowHideAnimation
|
||||||
[attr.aria-label]="(statusTranslatable || 'core.refresh') | translate" [size]="size">
|
[attr.aria-label]="(statusTranslatable || 'core.refresh') | translate">
|
||||||
<ion-icon slot="icon-only" name="fas-redo-alt" aria-hidden="true"></ion-icon>
|
<ion-icon slot="icon-only" name="fas-redo-alt" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,10 @@ export class CoreDownloadRefreshComponent {
|
||||||
@Input() statusTranslatable?: string; // Download status translatable string.
|
@Input() statusTranslatable?: string; // Download status translatable string.
|
||||||
@Input() enabled = false; // Whether the download is enabled.
|
@Input() enabled = false; // Whether the download is enabled.
|
||||||
@Input() loading = true; // Force loading status when is not downloading.
|
@Input() loading = true; // Force loading status when is not downloading.
|
||||||
@Input() size: 'small' | 'default' | 'large' = 'default'; // Size of the buttons.
|
/**
|
||||||
|
* @deprecated since 4.0. It has no effect.
|
||||||
|
*/
|
||||||
|
@Input() size = ''; // Size of the buttons.
|
||||||
@Input() canTrustDownload = false; // If false, refresh will be shown if downloaded.
|
@Input() canTrustDownload = false; // If false, refresh will be shown if downloaded.
|
||||||
@Output() action: EventEmitter<boolean>; // Will emit an event when the item clicked.
|
@Output() action: EventEmitter<boolean>; // Will emit an event when the item clicked.
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<div slot="end" class="flex-row">
|
<div slot="end" class="flex-row">
|
||||||
<core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" [canTrustDownload]="!alwaysDownload"
|
<core-download-refresh [status]="state" [enabled]="canDownload" [loading]="isDownloading" [canTrustDownload]="!alwaysDownload"
|
||||||
(action)="download()" size="small">
|
(action)="download()">
|
||||||
</core-download-refresh>
|
</core-download-refresh>
|
||||||
|
|
||||||
<ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" color="dark"
|
<ion-button fill="clear" *ngIf="isDownloaded && isIOS" (click)="openFile($event, true)" color="dark"
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" [attr.aria-label]="'core.delete' | translate"
|
<ion-button fill="clear" *ngIf="!isDownloading && canDelete" (click)="delete($event)" [attr.aria-label]="'core.delete' | translate"
|
||||||
color="danger" size="small">
|
color="danger">
|
||||||
<ion-icon slot="icon-only" name="fas-trash" aria-hidden="true"></ion-icon>
|
<ion-icon slot="icon-only" name="fas-trash" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
--size: var(--module-icon-size);
|
--size: var(--module-icon-size);
|
||||||
--margin-end: 0px;
|
--margin-end: 0px;
|
||||||
--margin-vertical: 0px;
|
--margin-vertical: 0px;
|
||||||
|
--icon-radius: var(--small-radius);
|
||||||
|
|
||||||
margin-top: var(--margin-vertical);
|
margin-top: var(--margin-vertical);
|
||||||
margin-bottom: var(--margin-vertical);
|
margin-bottom: var(--margin-vertical);
|
||||||
@include margin-horizontal(null, var(--margin-end));
|
@include margin-horizontal(null, var(--margin-end));
|
||||||
|
|
||||||
border-radius: var(--small-radius);
|
border-radius: var(--icon-radius);
|
||||||
padding: 0.7rem;
|
padding: 0.7rem;
|
||||||
background-color: $gray-100;
|
background-color: $gray-100;
|
||||||
line-height: var(--size);
|
line-height: var(--size);
|
||||||
|
@ -50,4 +51,5 @@ img {
|
||||||
:host-context(ion-card ion-item) {
|
:host-context(ion-card ion-item) {
|
||||||
--margin-vertical: 12px;
|
--margin-vertical: 12px;
|
||||||
--margin-end: 12px;
|
--margin-end: 12px;
|
||||||
|
--icon-radius: var(--module-icon-radius);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
--ion-safe-area-top: 0px;
|
||||||
|
|
||||||
ion-tabs {
|
ion-tabs {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
|
@ -32,7 +32,6 @@ import { CoreMath } from '@singletons/math';
|
||||||
})
|
})
|
||||||
export class CoreCollapsibleHeaderDirective implements OnDestroy {
|
export class CoreCollapsibleHeaderDirective implements OnDestroy {
|
||||||
|
|
||||||
protected scrollElement?: HTMLElement;
|
|
||||||
protected loadingObserver: CoreEventObserver;
|
protected loadingObserver: CoreEventObserver;
|
||||||
protected content?: HTMLIonContentElement | null;
|
protected content?: HTMLIonContentElement | null;
|
||||||
protected header: HTMLIonHeaderElement;
|
protected header: HTMLIonHeaderElement;
|
||||||
|
|
|
@ -34,18 +34,18 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ion-buttons class="ion-padding core-course-section-nav-buttons safe-area-padding-horizontal"
|
<ion-buttons class="ion-padding core-course-section-nav-buttons safe-area-padding-horizontal"
|
||||||
*ngIf="displayCourseIndex && sections?.length">
|
*ngIf="displayCourseIndex && (previousSection || nextSection)">
|
||||||
<ion-button *ngIf="previousSection" (click)="sectionChanged(previousSection)" fill="outline" color="primary"
|
<ion-button *ngIf="previousSection" (click)="sectionChanged(previousSection)" color="primary" fill="solid" expand="block"
|
||||||
[attr.aria-label]="('core.previous' | translate) + ': ' + previousSection.name">
|
[attr.aria-label]="('core.previous' | translate) + ': ' + previousSection.name">
|
||||||
<ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-arrow-left" slot="start" aria-hidden="true"></ion-icon>
|
||||||
<core-format-text class="sr-only" [text]="previousSection.name" contextLevel="course" [contextInstanceId]="course.id">
|
<core-format-text [text]="previousSection.name" contextLevel="course" [contextInstanceId]="course.id">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button *ngIf="nextSection" (click)="sectionChanged(nextSection)" fill="solid" color="primary"
|
<ion-button *ngIf="nextSection" (click)="sectionChanged(nextSection)" color="primary" fill="solid" expand="block"
|
||||||
[attr.aria-label]="('core.next' | translate) + ': ' + nextSection.name">
|
[attr.aria-label]="('core.next' | translate) + ': ' + nextSection.name">
|
||||||
<core-format-text class="sr-only" [text]="nextSection.name" contextLevel="course" [contextInstanceId]="course.id">
|
<core-format-text [text]="nextSection.name" contextLevel="course" [contextInstanceId]="course.id">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
<ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-arrow-right" slot="end" aria-hidden="true"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
</core-loading>
|
</core-loading>
|
||||||
|
@ -74,26 +74,32 @@
|
||||||
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course.id">
|
<core-format-text [text]="section.name" contextLevel="course" [contextInstanceId]="course.id">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
</h2>
|
</h2>
|
||||||
<p *ngIf="section.visible === 0 || section.availabilityinfo || (section.highlighted && highlighted)">
|
<div *ngIf="section.visible === 0 && section.uservisible !== false">
|
||||||
<ion-badge color="info" *ngIf="section.visible === 0 && section.uservisible !== false" class="ion-text-wrap block">
|
<ion-chip>
|
||||||
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.course.hiddenfromstudents' | translate }}
|
<ion-label>{{ 'core.course.hiddenfromstudents' | translate }}</ion-label>
|
||||||
</ion-badge>
|
</ion-chip>
|
||||||
<ion-badge color="info" *ngIf="section.visible === 0 && section.uservisible === false" class="ion-text-wrap block">
|
</div>
|
||||||
|
<div *ngIf="section.visible === 0 && section.uservisible === false">
|
||||||
|
<ion-chip>
|
||||||
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
||||||
{{ 'core.notavailable' | translate }}
|
<ion-label>{{ 'core.notavailable' | translate }}</ion-label>
|
||||||
</ion-badge>
|
</ion-chip>
|
||||||
<ion-badge color="info" *ngIf="section.availabilityinfo" class="ion-text-wrap block">
|
</div>
|
||||||
|
<div *ngIf="section.availabilityinfo">
|
||||||
|
<ion-chip>
|
||||||
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
|
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
|
||||||
<core-format-text [text]=" section.availabilityinfo" contextLevel="course" [contextInstanceId]="course.id">
|
<ion-label>
|
||||||
</core-format-text>
|
<core-format-text [text]=" section.availabilityinfo" contextLevel="course" [contextInstanceId]="course.id">
|
||||||
</ion-badge>
|
</core-format-text>
|
||||||
</p>
|
</ion-label>
|
||||||
|
</ion-chip>
|
||||||
|
</div>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
<ion-badge class="ion-text-wrap block" *ngIf="section.highlighted && highlighted" slot="end">{{highlighted}}</ion-badge>
|
<ion-badge *ngIf="section.highlighted && highlighted" slot="end">{{highlighted}}</ion-badge>
|
||||||
</ion-item-divider>
|
</ion-item-divider>
|
||||||
|
|
||||||
<ion-item class="ion-text-wrap" *ngIf="section.summary">
|
<ion-item class="ion-text-wrap" *ngIf="section.summary" lines="none">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course.id">
|
<core-format-text [text]="section.summary" contextLevel="course" [contextInstanceId]="course.id">
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
.core-course-section-nav-buttons {
|
.core-course-section-nav-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: space-between;
|
||||||
|
|
||||||
core-format-text {
|
ion-button {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
}
|
flex: 1;
|
||||||
}
|
|
||||||
|
|
||||||
.course-section {
|
|
||||||
ion-badge {
|
|
||||||
text-align: start;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,11 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngIf="!completion.istrackeduser">
|
<ng-container *ngIf="!completion.istrackeduser">
|
||||||
<ion-chip *ngFor="let rule of details" color="light" role="listitem">
|
<ion-chip *ngFor="let rule of details" role="listitem">
|
||||||
<ion-label>{{ rule.rulevalue.description }}</ion-label>
|
<ion-icon name="fas-edit" aria-hidden="true"></ion-icon>
|
||||||
|
<ion-label>
|
||||||
|
<strong>{{ 'core.course.completion_automatic:todo' | translate }}</strong> {{ rule.rulevalue.description }}
|
||||||
|
</ion-label>
|
||||||
</ion-chip>
|
</ion-chip>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<ion-card *ngIf="module.handlerData && module.visibleoncoursepage !== 0">
|
<ion-card *ngIf="module.handlerData && module.visibleoncoursepage !== 0">
|
||||||
<ng-container *ngIf="!module.handlerData.loading">
|
<ng-container *ngIf="!module.handlerData.loading">
|
||||||
<ion-item id="core-course-module-{{module.id}}"
|
<ion-item id="core-course-module-{{module.id}}" detail="false" lines="none"
|
||||||
class="ion-text-wrap core-course-module-handler core-module-main-item {{module.handlerData.class}}"
|
class="ion-text-wrap core-course-module-handler core-module-main-item {{module.handlerData.class}}"
|
||||||
(click)="moduleClicked($event)" [attr.aria-label]="module.handlerData.a11yTitle" [ngClass]="{
|
(click)="moduleClicked($event)" [attr.aria-label]="module.handlerData.a11yTitle" [ngClass]="{
|
||||||
'has-module-info': hasInfo,
|
'has-module-info': hasInfo,
|
||||||
'item-media': module.handlerData.icon,
|
'item-media': module.handlerData.icon,
|
||||||
'item-dimmed': module.visible === 0 || module.uservisible === false
|
'item-dimmed': module.visible === 0 || module.uservisible === false
|
||||||
}" [button]="module.handlerData.action && module.uservisible" detail="false">
|
}" [button]="module.handlerData.action && module.uservisible">
|
||||||
|
|
||||||
<core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" [modname]="module.modname"
|
<core-mod-icon slot="start" *ngIf="module.handlerData.icon" [modicon]="module.handlerData.icon" [modname]="module.modname"
|
||||||
[componentId]="module.instance">
|
[componentId]="module.instance">
|
||||||
|
@ -19,8 +19,8 @@
|
||||||
</core-format-text>
|
</core-format-text>
|
||||||
</p>
|
</p>
|
||||||
<ion-chip class="completioninfo completion_incomplete" *ngIf="completionStatus === 0">
|
<ion-chip class="completioninfo completion_incomplete" *ngIf="completionStatus === 0">
|
||||||
|
<ion-icon name="fas-edit" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<ion-icon name="fas-edit" aria-hidden="true"></ion-icon>
|
|
||||||
{{ 'core.course.todo' | translate }}
|
{{ 'core.course.todo' | translate }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-chip>
|
</ion-chip>
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
|
|
||||||
<div class="core-module-buttons-more">
|
<div class="core-module-buttons-more">
|
||||||
<!-- Buttons defined by the module handler. -->
|
<!-- Buttons defined by the module handler. -->
|
||||||
<ion-button fill="clear" *ngFor="let button of module.handlerData.buttons" color="dark" size="small"
|
<ion-button fill="clear" *ngFor="let button of module.handlerData.buttons" color="dark"
|
||||||
[hidden]="button.hidden || module.handlerData.spinner" class="core-animate-show-hide"
|
[hidden]="button.hidden || module.handlerData.spinner" class="core-animate-show-hide"
|
||||||
(click)="buttonClicked($event, button)" [attr.aria-label]="button.label | translate:{$a: module.handlerData.title}">
|
(click)="buttonClicked($event, button)" [attr.aria-label]="button.label | translate:{$a: module.handlerData.title}">
|
||||||
<ion-icon [name]="button.icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
<ion-icon [name]="button.icon" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||||
|
@ -58,11 +58,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item *ngIf="hasInfo" id="core-course-module-{{module.id}}-info"
|
<ion-item *ngIf="hasInfo" id="core-course-module-{{module.id}}-info" detail="false" lines="none"
|
||||||
class="ion-text-wrap core-course-module-handler core-course-module-info {{module.handlerData.class}}" [ngClass]="{
|
class="ion-text-wrap core-course-module-handler core-course-module-info {{module.handlerData.class}}" [ngClass]="{
|
||||||
'item-media': module.handlerData.icon,
|
'item-media': module.handlerData.icon,
|
||||||
'item-dimmed': module.visible === 0 || module.uservisible === false
|
'item-dimmed': module.visible === 0 || module.uservisible === false
|
||||||
}" detail="false">
|
}">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<core-format-text class="core-module-description" *ngIf="module.description" [maxHeight]="80" [text]="module.description"
|
<core-format-text class="core-module-description" *ngIf="module.description" [maxHeight]="80" [text]="module.description"
|
||||||
contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course">
|
contextLevel="module" [contextInstanceId]="module.id" [courseId]="module.course">
|
||||||
|
@ -82,30 +82,38 @@
|
||||||
[showManualCompletion]="showManualCompletion" (completionChanged)="completionChanged.emit($event)">
|
[showManualCompletion]="showManualCompletion" (completionChanged)="completionChanged.emit($event)">
|
||||||
</core-course-module-completion>
|
</core-course-module-completion>
|
||||||
|
|
||||||
<ion-chip *ngIf="module.completiondata?.offline" color="warning" class="ion-text-wrap block">
|
<div *ngIf="module.completiondata?.offline">
|
||||||
<ion-icon name="fas-sync" aria-hidden="true"></ion-icon>
|
<ion-chip color="warning">
|
||||||
<ion-label>{{ 'core.course.manualcompletionnotsynced' | translate }}</ion-label>
|
<ion-icon name="fas-sync" aria-hidden="true"></ion-icon>
|
||||||
</ion-chip>
|
<ion-label>{{ 'core.course.manualcompletionnotsynced' | translate }}</ion-label>
|
||||||
|
</ion-chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Availability -->
|
<!-- Availability -->
|
||||||
<ion-chip *ngIf="module.visible === 0 && (!section || section.visible)" class="ion-text-wrap block">
|
<div *ngIf="module.visible === 0 && (!section || section.visible)">
|
||||||
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
<ion-chip>
|
||||||
<ion-label>{{ 'core.course.hiddenfromstudents' | translate }}</ion-label>
|
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
||||||
</ion-chip>
|
<ion-label>{{ 'core.course.hiddenfromstudents' | translate }}</ion-label>
|
||||||
|
</ion-chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ion-chip *ngIf="module.visible !== 0 && module.isStealth" class="ion-text-wrap block">
|
<div *ngIf="module.visible !== 0 && module.isStealth">
|
||||||
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
<ion-chip>
|
||||||
<ion-label>{{ 'core.course.hiddenoncoursepage' | translate }}</ion-label>
|
<ion-icon name="fas-eye-slash" aria-hidden="true"></ion-icon>
|
||||||
</ion-chip>
|
<ion-label>{{ 'core.course.hiddenoncoursepage' | translate }}</ion-label>
|
||||||
|
</ion-chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ion-chip class="core-module-availabilityinfo ion-text-wrap block" *ngIf="module.availabilityinfo">
|
<div *ngIf="module.availabilityinfo">
|
||||||
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
|
<ion-chip class="core-module-availabilityinfo">
|
||||||
<ion-label>
|
<ion-icon name="fas-lock" [attr.aria-label]="'core.restricted' | translate"></ion-icon>
|
||||||
<core-format-text [text]="module.availabilityinfo" contextLevel="module" [contextInstanceId]="module.id"
|
<ion-label>
|
||||||
[courseId]="module.course" class="ion-text-wrap">
|
<core-format-text [text]="module.availabilityinfo" contextLevel="module" [contextInstanceId]="module.id"
|
||||||
</core-format-text>
|
[courseId]="module.course">
|
||||||
</ion-label>
|
</core-format-text>
|
||||||
</ion-chip>
|
</ion-label>
|
||||||
|
</ion-chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
@ -114,7 +122,7 @@
|
||||||
<!-- Loading. -->
|
<!-- Loading. -->
|
||||||
<ion-item *ngIf="module.handlerData.loading" role="status" class="ion-text-wrap" id="core-course-module-{{module.id}}"
|
<ion-item *ngIf="module.handlerData.loading" role="status" class="ion-text-wrap" id="core-course-module-{{module.id}}"
|
||||||
[attr.aria-label]="module.handlerData.a11yTitle"
|
[attr.aria-label]="module.handlerData.a11yTitle"
|
||||||
[ngClass]="['core-course-module-handler', 'core-module-loading', module.handlerData.class]" detail="false">
|
[ngClass]="['core-course-module-handler', 'core-module-loading', module.handlerData.class]" detail="false" lines="none">
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
<ion-spinner [attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
|
@ -62,8 +62,9 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title;
|
this.module.handlerData.a11yTitle = this.module.handlerData.a11yTitle ?? this.module.handlerData.title;
|
||||||
this.completionStatus = this.module.completiondata === undefined ||
|
this.completionStatus = this.module.completiondata === undefined ||
|
||||||
this.module.completiondata.tracking == CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE
|
!this.module.completiondata?.istrackeduser ||
|
||||||
|
this.module.completiondata.tracking == CoreCourseModuleCompletionTracking.COMPLETION_TRACKING_NONE
|
||||||
? undefined
|
? undefined
|
||||||
: this.module.completiondata.state;
|
: this.module.completiondata.state;
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
|
|
||||||
:host-context(body.dark) {
|
:host-context(body.dark) {
|
||||||
@if ($core-login-button-outline-dark) {
|
@if ($core-login-button-outline-dark) {
|
||||||
form ion-button-dark {
|
form ion-button {
|
||||||
--background: white;
|
--background: white;
|
||||||
--color: var(--core-login-background-dark);
|
--color: var(--core-login-background-dark);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
<div class="ion-text-center ion-padding">{{ 'core.login.or' | translate }}</div>
|
<div class="ion-text-center ion-padding">{{ 'core.login.or' | translate }}</div>
|
||||||
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()">
|
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()">
|
||||||
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
|
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>{{ 'core.scanqr' | translate }}</ion-label>
|
{{ 'core.scanqr' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</form>
|
</form>
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
<!-- Forgotten password option. -->
|
<!-- Forgotten password option. -->
|
||||||
<ion-button *ngIf="showForgottenPassword" expand="block" fill="clear" color="dark"
|
<ion-button *ngIf="showForgottenPassword" expand="block" fill="clear" color="dark"
|
||||||
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
||||||
<ion-label>{{ 'core.login.forgotten' | translate }}</ion-label>
|
{{ 'core.login.forgotten' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<ion-list *ngIf="identityProviders && identityProviders.length" class="ion-padding-top core-login-identity-providers">
|
<ion-list *ngIf="identityProviders && identityProviders.length" class="ion-padding-top core-login-identity-providers">
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
<div class="ion-text-center ion-padding">{{ 'core.login.or' | translate }}</div>
|
<div class="ion-text-center ion-padding">{{ 'core.login.or' | translate }}</div>
|
||||||
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()">
|
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()">
|
||||||
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
|
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>{{ 'core.scanqr' | translate }}</ion-label>
|
{{ 'core.scanqr' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</form>
|
</form>
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
<!-- Forgotten password option. -->
|
<!-- Forgotten password option. -->
|
||||||
<ion-button *ngIf="showForgottenPassword && !isOAuth" expand="block" fill="clear" color="dark"
|
<ion-button *ngIf="showForgottenPassword && !isOAuth" expand="block" fill="clear" color="dark"
|
||||||
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
class="core-login-forgotten-password core-button-as-link ion-text-wrap" (click)="forgottenPassword()">
|
||||||
<ion-label>{{ 'core.login.forgotten' | translate }}</ion-label>
|
{{ 'core.login.forgotten' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<!-- Identity providers. -->
|
<!-- Identity providers. -->
|
||||||
|
|
|
@ -104,14 +104,14 @@
|
||||||
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()"
|
<ion-button expand="block" color="light" class="ion-margin" lines="none" (click)="showInstructionsAndScanQR()"
|
||||||
aria-haspopup="dialog">
|
aria-haspopup="dialog">
|
||||||
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
|
<ion-icon slot="start" name="fas-qrcode" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>{{ 'core.scanqr' | translate }}</ion-label>
|
{{ 'core.scanqr' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Help. -->
|
<!-- Help. -->
|
||||||
<ion-button class="ion-margin-top core-login-need-help core-button-as-link ion-text-wrap" (click)="showHelp()" aria-haspopup="dialog"
|
<ion-button class="ion-margin-top core-login-need-help core-button-as-link ion-text-wrap" (click)="showHelp()" aria-haspopup="dialog"
|
||||||
expand="block" fill="clear" color="dark">
|
expand="block" fill="clear" color="dark">
|
||||||
<ion-label>{{ 'core.needhelp' | translate }}</ion-label>
|
{{ 'core.needhelp' | translate }}
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
<ng-template #allCourseList>
|
<ng-template #allCourseList>
|
||||||
<ion-item button class="ion-text-wrap" (click)="openAvailableCourses()" detail="true">
|
<ion-item button class="ion-text-wrap" (click)="openAvailableCourses()" lines="none">
|
||||||
<ion-icon name="fas-graduation-cap" fixed-width slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-graduation-cap" fixed-width slot="start" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'core.courses.availablecourses' | translate}}</h2>
|
<h2>{{ 'core.courses.availablecourses' | translate}}</h2>
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #categories>
|
<ng-template #categories>
|
||||||
<ion-item button class="ion-text-wrap" (click)="openCourseCategories()" detail="true">
|
<ion-item button class="ion-text-wrap" (click)="openCourseCategories()" lines="none">
|
||||||
<ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-folder" slot="start" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'core.courses.categories' | translate}}</h2>
|
<h2>{{ 'core.courses.categories' | translate}}</h2>
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #enrolledCourseList>
|
<ng-template #enrolledCourseList>
|
||||||
<ion-item button class="ion-text-wrap" (click)="openMyCourses()" detail="true">
|
<ion-item button class="ion-text-wrap" (click)="openMyCourses()" lines="none">
|
||||||
<ion-icon name="fas-graduation-cap" fixed-width slot="start" aria-hidden="true">
|
<ion-icon name="fas-graduation-cap" fixed-width slot="start" aria-hidden="true">
|
||||||
</ion-icon>
|
</ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #courseSearch>
|
<ng-template #courseSearch>
|
||||||
<ion-item button class="ion-text-wrap" (click)="openSearch()" detail="true">
|
<ion-item button class="ion-text-wrap" (click)="openSearch()" lines="none">
|
||||||
<ion-icon name="fas-search" slot="start" aria-hidden="true"></ion-icon>
|
<ion-icon name="fas-search" slot="start" aria-hidden="true"></ion-icon>
|
||||||
<ion-label>
|
<ion-label>
|
||||||
<h2>{{ 'core.courses.searchcourses' | translate}}</h2>
|
<h2>{{ 'core.courses.searchcourses' | translate}}</h2>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
ion-item ion-icon {
|
ion-item ion-icon {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: var(--small-radius);
|
border-radius: var(--module-icon-radius);
|
||||||
padding: 0.7rem;
|
padding: 0.7rem;
|
||||||
background-color: $gray-100;
|
background-color: $gray-100;
|
||||||
line-height: var(--size);
|
line-height: var(--size);
|
||||||
|
@ -10,7 +10,7 @@ ion-item ion-icon {
|
||||||
@include margin-horizontal(null, var(--margin-end));
|
@include margin-horizontal(null, var(--margin-end));
|
||||||
}
|
}
|
||||||
|
|
||||||
core-course-module.core-sitehome-news ::ng-deep ion-card {
|
core-course-module.core-sitehome-news ::ng-deep ion-card {
|
||||||
--border-width: 0;
|
--border-width: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
|
@ -1541,7 +1541,6 @@ export class CoreUtilsProvider {
|
||||||
/**
|
/**
|
||||||
* Debounce a function so consecutive calls are ignored until a certain time has passed since the last call.
|
* Debounce a function so consecutive calls are ignored until a certain time has passed since the last call.
|
||||||
*
|
*
|
||||||
* @param context The context to apply to the function.
|
|
||||||
* @param fn Function to debounce.
|
* @param fn Function to debounce.
|
||||||
* @param delay Time that must pass until the function is called.
|
* @param delay Time that must pass until the function is called.
|
||||||
* @return Debounced function.
|
* @return Debounced function.
|
||||||
|
@ -1558,6 +1557,31 @@ export class CoreUtilsProvider {
|
||||||
return debounced;
|
return debounced;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throttle a function so consecutive calls are ignored until a certain time has passed since the last executed call.
|
||||||
|
*
|
||||||
|
* @param fn Function to throttle.
|
||||||
|
* @param duration Time that must pass until the function is called.
|
||||||
|
* @return Throttled function.
|
||||||
|
*/
|
||||||
|
throttle<T extends unknown[]>(fn: (...args: T) => unknown, duration: number): (...args: T) => void {
|
||||||
|
let shouldWait = false;
|
||||||
|
|
||||||
|
const throttled = (...args: T): void => {
|
||||||
|
if (!shouldWait) {
|
||||||
|
fn.apply(null, args);
|
||||||
|
|
||||||
|
shouldWait = true;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
shouldWait = false;
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return throttled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the app can scan QR codes.
|
* Check whether the app can scan QR codes.
|
||||||
*
|
*
|
||||||
|
|
|
@ -699,7 +699,7 @@ core-rich-text-editor .core-rte-editor {
|
||||||
padding: .25em .4em;
|
padding: .25em .4em;
|
||||||
font-size: 75%;
|
font-size: 75%;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1.1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
|
|
|
@ -189,6 +189,7 @@ ion-button core-format-text .core-format-text-content {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
display: block;
|
display: block;
|
||||||
|
line-height: 1.2;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-button > * {
|
ion-button > * {
|
||||||
|
@ -217,6 +218,10 @@ ion-button ion-spinner {
|
||||||
--color: inherit !important;
|
--color: inherit !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-button:not(.button-has-icon-only) > ion-icon {
|
||||||
|
min-width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
@each $color-name, $unused in $colors {
|
@each $color-name, $unused in $colors {
|
||||||
.text-#{$color-name},
|
.text-#{$color-name},
|
||||||
p.text-#{$color-name} {
|
p.text-#{$color-name} {
|
||||||
|
@ -850,14 +855,22 @@ ion-select-popover ion-item.core-select-option-title {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-badge {
|
||||||
|
line-height: 1.1;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: var(--big-radius);
|
||||||
|
}
|
||||||
|
|
||||||
ion-chip {
|
ion-chip {
|
||||||
line-height: 1.1;
|
line-height: 1.1;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
height: 24px;
|
min-height: 24px;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
ion-icon {
|
ion-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
min-width: 16px;
|
||||||
@include margin(0, 8px, 0, 0);
|
@include margin(0, 8px, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,6 +882,10 @@ ion-chip {
|
||||||
color: var(--ion-color-base);
|
color: var(--ion-color-base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ion-label {
|
||||||
|
white-space: normal !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-searchbar {
|
ion-searchbar {
|
||||||
|
|
|
@ -58,6 +58,11 @@
|
||||||
|
|
||||||
--brand-color: var(--brand);
|
--brand-color: var(--brand);
|
||||||
|
|
||||||
|
--small-radius: 4px;
|
||||||
|
--medium-radius: 8px;
|
||||||
|
--big-radius: 16px;
|
||||||
|
--huge-radius: 24px;
|
||||||
|
|
||||||
// Accessibility vars.
|
// Accessibility vars.
|
||||||
--a11y-min-target-size: 44px;
|
--a11y-min-target-size: 44px;
|
||||||
--a11y-focus-color: var(--primary);
|
--a11y-focus-color: var(--primary);
|
||||||
|
@ -65,6 +70,7 @@
|
||||||
--zoom-level: 100%;
|
--zoom-level: 100%;
|
||||||
|
|
||||||
--module-icon-size: 24px;
|
--module-icon-size: 24px;
|
||||||
|
--module-icon-radius: var(--medium-radius);
|
||||||
|
|
||||||
--ion-background-color: var(--background-color);
|
--ion-background-color: var(--background-color);
|
||||||
--ion-background-color-rgb: #{$background-color-rgb};
|
--ion-background-color-rgb: #{$background-color-rgb};
|
||||||
|
@ -75,11 +81,6 @@
|
||||||
--ion-text-color-rgb: #{$text-color-rgb};
|
--ion-text-color-rgb: #{$text-color-rgb};
|
||||||
--subdued-text-color: var(--gray-700);
|
--subdued-text-color: var(--gray-700);
|
||||||
|
|
||||||
--small-radius: 4px;
|
|
||||||
--medium-radius: 8px;
|
|
||||||
--big-radius: 16px;
|
|
||||||
--huge-radius: 24px;
|
|
||||||
|
|
||||||
--ion-card-color: var(--text-color);
|
--ion-card-color: var(--text-color);
|
||||||
ion-card {
|
ion-card {
|
||||||
--border-width: 1px;
|
--border-width: 1px;
|
||||||
|
|
Loading…
Reference in New Issue