Merge pull request #3154 from crazyserver/MOBILE-3814

Mobile 3814
main
Dani Palou 2022-03-03 09:18:30 +01:00 committed by GitHub
commit aca867cd53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
75 changed files with 346 additions and 336 deletions

View File

@ -292,6 +292,7 @@ module.exports = {
'@angular-eslint/template/no-positive-tabindex': 'error', '@angular-eslint/template/no-positive-tabindex': 'error',
'@angular-eslint/template/accessibility-table-scope': 'error', '@angular-eslint/template/accessibility-table-scope': 'error',
'@angular-eslint/template/accessibility-valid-aria': 'error', '@angular-eslint/template/accessibility-valid-aria': 'error',
'@angular-eslint/template/no-duplicate-attributes': 'error',
}, },
}, },
{ {

View File

@ -20,10 +20,10 @@
"issuerurl": "Issuer URL", "issuerurl": "Issuer URL",
"language": "Language", "language": "Language",
"noalignment": "This badge does not have any external skills or standards specified.", "noalignment": "This badge does not have any external skills or standards specified.",
"nobadges": "There are no badges available.", "nobadges": "There are currently no badges available for users to earn.",
"norelated": "This badge does not have any related badges.", "norelated": "This badge does not have any related badges.",
"recipientdetails": "Recipient details", "recipientdetails": "Recipient details",
"relatedbages": "Related badges", "relatedbages": "Related badges",
"version": "Version", "version": "Version",
"warnexpired": "(This badge has expired!)" "warnexpired": "(This badge has expired!)"
} }

View File

@ -5,7 +5,7 @@
<div slot="end" class="flex-row"> <div slot="end" class="flex-row">
<!-- Download all courses. --> <!-- Download all courses. -->
<div *ngIf="downloadCoursesEnabled && filteredCourses.length > 1" class="core-button-spinner"> <div *ngIf="downloadCoursesEnabled && filteredCourses.length > 1" class="core-button-spinner">
<ion-button *ngIf="!prefetchCoursesData.loading" fill="clear" color="dark" (click)="prefetchCourses()" <ion-button *ngIf="!prefetchCoursesData.loading" fill="clear" (click)="prefetchCourses()"
[attr.aria-label]="prefetchCoursesData.statusTranslatable | translate"> [attr.aria-label]="prefetchCoursesData.statusTranslatable | translate">
<ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"> <ion-icon [name]="prefetchCoursesData.icon" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>

View File

@ -53,7 +53,7 @@
</ion-row> </ion-row>
</ion-col> </ion-col>
<ion-col class="addon-block-timeline-activity-action ion-no-padding" *ngIf="event.action?.actionable"> <ion-col class="addon-block-timeline-activity-action ion-no-padding" *ngIf="event.action?.actionable">
<ion-button fill="outline" color="medium" (click)="action($event, event.action.url)" [title]="event.action.name"> <ion-button fill="outline" (click)="action($event, event.action.url)" [title]="event.action.name">
{{event.action.name}} {{event.action.name}}
<ion-badge slot="end" class="ion-margin-start" *ngIf="event.action.showitemcount"> <ion-badge slot="end" class="ion-margin-start" *ngIf="event.action.showitemcount">
{{event.action.itemcount}} {{event.action.itemcount}}

View File

@ -118,7 +118,7 @@
<ion-label> <ion-label>
<p class="item-heading">{{ 'addon.calendar.reminders' | translate }}</p> <p class="item-heading">{{ 'addon.calendar.reminders' | translate }}</p>
</ion-label> </ion-label>
<ion-button fill="clear" color="dark" (click)="addReminder()" slot="end" <ion-button fill="clear" (click)="addReminder()" slot="end"
[attr.aria-label]="'addon.calendar.setnewreminder' | translate"> [attr.aria-label]="'addon.calendar.setnewreminder' | translate">
<ion-icon name="fas-plus" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-plus" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -120,7 +120,7 @@
</ion-item> </ion-item>
<ion-item *ngIf="moduleUrl"> <ion-item *ngIf="moduleUrl">
<ion-label> <ion-label>
<ion-button expand="block" color="primary" [href]="moduleUrl" core-link capture="true"> <ion-button expand="block" [href]="moduleUrl" core-link capture="true">
{{ 'addon.calendar.gotoactivity' | translate }} {{ 'addon.calendar.gotoactivity' | translate }}
</ion-button> </ion-button>
</ion-label> </ion-label>
@ -148,7 +148,7 @@
<ng-container *ngIf="event.timestart > currentTime"> <ng-container *ngIf="event.timestart > currentTime">
<ion-item> <ion-item>
<ion-label> <ion-label>
<ion-button expand="block" color="primary" (click)="addReminder()"> <ion-button expand="block" (click)="addReminder()">
{{ 'addon.calendar.setnewreminder' | translate }} {{ 'addon.calendar.setnewreminder' | translate }}
</ion-button> </ion-button>
</ion-label> </ion-label>

View File

@ -28,18 +28,19 @@
<core-context-menu-item [hidden]="isSelf || !showInfo || !isGroup" [priority]="1000" <core-context-menu-item [hidden]="isSelf || !showInfo || !isGroup" [priority]="1000"
[content]="'addon.messages.groupinfo' | translate" (action)="viewInfo()" iconAction="fas-info-circle"> [content]="'addon.messages.groupinfo' | translate" (action)="viewInfo()" iconAction="fas-info-circle">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item [hidden]="!groupMessagingEnabled || !conversation" [priority]="800" [content]="(conversation && conversation.isfavourite ? 'addon.messages.removefromfavourites' : <core-context-menu-item [hidden]="!groupMessagingEnabled || !conversation" [priority]="800" (action)="changeFavourite($event)"
'addon.messages.addtofavourites') | translate" (action)="changeFavourite($event)" [closeOnClick]="false" [closeOnClick]="false" [content]="(conversation && conversation.isfavourite ? 'addon.messages.removefromfavourites' :
[iconAction]="favouriteIcon" [iconSlash]="favouriteIconSlash"></core-context-menu-item> 'addon.messages.addtofavourites') | translate" [iconAction]="favouriteIcon" [iconSlash]="favouriteIconSlash">
</core-context-menu-item>
<core-context-menu-item [hidden]="isSelf || !otherMember || otherMember.isblocked" [priority]="700" <core-context-menu-item [hidden]="isSelf || !otherMember || otherMember.isblocked" [priority]="700"
[content]="'addon.messages.blockuser' | translate" (action)="blockUser()" [iconAction]="blockIcon"> [content]="'addon.messages.blockuser' | translate" (action)="blockUser()" [iconAction]="blockIcon">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item [hidden]="isSelf || !otherMember || !otherMember.isblocked" [priority]="700" <core-context-menu-item [hidden]="isSelf || !otherMember || !otherMember.isblocked" [priority]="700"
[content]="'addon.messages.unblockuser' | translate" (action)="unblockUser()" [iconAction]="blockIcon"> [content]="'addon.messages.unblockuser' | translate" (action)="unblockUser()" [iconAction]="blockIcon">
</core-context-menu-item> </core-context-menu-item>
<core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' : <core-context-menu-item [hidden]="isSelf || !muteEnabled || !conversation" [priority]="600" (action)="changeMute($event)"
'addon.messages.muteconversation') | translate" (action)="changeMute($event)" [closeOnClick]="false" [closeOnClick]="false" [content]="(conversation && conversation.ismuted ? 'addon.messages.unmuteconversation' :
[iconAction]="muteIcon"></core-context-menu-item> 'addon.messages.muteconversation') | translate" [iconAction]="muteIcon"></core-context-menu-item>
<core-context-menu-item [hidden]="!canDelete || !messages || !messages.length" [priority]="400" <core-context-menu-item [hidden]="!canDelete || !messages || !messages.length" [priority]="400"
[content]="'addon.messages.showdeletemessages' | translate" iconAction="toggle" [(toggle)]="showDelete"> [content]="'addon.messages.showdeletemessages' | translate" iconAction="toggle" [(toggle)]="showDelete">
</core-context-menu-item> </core-context-menu-item>
@ -157,7 +158,7 @@
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="confirmContactRequest()"> <ion-button expand="block" class="ion-text-wrap ion-margin-bottom" (click)="confirmContactRequest()">
{{ 'addon.messages.acceptandaddcontact' | translate }} {{ 'addon.messages.acceptandaddcontact' | translate }}
</ion-button> </ion-button>
<ion-button expand="block" class="ion-text-wrap ion-margin-bottom" color="light" (click)="declineContactRequest()"> <ion-button expand="block" class="ion-text-wrap ion-margin-bottom" fill="outline" (click)="declineContactRequest()">
{{ 'addon.messages.decline' | translate }} {{ 'addon.messages.decline' | translate }}
</ion-button> </ion-button>
</div> </div>

View File

@ -146,9 +146,11 @@
<!-- Template to render a list of conversations. --> <!-- Template to render a list of conversations. -->
<ng-template #conversationsTemplate let-conversations="conversations"> <ng-template #conversationsTemplate let-conversations="conversations">
<ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let conversation of conversations" button detail="false" <ion-item class="ion-text-wrap addon-message-discussion" *ngFor="let conversation of conversations" button detail="false"
[attr.aria-label]="conversation.name" (click)="gotoConversation(conversation.id, conversation.userid)" [attr.aria-current]="((conversation.id && conversation.id == selectedConversationId) || (click)="gotoConversation(conversation.id, conversation.userid)"
(conversation.userid && conversation.userid == selectedUserId)) ? 'page': 'false'" [attr.aria-current]="((conversation.id &&
id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}"> conversation.id == selectedConversationId) || (conversation.userid && conversation.userid == selectedUserId)) ? 'page': 'false'"
id="addon-message-conversation-{{ conversation.id ? conversation.id : 'user-' + conversation.userid }}"
[attr.aria-label]="conversation.name">
<!-- Group conversation image. --> <!-- Group conversation image. -->
<ion-avatar slot="start" *ngIf="conversation.type == typeGroup"> <ion-avatar slot="start" *ngIf="conversation.type == typeGroup">
<img [src]="conversation.imageurl" [alt]="conversation.name" core-external-content <img [src]="conversation.imageurl" [alt]="conversation.name" core-external-content

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="hasOffline"> [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
<ion-list inset="true" description *ngIf="assign && assign.introattachments && assign.introattachments.length"> <ion-list inset="true" description *ngIf="assign && assign.introattachments && assign.introattachments.length">
<core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId"> <core-file *ngFor="let file of assign.introattachments" [file]="file" [component]="component" [componentId]="componentId">
</core-file> </core-file>
@ -127,6 +127,5 @@
</addon-mod-assign-submission> </addon-mod-assign-submission>
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>

View File

@ -103,27 +103,26 @@
<ion-label> <ion-label>
<div *ngIf="!unsupportedEditPlugins.length && !showErrorStatementEdit"> <div *ngIf="!unsupportedEditPlugins.length && !showErrorStatementEdit">
<!-- If has offline data, show edit. --> <!-- If has offline data, show edit. -->
<ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="hasOffline" (click)="goToEdit()"> <ion-button expand="block" class="ion-text-wrap" *ngIf="hasOffline" (click)="goToEdit()">
{{ 'addon.mod_assign.editsubmission' | translate }} {{ 'addon.mod_assign.editsubmission' | translate }}
</ion-button> </ion-button>
<!-- If no submission or is new, show add submission. --> <!-- If no submission or is new, show add submission. -->
<ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="!hasOffline && <ion-button expand="block" class="ion-text-wrap" (click)="goToEdit()" *ngIf="!hasOffline &&
(!userSubmission || !userSubmission!.status || userSubmission!.status == statusNew)" (!userSubmission || !userSubmission!.status || userSubmission!.status == statusNew)">
(click)="goToEdit()">
{{ 'addon.mod_assign.addsubmission' | translate }} {{ 'addon.mod_assign.addsubmission' | translate }}
</ion-button> </ion-button>
<!-- If reopened, show addfromprevious and addnewattempt. --> <!-- If reopened, show addfromprevious and addnewattempt. -->
<ng-container *ngIf="!hasOffline && userSubmission?.status == statusReopened"> <ng-container *ngIf="!hasOffline && userSubmission?.status == statusReopened">
<ion-button *ngIf="!isPreviousAttemptEmpty" expand="block" class="ion-text-wrap" color="primary" <ion-button *ngIf="!isPreviousAttemptEmpty" expand="block" class="ion-text-wrap" (click)="copyPrevious()">
(click)="copyPrevious()">
{{ 'addon.mod_assign.addnewattemptfromprevious' | translate }} {{ 'addon.mod_assign.addnewattemptfromprevious' | translate }}
</ion-button> </ion-button>
<ion-button expand="block" class="ion-text-wrap" color="primary" (click)="goToEdit()"> <ion-button expand="block" class="ion-text-wrap" (click)="goToEdit()">
{{ 'addon.mod_assign.addnewattempt' | translate }} {{ 'addon.mod_assign.addnewattempt' | translate }}
</ion-button> </ion-button>
</ng-container> </ng-container>
<!-- Else show editsubmission. --> <!-- Else show editsubmission. -->
<ion-button expand="block" class="ion-text-wrap" color="primary" *ngIf="!hasOffline && userSubmission && userSubmission!.status && <ion-button expand="block" class="ion-text-wrap" *ngIf="!hasOffline &&
userSubmission && userSubmission!.status &&
userSubmission!.status != statusNew && userSubmission!.status != statusNew &&
userSubmission!.status != statusReopened" (click)="goToEdit()"> userSubmission!.status != statusReopened" (click)="goToEdit()">
{{ 'addon.mod_assign.editsubmission' | translate }} {{ 'addon.mod_assign.editsubmission' | translate }}

View File

@ -10,7 +10,7 @@
</ion-label> </ion-label>
<div slot="end"> <div slot="end">
<div class="ion-text-end"> <div class="ion-text-end">
<ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" color="dark" [attr.aria-label]="'core.edit' | translate"> <ion-button fill="clear" *ngIf="canEdit" (click)="editComment()" [attr.aria-label]="'core.edit' | translate">
<ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</div> </div>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId"> [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ng-container *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)"> <ng-container *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
@ -114,7 +114,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -1,15 +1,15 @@
{ {
"end_session_confirm": "Are you sure you want to end the virtual classroom session?", "end_session_confirm": "Are you sure you want to end the session?",
"end_session_confirm_title": "Really end session?", "end_session_confirm_title": "Really end session?",
"mod_form_field_closingtime": "Join closed", "mod_form_field_closingtime": "Close",
"mod_form_field_openingtime": "Join open", "mod_form_field_openingtime": "Open",
"userlimitreached": "The number of users allowed in a meeting has been reached.", "userlimitreached": "The number of users allowed in a session has been reached.",
"view_conference_action_end": "End session", "view_conference_action_end": "End session",
"view_conference_action_join": "Join session", "view_conference_action_join": "Join session",
"view_error_unable_join_student": "Unable to connect to the BigBlueButton server. Please contact your Teacher or the Administrator.", "view_error_unable_join_student": "Unable to connect to the BigBlueButton server.",
"view_groups_selection_warning": "There is a conference room for each group and you have access to more than one. Be sure to select the correct one.", "view_groups_selection_warning": "There is a room for each group and you have access to more than one. Be sure to select the correct one.",
"view_message_conference_in_progress": "This conference is in progress.", "view_message_conference_in_progress": "The session is in progress.",
"view_message_conference_room_ready": "This conference room is ready. You can join the session now.", "view_message_conference_room_ready": "This room is ready. You can join the session now.",
"view_message_moderator": "moderator", "view_message_moderator": "moderator",
"view_message_moderators": "moderators", "view_message_moderators": "moderators",
"view_message_session_started_at": "This session started at", "view_message_session_started_at": "This session started at",

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId"> [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-list> <ion-list>
@ -41,7 +41,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId"> [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-card *ngIf="chatInfo" class="core-info-card"> <ion-card *ngIf="chatInfo" class="core-info-card">
@ -26,12 +26,12 @@
<div collapsible-footer *ngIf="!showLoading" slot="fixed"> <div collapsible-footer *ngIf="!showLoading" slot="fixed">
<div class="list-item-limited-width" *ngIf="chat"> <div class="list-item-limited-width" *ngIf="chat">
<ion-button class="ion-margin ion-text-wrap" expand="block" color="primary" (click)="enterChat()"> <ion-button class="ion-margin ion-text-wrap" expand="block" (click)="enterChat()">
{{ 'addon.mod_chat.enterchat' | translate }} {{ 'addon.mod_chat.enterchat' | translate }}
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,7 @@
<div class="list-item-limited-width"> <div class="list-item-limited-width">
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="hasOffline"> [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<!-- Activity availability messages --> <!-- Activity availability messages -->
@ -146,7 +146,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -1,24 +1,27 @@
<ion-button *ngIf="action == 'more'" fill="clear" (click)="viewEntry()" [attr.aria-label]="'addon.mod_data.more' | translate"> <ion-button size="small" *ngIf="action == 'more'" fill="clear" (click)="viewEntry()" [attr.aria-label]="'addon.mod_data.more' | translate">
<ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-search" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'edit'" fill="clear" (click)="editEntry()" [attr.aria-label]="'core.edit' | translate"> <ion-button size="small" *ngIf="action == 'edit'" fill="clear" (click)="editEntry()" [attr.aria-label]="'core.edit' | translate">
<ion-icon name="fas-cog" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-cog" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'delete' && !entry.deleted" fill="clear" (click)="deleteEntry()" [attr.aria-label]="'core.delete' | translate"> <ion-button size="small" *ngIf="action == 'delete' && !entry.deleted" fill="clear" color="danger" (click)="deleteEntry()"
[attr.aria-label]="'core.delete' | translate">
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'delete' && entry.deleted" fill="clear" (click)="undoDelete()" [attr.aria-label]="'core.restore' | translate"> <ion-button size="small" *ngIf="action == 'delete' && entry.deleted" fill="clear" color="danger" (click)="undoDelete()"
[attr.aria-label]="'core.restore' | translate">
<ion-icon name="fas-undo-alt" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-undo-alt" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'approve'" fill="clear" (click)="approveEntry()" [attr.aria-label]="'addon.mod_data.approve' | translate"> <ion-button size="small" *ngIf="action == 'approve'" fill="clear" (click)="approveEntry()"
[attr.aria-label]="'addon.mod_data.approve' | translate">
<ion-icon name="fas-thumbs-up" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-thumbs-up" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="action == 'disapprove'" fill="clear" (click)="disapproveEntry()" <ion-button size="small" *ngIf="action == 'disapprove'" fill="clear" (click)="disapproveEntry()"
[attr.aria-label]="'addon.mod_data.disapprove' | translate"> [attr.aria-label]="'addon.mod_data.disapprove' | translate">
<ion-icon name="far-thumbs-down" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="far-thumbs-down" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -22,7 +22,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-item class="ion-text-wrap core-group-selector" *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)"> <ion-item class="ion-text-wrap core-group-selector" *ngIf="groupInfo && (groupInfo.separateGroups || groupInfo.visibleGroups)">
@ -72,8 +72,8 @@
<!-- Reset search. --> <!-- Reset search. -->
<ng-container *ngIf="search.searching && !isEmpty"> <ng-container *ngIf="search.searching && !isEmpty">
<ion-item (click)="searchReset()" button detail="false"> <ion-item (click)="searchReset()" button detail="false" *ngIf="!foundRecordsTranslationData">
<ion-label color="primary"> <ion-label color="info">
{{ 'addon.mod_data.resetsettings' | translate}} {{ 'addon.mod_data.resetsettings' | translate}}
</ion-label> </ion-label>
</ion-item> </ion-item>
@ -120,8 +120,7 @@
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd">

View File

@ -64,7 +64,7 @@
<div collapsible-footer *ngIf="entryLoaded && hasPrevious || hasNext" slot="fixed"> <div collapsible-footer *ngIf="entryLoaded && hasPrevious || hasNext" slot="fixed">
<ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap"> <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap">
<ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto"> <ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto">
<ion-button [disabled]="!hasPrevious" fill="clear" color="dark" [attr.aria-label]="'core.previous' | translate" <ion-button [disabled]="!hasPrevious" fill="clear" [attr.aria-label]="'core.previous' | translate"
(click)="gotoEntry(offset! -1)"> (click)="gotoEntry(offset! -1)">
<ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
@ -72,7 +72,7 @@
<ion-col class="ion-text-center"> <ion-col class="ion-text-center">
</ion-col> </ion-col>
<ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto"> <ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto">
<ion-button [disabled]="!hasNext" fill="clear" color="dark" [attr.aria-label]=" 'core.next' | translate" <ion-button [disabled]="!hasNext" fill="clear" [attr.aria-label]=" 'core.next' | translate"
(click)="gotoEntry(offset! + 1)"> (click)="gotoEntry(offset! + 1)">
<ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="hasOffline"> [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<core-tabs [hideUntil]="tabsReady" [selectedIndex]="firstSelectedTab"> <core-tabs [hideUntil]="tabsReady" [selectedIndex]="firstSelectedTab">
@ -52,7 +52,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -32,6 +32,6 @@
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id"
(completionChanged)="onCompletionChange()"> (completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>

View File

@ -14,7 +14,8 @@
<core-loading [hideUntil]="!showLoading && discussions && discussions.loaded"> <core-loading [hideUntil]="!showLoading && discussions && discussions.loaded">
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="forum && forum.type != 'single' && description" [component]="component" <core-course-module-info [module]="module" [description]="forum && forum.type != 'single' && description" [component]="component"
[componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"
(completionChanged)="onCompletionChange()">
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
{{descriptionNote}} {{descriptionNote}}
@ -56,7 +57,7 @@
[courseId]="courseId"> [courseId]="courseId">
</core-format-text> </core-format-text>
</p> </p>
<ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear" color="dark" <ion-button *ngIf="canPin || discussion.canlock || discussion.canfavourite" fill="clear"
[attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)"> [attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event, discussion)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
@ -114,8 +115,7 @@
</ng-container> </ng-container>
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="forum && canAddDiscussion"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="forum && canAddDiscussion">

View File

@ -19,8 +19,8 @@
[attr.aria-label]="'addon.mod_forum.unread' | translate"> [attr.aria-label]="'addon.mod_forum.unread' | translate">
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon> <ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
</ion-note> </ion-note>
<ion-button *ngIf="optionsMenuEnabled" fill="clear" color="dark" <ion-button *ngIf="optionsMenuEnabled" fill="clear" [attr.aria-label]="('core.displayoptions' | translate)"
[attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event)"> (click)="showOptionsMenu($event)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true">
</ion-icon> </ion-icon>
</ion-button> </ion-button>
@ -47,8 +47,8 @@
[attr.aria-label]="'addon.mod_forum.unread' | translate"> [attr.aria-label]="'addon.mod_forum.unread' | translate">
<ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon> <ion-icon name="fas-circle" color="primary" aria-hidden="true"></ion-icon>
</ion-note> </ion-note>
<ion-button *ngIf="optionsMenuEnabled" fill="clear" color="dark" <ion-button *ngIf="optionsMenuEnabled" fill="clear" [attr.aria-label]="('core.displayoptions' | translate)"
[attr.aria-label]="('core.displayoptions' | translate)" (click)="showOptionsMenu($event)"> (click)="showOptionsMenu($event)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ng-container> </ng-container>

View File

@ -27,7 +27,8 @@
<core-loading [hideUntil]="!showLoading"> <core-loading [hideUntil]="!showLoading">
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info *ngIf="!isSearch" [module]="module" [description]="description" [component]="component" <core-course-module-info *ngIf="!isSearch" [module]="module" [description]="description" [component]="component"
[componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"> [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline || hasOfflineRatings"
(completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-list *ngIf="!isSearch && entries && entries.offlineEntries.length > 0"> <ion-list *ngIf="!isSearch && entries && entries.offlineEntries.length > 0">
@ -72,8 +73,7 @@
</core-infinite-loading> </core-infinite-loading>
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canAdd">

View File

@ -20,7 +20,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="hasOffline"> [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<!-- Offline disabled. --> <!-- Offline disabled. -->
@ -68,6 +68,5 @@
</core-h5p-iframe> </core-h5p-iframe>
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId"> [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-list> <ion-list>
@ -38,7 +38,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -14,7 +14,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="hasOffline"> [courseId]="courseId" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<!-- Prevent access messages. Only show the first one. --> <!-- Prevent access messages. Only show the first one. -->
@ -214,7 +214,7 @@
<ng-container *ngTemplateOutlet="buttons"></ng-container> <ng-container *ngTemplateOutlet="buttons"></ng-container>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="displayDescription && description" [component]="component" <core-course-module-info [module]="module" [description]="displayDescription && description" [component]="component"
[componentId]="componentId" [courseId]="courseId"> [componentId]="componentId" [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<div collapsible-footer *ngIf="!showLoading" slot="fixed"> <div collapsible-footer *ngIf="!showLoading" slot="fixed">
@ -21,7 +21,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="displayDescription && description" [component]="component" <core-course-module-info [module]="module" [description]="displayDescription && description" [component]="component"
[componentId]="componentId" [courseId]="courseId"> [componentId]="componentId" [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-card class="core-warning-card" *ngIf="warning"> <ion-card class="core-warning-card" *ngIf="warning">
@ -32,6 +32,5 @@
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="buttonText && hasOffline"> [courseId]="courseId" [hasDataToSync]="buttonText && hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<!-- Access rules description messages. --> <!-- Access rules description messages. -->
@ -213,7 +213,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>

View File

@ -116,7 +116,7 @@
<div collapsible-footer *ngIf="loaded && numPages > 1" slot="fixed"> <div collapsible-footer *ngIf="loaded && numPages > 1" slot="fixed">
<ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap"> <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap">
<ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto" *ngIf="!showAll"> <ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto" *ngIf="!showAll">
<ion-button [disabled]="previousPage < 0" fill="clear" color="dark" [attr.aria-label]="'core.previous' | translate" <ion-button [disabled]="previousPage < 0" fill="clear" [attr.aria-label]="'core.previous' | translate"
(click)="changePage(previousPage)"> (click)="changePage(previousPage)">
<ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
@ -129,7 +129,7 @@
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto" *ngIf="!showAll"> <ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto" *ngIf="!showAll">
<ion-button [disabled]="nextPage >= numPages" fill="clear" color="dark" [attr.aria-label]="'core.next' | translate" <ion-button [disabled]="nextPage >= numPages" fill="clear" [attr.aria-label]="'core.next' | translate"
(click)="changePage(nextPage)"> (click)="changePage(nextPage)">
<ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [courseId]="courseId" [description]="displayDescription && description" <core-course-module-info [module]="module" [courseId]="courseId" [description]="displayDescription && description"
[component]="component" [componentId]="componentId"> [component]="component" [componentId]="componentId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-card class="core-warning-card" *ngIf="warning"> <ion-card class="core-warning-card" *ngIf="warning">
@ -98,7 +98,7 @@
{{ 'core.openwith' | translate }} {{ 'core.openwith' | translate }}
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId" [hasDataToSync]="!errorMessage && hasOffline"> [courseId]="courseId" [hasDataToSync]="!errorMessage && hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<!-- Warning message. --> <!-- Warning message. -->
@ -221,7 +221,7 @@
</ion-item> </ion-item>
</ng-container> </ng-container>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,8 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="survey && !survey.surveydone && !hasOffline && description" <core-course-module-info [module]="module" [description]="survey && !survey.surveydone && !hasOffline && description"
[component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"> [component]="component" [componentId]="componentId" [courseId]="courseId" [hasDataToSync]="hasOffline"
(completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<!-- Survey already done --> <!-- Survey already done -->
@ -130,7 +131,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -10,7 +10,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="displayDescription && description" [component]="component" <core-course-module-info [module]="module" [description]="displayDescription && description" [component]="component"
[componentId]="componentId" [courseId]="courseId"> [componentId]="componentId" [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<div *ngIf="shouldIframe || (shouldEmbed && isOther)" class="addon-mod_url-embedded-url"> <div *ngIf="shouldIframe || (shouldEmbed && isOther)" class="addon-mod_url-embedded-url">
@ -44,7 +44,7 @@
{{ 'addon.mod_url.accessurl' | translate }} {{ 'addon.mod_url.accessurl' | translate }}
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -31,7 +31,7 @@
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId" <core-course-module-info [module]="module" [description]="description" [component]="component" [componentId]="componentId"
[courseId]="courseId"> [courseId]="courseId" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<div *ngIf="pageIsOffline || hasOffline || pageWarning"> <div *ngIf="pageIsOffline || hasOffline || pageWarning">
@ -71,8 +71,7 @@
</div> </div>
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="showLoading" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()">
</core-course-module-navigation> </core-course-module-navigation>
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canEdit"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="canEdit">

View File

@ -13,8 +13,8 @@
{{ 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' | translate : {'$a': field.dimtitle } }} {{ 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' | translate : {'$a': field.dimtitle } }}
</span> </span>
</ion-label> </ion-label>
<ion-select [(ngModel)]="selectedValues[n].grade" interface="action-sheet" [interfaceOptions]="{header: 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' | <ion-select [interfaceOptions]="{header: 'addon.mod_workshop_assessment_accumulative.dimensiongradefor' |
translate : {'$a': field.dimtitle }}"> translate : {'$a': field.dimtitle }}" [(ngModel)]="selectedValues[n].grade" interface="action-sheet">
<ion-select-option *ngFor="let grade of field.grades" [value]="grade.value">{{grade.label}}</ion-select-option> <ion-select-option *ngFor="let grade of field.grades" [value]="grade.value">{{grade.label}}</ion-select-option>
</ion-select> </ion-select>
<core-input-errors *ngIf="fieldErrors['grade_' + n]" [errorText]="fieldErrors['grade_' + n]"> <core-input-errors *ngIf="fieldErrors['grade_' + n]" [errorText]="fieldErrors['grade_' + n]">

View File

@ -9,7 +9,7 @@
<core-loading [hideUntil]="!showLoading" class="list-item-limited-width"> <core-loading [hideUntil]="!showLoading" class="list-item-limited-width">
<!-- Activity info. --> <!-- Activity info. -->
<core-course-module-info [module]="module" [hasDataToSync]="hasOffline"> <core-course-module-info [module]="module" [hasDataToSync]="hasOffline" (completionChanged)="onCompletionChange()">
</core-course-module-info> </core-course-module-info>
<ion-card *ngIf="phases"> <ion-card *ngIf="phases">
@ -235,7 +235,7 @@
</ion-button> </ion-button>
</div> </div>
<core-course-module-navigation [courseId]="courseId" [currentModule]="module" (completionChanged)="onCompletionChange()"> <core-course-module-navigation [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>
</div> </div>
</core-loading> </core-loading>

View File

@ -34,9 +34,9 @@
</span> </span>
</ion-label> </ion-label>
<core-rich-text-editor [control]="editForm.controls['content']" name="content" <core-rich-text-editor [control]="editForm.controls['content']" name="content"
[placeholder]="'addon.mod_workshop.submissioncontent' | translate" name="content" [component]="component" [placeholder]="'addon.mod_workshop.submissioncontent' | translate" [component]="component" [componentId]="componentId"
[componentId]="componentId" [autoSave]="true" contextLevel="module" [contextInstanceId]="module.id" [autoSave]="true" contextLevel="module" [contextInstanceId]="module.id" elementId="content_editor"
elementId="content_editor" [draftExtraParams]="editorExtraParams"></core-rich-text-editor> [draftExtraParams]="editorExtraParams"></core-rich-text-editor>
</ion-item> </ion-item>
<core-attachments *ngIf="fileAvailable" [files]="attachments" [maxSize]="workshop.maxbytes" <core-attachments *ngIf="fileAvailable" [files]="attachments" [maxSize]="workshop.maxbytes"

View File

@ -19,7 +19,7 @@
<p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totaldownloads' | translate }}</p> <p class="item-heading ion-text-wrap">{{ 'addon.storagemanager.totaldownloads' | translate }}</p>
<ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge> <ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge>
</ion-label> </ion-label>
<ion-button slot="end" (click)="deleteForCourse()" [disabled]="totalSize == 0" color="danger" fill="outline"> <ion-button slot="end" (click)="deleteForCourse()" [disabled]="totalSize == 0" color="danger" fill="clear">
<ion-icon name="fas-trash" slot="icon-only" [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: <ion-icon name="fas-trash" slot="icon-only" [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate:
{ name: title }"> { name: title }">
</ion-icon> </ion-icon>
@ -48,7 +48,7 @@
</p> </p>
</ion-label> </ion-label>
<div class="storage-buttons" slot="end" *ngIf="section.totalSize > 0 || downloadEnabled"> <div class="storage-buttons" slot="end" *ngIf="section.totalSize > 0 || downloadEnabled">
<ion-button (click)="deleteForSection(section)" *ngIf="section.totalSize > 0" color="danger" fill="outline"> <ion-button (click)="deleteForSection(section)" *ngIf="section.totalSize > 0" color="danger" fill="clear">
<ion-icon name="fas-trash" slot="icon-only" <ion-icon name="fas-trash" slot="icon-only"
[attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: section.name }"> [attr.aria-label]="'addon.storagemanager.deletedatafrom' | translate: { name: section.name }">
</ion-icon> </ion-icon>

View File

@ -21,7 +21,7 @@
</ion-label> </ion-label>
<ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage($event)" <ion-button fill="clear" color="danger" slot="end" (click)="deleteSiteStorage($event)"
[hidden]="spaceUsage.spaceUsage! + spaceUsage.cacheEntries! <= 0" [hidden]="spaceUsage.spaceUsage! + spaceUsage.cacheEntries! <= 0"
[attr.aria-label]="'addon.storagemanager.deleteallsitedata' | translate" fill="outline"> [attr.aria-label]="'addon.storagemanager.deleteallsitedata' | translate">
<ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-trash" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
@ -37,7 +37,7 @@
<ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge> <ion-badge color="light">{{ totalSize | coreBytesToSize }}</ion-badge>
</ion-label> </ion-label>
<ion-button slot="end" (click)="deleteCompletelyDownloadedCourses($event)" <ion-button slot="end" (click)="deleteCompletelyDownloadedCourses($event)"
[disabled]="completelyDownloadedCourses.length === 0" color="danger" fill="outline"> [disabled]="completelyDownloadedCourses.length === 0" color="danger" fill="clear">
<ion-icon name="fas-trash" slot="icon-only" ariaLabel="{{ 'addon.storagemanager.deletecourses' | translate }}"> <ion-icon name="fas-trash" slot="icon-only" ariaLabel="{{ 'addon.storagemanager.deletecourses' | translate }}">
</ion-icon> </ion-icon>
</ion-button> </ion-button>

View File

@ -1,14 +1,13 @@
<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)" @coreShowHideAnimation
[attr.aria-label]="(statusTranslatable || 'core.download') | translate"> [attr.aria-label]="(statusTranslatable || 'core.download') | translate">
<ion-icon slot="icon-only" name="fas-cloud-download-alt" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" name="fas-cloud-download-alt" 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="primary" @coreShowHideAnimation (click)="download($event, true)" @coreShowHideAnimation [attr.aria-label]="(statusTranslatable || 'core.refresh') | translate">
[attr.aria-label]="(statusTranslatable || 'core.refresh') | translate">
<ion-icon slot="icon-only" name="fam-cloud-refresh" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" name="fam-cloud-refresh" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -12,8 +12,7 @@
(action)="download()"> (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)" [title]="openButtonLabel | translate">
[title]="openButtonLabel | translate">
<ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" [name]="openButtonIcon" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -1,9 +1,9 @@
<ion-button fill="clear" color="dark" (click)="scroll('backward')" [hidden]="scrollPosition === 'hidden'" <ion-button fill="clear" (click)="scroll('backward')" [hidden]="scrollPosition === 'hidden'" [disabled]="scrollPosition === 'start'"
[disabled]="scrollPosition === 'start'" [attr.aria-label]="'core.scrollbackward' | translate" [attr.aria-controls]="targetId"> [attr.aria-label]="'core.scrollbackward' | translate" [attr.aria-controls]="targetId">
<ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
<ion-button fill="clear" color="dark" (click)="scroll('forward')" [hidden]="scrollPosition === 'hidden'" <ion-button fill="clear" (click)="scroll('forward')" [hidden]="scrollPosition === 'hidden'" [disabled]="scrollPosition === 'end'"
[disabled]="scrollPosition === 'end'" [attr.aria-label]="'core.scrollforward' | translate" [attr.aria-controls]="targetId"> [attr.aria-label]="'core.scrollforward' | translate" [attr.aria-controls]="targetId">
<ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -13,8 +13,8 @@
[src]="safeUrl" [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null"> [src]="safeUrl" [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null">
</iframe> </iframe>
<ion-button *ngIf="!loading && displayHelp" color="dark" expand="block" fill="clear" (click)="openIframeHelpModal()" <ion-button *ngIf="!loading && displayHelp" expand="block" fill="clear" (click)="openIframeHelpModal()" aria-haspopup="dialog"
aria-haspopup="dialog" class="core-button-as-link core-iframe-help"> class="core-button-as-link core-iframe-help">
{{ 'core.iframehelp' | translate }} {{ 'core.iframehelp' | translate }}
</ion-button> </ion-button>

View File

@ -24,7 +24,7 @@
<ng-container *ngIf="manage"> <ng-container *ngIf="manage">
<ion-button *ngIf="!editMode" fill="clear" [core-suppress-events] (onClick)="activateEdit($event)" <ion-button *ngIf="!editMode" fill="clear" [core-suppress-events] (onClick)="activateEdit($event)"
[attr.aria-label]="'core.edit' | translate" color="dark"> [attr.aria-label]="'core.edit' | translate">
<ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -1,7 +1,6 @@
<ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap" *ngIf="items.length > 1"> <ion-row class="ion-justify-content-between ion-align-items-center ion-no-padding ion-wrap" *ngIf="items.length > 1">
<ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto"> <ion-col class="ion-text-start ion-no-padding core-navigation-arrow" size="auto">
<ion-button [disabled]="previousIndex < 0" fill="clear" color="dark" [attr.aria-label]="previousTitle" <ion-button [disabled]="previousIndex < 0" fill="clear" [attr.aria-label]="previousTitle" (click)="navigate(previousIndex)">
(click)="navigate(previousIndex)">
<ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
@ -10,7 +9,7 @@
</core-progress-bar> </core-progress-bar>
</ion-col> </ion-col>
<ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto"> <ion-col class="ion-text-end ion-no-padding core-navigation-arrow" size="auto">
<ion-button [disabled]="nextIndex < 0" fill="clear" color="dark" [attr.aria-label]="nextTitle" (click)="navigate(nextIndex)"> <ion-button [disabled]="nextIndex < 0" fill="clear" [attr.aria-label]="nextTitle" (click)="navigate(nextIndex)">
<ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-chevron-right" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>

View File

@ -7,6 +7,6 @@
</textarea> </textarea>
<ion-button fill="clear" size="large" type="submit" [disabled]="!message || sendDisabled" [attr.aria-label]="'core.send' | translate" <ion-button fill="clear" size="large" type="submit" [disabled]="!message || sendDisabled" [attr.aria-label]="'core.send' | translate"
[core-suppress-events] (onClick)="submitForm($event)"> [core-suppress-events] (onClick)="submitForm($event)">
<ion-icon name="send" color="dark" slot="icon-only" aria-hidden="true" flip-rtl></ion-icon> <ion-icon name="send" slot="icon-only" aria-hidden="true" flip-rtl></ion-icon>
</ion-button> </ion-button>
</form> </form>

View File

@ -27,13 +27,13 @@
<ion-buttons class="ion-padding core-course-section-nav-buttons safe-area-padding-horizontal list-item-limited-width" <ion-buttons class="ion-padding core-course-section-nav-buttons safe-area-padding-horizontal list-item-limited-width"
*ngIf="displayCourseIndex && (previousSection || nextSection)"> *ngIf="displayCourseIndex && (previousSection || nextSection)">
<ion-button *ngIf="previousSection" (click)="sectionChanged(previousSection)" color="primary" fill="solid" expand="block" <ion-button *ngIf="previousSection" (click)="sectionChanged(previousSection)" fill="solid" expand="block"
[attr.aria-label]="('core.previous' | translate) + ': ' + previousSection.name"> [attr.aria-label]="('core.previous' | translate) + ': ' + previousSection.name">
<ion-icon name="fas-arrow-left" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-arrow-left" slot="start" aria-hidden="true"></ion-icon>
<core-format-text [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)" color="primary" fill="solid" expand="block" <ion-button *ngIf="nextSection" (click)="sectionChanged(nextSection)" fill="solid" expand="block"
[attr.aria-label]="('core.next' | translate) + ': ' + nextSection.name"> [attr.aria-label]="('core.next' | translate) + ': ' + nextSection.name">
<core-format-text [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>
@ -49,7 +49,7 @@
<!-- Course Index button. --> <!-- Course Index button. -->
<ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && displayCourseIndex"> <ion-fab slot="fixed" core-fab vertical="bottom" horizontal="end" *ngIf="loaded && displayCourseIndex">
<ion-fab-button (click)="openCourseIndex()" [attr.aria-label]="'core.course.courseindex' | translate"> <ion-fab-button (click)="openCourseIndex()" [attr.aria-label]="'core.course.courseindex' | translate" color="secondary">
<ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon> <ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon>
<span class="sr-only">{{'core.course.courseindex' | translate }}</span> <span class="sr-only">{{'core.course.courseindex' | translate }}</span>
</ion-fab-button> </ion-fab-button>

View File

@ -30,8 +30,7 @@ ion-item.core-course-index-all::part(native) {
} }
ion-item.item.item-current { ion-item.item.item-current {
--background: var(--primary); --background: var(--primary-tint);
--color: var(--primary-contrast);
border: 0; border: 0;
} }

View File

@ -23,10 +23,12 @@
<ng-content select="[description]"></ng-content> <ng-content select="[description]"></ng-content>
<!-- Module completion. --> <!-- Module completion. -->
<ion-item class="ion-text-wrap" *ngIf="showCompletion && module.completiondata && module.completiondata.isautomatic"> <ion-item class="ion-text-wrap"
*ngIf="showCompletion && module.completiondata && (module.completiondata.isautomatic || (showManualCompletion && module.uservisible))">
<ion-label> <ion-label>
<core-course-module-completion [completion]="module.completiondata" [moduleName]="module.name" [moduleId]="module.id" <core-course-module-completion [completion]="module.completiondata" [moduleName]="module.name" [moduleId]="module.id"
[showCompletionConditions]="true"> [showCompletionConditions]="true" [showManualCompletion]="showManualCompletion && module.uservisible"
(completionChanged)="completionChanged.emit($event)">
</core-course-module-completion> </core-course-module-completion>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, Input, OnInit } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { CoreCourse } from '@features/course/services/course'; import { CoreCourse } from '@features/course/services/course';
import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseModuleCompletionData, CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
@ -48,6 +48,9 @@ export class CoreCourseModuleInfoComponent implements OnInit {
@Input() hasDataToSync = false; // If the activity has any data to be synced. @Input() hasDataToSync = false; // If the activity has any data to be synced.
@Input() showManualCompletion = true; // Whether to show manual completion, true by default.
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when completion changes.
modicon = ''; modicon = '';
showCompletion = false; // Whether to show completion. showCompletion = false; // Whether to show completion.
moduleNameTranslated = ''; moduleNameTranslated = '';

View File

@ -7,8 +7,8 @@
<ion-icon *ngIf="completion?.offline" name="fas-sync" [attr.aria-label]="'core.course.manualcompletionnotsynced' | translate" <ion-icon *ngIf="completion?.offline" name="fas-sync" [attr.aria-label]="'core.course.manualcompletionnotsynced' | translate"
slot="end"></ion-icon> slot="end"></ion-icon>
</ion-button> </ion-button>
<ion-button *ngIf="!completion.state" color="dark" fill="outline" [attr.aria-label]="accessibleDescription" <ion-button *ngIf="!completion.state" fill="outline" [attr.aria-label]="accessibleDescription" (click)="completionClicked($event)"
(click)="completionClicked($event)" class="ion-text-wrap" [class.chip]="mode == 'basic'"> class="ion-text-wrap" [class.chip]="mode == 'basic'">
{{ 'core.course.completion_manual:markdone' | translate }} {{ 'core.course.completion_manual:markdone' | translate }}
<ion-icon *ngIf="completion?.offline" name="fas-sync" [attr.aria-label]="'core.course.manualcompletionnotsynced' | translate" <ion-icon *ngIf="completion?.offline" name="fas-sync" [attr.aria-label]="'core.course.manualcompletionnotsynced' | translate"
slot="end"></ion-icon> slot="end"></ion-icon>
@ -16,7 +16,7 @@
</ng-container> </ng-container>
<ng-container *ngIf="!completion.istrackeduser"> <ng-container *ngIf="!completion.istrackeduser">
<ion-button disabled="true" color="dark" fill="outline" class="ion-text-wrap" [class.chip]="mode == 'basic'"> <ion-button disabled="true" fill="outline" class="ion-text-wrap" [class.chip]="mode == 'basic'">
{{ 'core.course.completion_manual:markdone' | translate }} {{ 'core.course.completion_manual:markdone' | translate }}
</ion-button> </ion-button>
</ng-container> </ng-container>

View File

@ -6,13 +6,6 @@
<ion-icon name="fas-arrow-left" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-arrow-left" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-col> </ion-col>
<ion-col class="ion-no-padding"
*ngIf="showCompletion && (currentModule.completiondata && showManualCompletion && currentModule.uservisible)">
<!-- Module completion. -->
<core-course-module-completion [completion]="currentModule.completiondata" [moduleName]="currentModule.name"
[moduleId]="currentModule.id" [showManualCompletion]="true" (completionChanged)="completionChanged.emit($event)">
</core-course-module-completion>
</ion-col>
<ion-col size="auto" class="ion-no-padding core-course-module-navigation-arrow"> <ion-col size="auto" class="ion-no-padding core-course-module-navigation-arrow">
<ion-button fill="clear" class="core-course-next-module" [disabled]="!nextModule" (click)="goToActivity(true)" <ion-button fill="clear" class="core-course-next-module" [disabled]="!nextModule" (click)="goToActivity(true)"
[attr.aria-label]="'core.course.gotonextactivity' | translate"> [attr.aria-label]="'core.course.gotonextactivity' | translate">

View File

@ -12,9 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { CoreCourse, CoreCourseProvider, CoreCourseWSSection } from '@features/course/services/course'; import { CoreCourse, CoreCourseProvider, CoreCourseWSSection } from '@features/course/services/course';
import { CoreCourseModuleCompletionData, CoreCourseModuleData } from '@features/course/services/course-helper'; import { CoreCourseModuleData } from '@features/course/services/course-helper';
import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate';
import { IonContent } from '@ionic/angular'; import { IonContent } from '@ionic/angular';
import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
@ -27,7 +27,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
* Component to show a button to go to the next resource/activity. * Component to show a button to go to the next resource/activity.
* *
* Example usage: * Example usage:
* <core-course-module-navigation [courseId]="courseId" [currentModule]="module"></core-course-module-navigation> * <core-course-module-navigation [courseId]="courseId" [currentModuleId]="moduleId"></core-course-module-navigation>
*/ */
@Component({ @Component({
selector: 'core-course-module-navigation', selector: 'core-course-module-navigation',
@ -37,21 +37,17 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy { export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy {
@Input() courseId!: number; // Course ID. @Input() courseId!: number; // Course ID.
@Input() currentModule!: CoreCourseModuleData; // Current module. @Input() currentModuleId!: number; // Current module Id.
@Input() showManualCompletion = true; // Whether to show manual completion, true by default.
@Output() completionChanged = new EventEmitter<CoreCourseModuleCompletionData>(); // Notify when completion changes.
nextModule?: CoreCourseModuleData; nextModule?: CoreCourseModuleData;
previousModule?: CoreCourseModuleData; previousModule?: CoreCourseModuleData;
nextModuleSection?: CoreCourseWSSection; nextModuleSection?: CoreCourseWSSection;
previousModuleSection?: CoreCourseWSSection; previousModuleSection?: CoreCourseWSSection;
loaded = false; loaded = false;
showCompletion = false; // Whether to show completion.
protected completionObserver: CoreEventObserver; protected completionObserver: CoreEventObserver;
constructor(el: ElementRef, protected ionContent: IonContent) { constructor(protected ionContent: IonContent) {
const siteId = CoreSites.getCurrentSiteId(); const siteId = CoreSites.getCurrentSiteId();
this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => { this.completionObserver = CoreEvents.on(CoreEvents.COMPLETION_MODULE_VIEWED, async (data) => {
@ -70,8 +66,6 @@ export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy {
* @inheritdoc * @inheritdoc
*/ */
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.showCompletion = CoreSites.getRequiredCurrentSite().isVersionGreaterEqualThan('3.11');
try { try {
await this.setNextAndPreviousModules(CoreSitesReadingStrategy.PREFER_CACHE); await this.setNextAndPreviousModules(CoreSitesReadingStrategy.PREFER_CACHE);
} finally { } finally {
@ -104,7 +98,6 @@ export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy {
} }
const preSets = CoreSites.getReadingStrategyPreSets(readingStrategy); const preSets = CoreSites.getReadingStrategyPreSets(readingStrategy);
const currentModuleId = this.currentModule.id;
const sections = await CoreCourse.getSections(this.courseId, false, true, preSets); const sections = await CoreCourse.getSections(this.courseId, false, true, preSets);
@ -117,7 +110,7 @@ export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy {
return false; return false;
} }
currentModuleIndex = section.modules.findIndex((module: CoreCourseModuleData) => module.id == currentModuleId); currentModuleIndex = section.modules.findIndex((module: CoreCourseModuleData) => module.id == this.currentModuleId);
return currentModuleIndex >= 0; return currentModuleIndex >= 0;
}); });

View File

@ -25,7 +25,7 @@
</h1> </h1>
</ion-label> </ion-label>
<ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser" [href]="externalUrl" core-link [showBrowserWarning]="false" <ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser" [href]="externalUrl" core-link [showBrowserWarning]="false"
color="dark" [attr.aria-label]="'core.openinbrowser' | translate" slot="end"> [attr.aria-label]="'core.openinbrowser' | translate" slot="end">
<ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-item> </ion-item>
@ -80,7 +80,7 @@
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-button fill="outline" expand="block" *ngIf="canPrefetch && displayOptions.displayPrefetch" class="ion-text-wrap" <ion-button fill="outline" expand="block" *ngIf="canPrefetch && displayOptions.displayPrefetch" class="ion-text-wrap"
(click)="prefetch()" color="primary" [disabled]="prefetchDisabled"> (click)="prefetch()" [disabled]="prefetchDisabled">
<ion-icon *ngIf="!prefetchLoading" name="fas-cloud-download-alt" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="!prefetchLoading" name="fas-cloud-download-alt" slot="start" aria-hidden="true"></ion-icon>
<ion-spinner *ngIf="prefetchLoading" slot="start" aria-hidden="true"></ion-spinner> <ion-spinner *ngIf="prefetchLoading" slot="start" aria-hidden="true"></ion-spinner>
<ion-label> <ion-label>
@ -197,14 +197,14 @@
</core-loading> </core-loading>
</ion-content> </ion-content>
<ion-footer *ngIf="loaded && isOnline && displayOptions.displayRefresh"> <ion-footer *ngIf="loaded && isOnline && displayOptions.displayRefresh">
<ion-button class="ion-margin" *ngIf="!hasOffline" (click)="refresh()" expand="block"> <ion-button class="ion-margin" *ngIf="!hasOffline" (click)="refresh()" expand="block" fill="outline">
<ion-icon name="fas-redo-alt" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-redo-alt" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'core.refresh' | translate }} {{ 'core.refresh' | translate }}
</ion-label> </ion-label>
</ion-button> </ion-button>
<ion-button class="ion-margin" *ngIf="hasOffline" (click)="sync()" expand="block"> <ion-button class="ion-margin" *ngIf="hasOffline" (click)="sync()" expand="block" fill="outline">
<ion-icon name="fas-sync-alt" slot="start" aria-hidden="true"></ion-icon> <ion-icon name="fas-sync-alt" slot="start" aria-hidden="true"></ion-icon>
<ion-label> <ion-label>
{{ 'core.settings.synchronizenow' | translate }} {{ 'core.settings.synchronizenow' | translate }}

View File

@ -53,7 +53,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" <ion-button fill="clear" *ngFor="let button of module.handlerData.buttons"
[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>

View File

@ -36,7 +36,7 @@
<core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"> <core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id">
</core-format-text> </core-format-text>
</h2> </h2>
<ion-chip color="brand" *ngIf="course.categoryname" class="core-course-category ion-text-nowrap"> <ion-chip color="primary" *ngIf="course.categoryname" class="core-course-category ion-text-nowrap">
<span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span> <span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span>
<ion-label> <ion-label>
<core-format-text [text]="course.categoryname" contextLevel="coursecat" [contextInstanceId]="course.categoryid"> <core-format-text [text]="course.categoryname" contextLevel="coursecat" [contextInstanceId]="course.categoryid">
@ -61,7 +61,7 @@
</p> </p>
</div> </div>
</ion-label> </ion-label>
<ion-button fill="clear" [href]="courseUrl" core-link [showBrowserWarning]="false" color="dark" <ion-button fill="clear" [href]="courseUrl" core-link [showBrowserWarning]="false"
[attr.aria-label]="'core.openinbrowser' | translate" slot="end"> [attr.aria-label]="'core.openinbrowser' | translate" slot="end">
<ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
@ -143,7 +143,7 @@
</ion-card> </ion-card>
<ng-container *ngIf="canAccessCourse"> <ng-container *ngIf="canAccessCourse">
<ion-button class="ion-margin" *ngFor="let item of courseMenuHandlers" (click)="openMenuItem(item)" [class]="item.data.class" <ion-button *ngFor="let item of courseMenuHandlers" (click)="openMenuItem(item)" [class]="'ion-margin' + item.data.class"
expand="block"> expand="block">
<ion-icon *ngIf="item.data.icon" [name]="item.data.icon" slot="start" aria-hidden="true"></ion-icon> <ion-icon *ngIf="item.data.icon" [name]="item.data.icon" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{item.data.title | translate }}</ion-label> <ion-label>{{item.data.title | translate }}</ion-label>

View File

@ -12,7 +12,7 @@
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button fill="clear" *ngIf="module.url && module.uservisible && !unsupported" [href]="module.url" core-link <ion-button fill="clear" *ngIf="module.url && module.uservisible && !unsupported" [href]="module.url" core-link
[showBrowserWarning]="false" color="dark" [attr.aria-label]="'core.openinbrowser' | translate"> [showBrowserWarning]="false" [attr.aria-label]="'core.openinbrowser' | translate">
<ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</ion-buttons> </ion-buttons>
@ -24,7 +24,8 @@
</ion-refresher> </ion-refresher>
<core-loading [hideUntil]="loaded" class="has-spacer list-item-limited-width"> <core-loading [hideUntil]="loaded" class="has-spacer list-item-limited-width">
<core-course-module-info [module]="module" [courseId]="courseId" [description]="module.description" [component]="module.modname" <core-course-module-info [module]="module" [courseId]="courseId" [description]="module.description" [component]="module.modname"
[componentId]="module.id" [expandDescription]="true" [showAvailabilityInfo]="true"> [componentId]="module.id" [expandDescription]="true" [showAvailabilityInfo]="true" (completionChanged)="onCompletionChange()"
[showManualCompletion]="showManualCompletion">
<div class="core-module-additional-info" title> <div class="core-module-additional-info" title>
<ion-chip *ngIf="module.handlerData?.extraBadge" [color]="module.handlerData?.extraBadgeColor" <ion-chip *ngIf="module.handlerData?.extraBadge" [color]="module.handlerData?.extraBadgeColor"
class="ion-text-wrap ion-text-start" [outline]="true"> class="ion-text-wrap ion-text-start" [outline]="true">
@ -44,6 +45,6 @@
<core-course-unsupported-module *ngIf="unsupported" [module]="module"></core-course-unsupported-module> <core-course-unsupported-module *ngIf="unsupported" [module]="module"></core-course-unsupported-module>
</core-loading> </core-loading>
<core-course-module-navigation collapsible-footer [hidden]="!loaded" [courseId]="courseId" [currentModule]="module" <core-course-module-navigation collapsible-footer [hidden]="!loaded" [courseId]="courseId" [currentModuleId]="module.id">
(completionChanged)="onCompletionChange()" [showManualCompletion]="showManualCompletion"></core-course-module-navigation> </core-course-module-navigation>
</ion-content> </ion-content>

View File

@ -17,7 +17,7 @@
<div class="core-button-spinner" *ngIf="courseOptionMenuEnabled"> <div class="core-button-spinner" *ngIf="courseOptionMenuEnabled">
<!-- Options menu. --> <!-- Options menu. -->
<ion-button fill="clear" color="dark" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner" <ion-button fill="clear" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner"
[attr.aria-label]="('core.displayoptions' | translate)"> [attr.aria-label]="('core.displayoptions' | translate)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
@ -66,7 +66,7 @@
color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon> color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon>
</p> </p>
<ion-chip color="brand" *ngIf="course.categoryname" <ion-chip color="primary" *ngIf="course.categoryname"
class="core-course-category core-course-additional-info ion-text-nowrap"> class="core-course-category core-course-additional-info ion-text-nowrap">
<span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span> <span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span>
<ion-label> <ion-label>

View File

@ -47,7 +47,7 @@
name="fam-cloud-done" color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon> name="fam-cloud-done" color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon>
<!-- Options menu. --> <!-- Options menu. -->
<ion-button fill="clear" color="dark" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner" <ion-button fill="clear" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner"
[attr.aria-label]="('core.displayoptions' | translate)"> [attr.aria-label]="('core.displayoptions' | translate)">
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon> <ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>

View File

@ -31,7 +31,7 @@
<!-- Download all courses. --> <!-- Download all courses. -->
<div *ngIf="downloadCoursesEnabled && myOverviewBlock && myOverviewBlock.filteredCourses.length > 1" <div *ngIf="downloadCoursesEnabled && myOverviewBlock && myOverviewBlock.filteredCourses.length > 1"
class="core-button-spinner"> class="core-button-spinner">
<ion-button *ngIf="!myOverviewBlock.prefetchCoursesData.loading" fill="clear" color="dark" <ion-button *ngIf="!myOverviewBlock.prefetchCoursesData.loading" fill="clear"
(click)="myOverviewBlock.prefetchCourses()" (click)="myOverviewBlock.prefetchCourses()"
[attr.aria-label]="myOverviewBlock.prefetchCoursesData.statusTranslatable | translate"> [attr.aria-label]="myOverviewBlock.prefetchCoursesData.statusTranslatable | translate">
<ion-icon [name]="myOverviewBlock.prefetchCoursesData.icon" slot="icon-only" aria-hidden="true"> <ion-icon [name]="myOverviewBlock.prefetchCoursesData.icon" slot="icon-only" aria-hidden="true">

View File

@ -80,8 +80,7 @@
</ion-slide> </ion-slide>
<ion-slide> <ion-slide>
<button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul" [title]="'core.editor.unorderedlist' | translate" <button [disabled]="!rteEnabled" [attr.aria-pressed]="toolbarStyles.ul" [title]="'core.editor.unorderedlist' | translate"
(click)="buttonAction($event, 'insertUnorderedList')" (click)="buttonAction($event, 'insertUnorderedList')" (click)="buttonAction($event, 'insertUnorderedList')" (mousedown)="downAction($event)" (keydown)="downAction($event)">
(mousedown)="downAction($event)" (keydown)="downAction($event)">
<ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon> <ion-icon name="fas-list-ul" aria-hidden="true"></ion-icon>
</button> </button>
</ion-slide> </ion-slide>

View File

@ -62,7 +62,7 @@
</form> </form>
<!-- Forgotten password option. --> <!-- Forgotten password option. -->
<ion-button *ngIf="showForgottenPassword" expand="block" fill="clear" color="dark" <ion-button *ngIf="showForgottenPassword" expand="block" fill="clear"
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()">
{{ 'core.login.forgotten' | translate }} {{ 'core.login.forgotten' | translate }}
</ion-button> </ion-button>

View File

@ -76,7 +76,7 @@
</form> </form>
<!-- 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"
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()">
{{ 'core.login.forgotten' | translate }} {{ 'core.login.forgotten' | translate }}
</ion-button> </ion-button>

View File

@ -110,7 +110,7 @@
<!-- Help. --> <!-- Help. -->
<ion-button class="ion-margin-top core-login-need-help core-button-as-link ion-text-wrap" (click)="showHelp()" <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"> aria-haspopup="dialog" expand="block" fill="clear">
{{ 'core.needhelp' | translate }} {{ 'core.needhelp' | translate }}
</ion-button> </ion-button>
</div> </div>

View File

@ -1,161 +1,178 @@
@import "~theme/globals"; @import "~theme/globals";
:host{ :host {
--menutabbar-size: var(--bottom-tabs-size); ion-tabs {
--menutabbar-size: var(--bottom-tabs-size);
ion-tab-bar {
height: var(--menutabbar-size);
}
@if ($core-always-show-main-menu) {
ion-tabs.placement-bottom ion-tab-bar {
height: var(--menutabbar-size) !important;
visibility: visible !important;
transform: translateY(0) !important;
}
} @else {
ion-tabs.tabshidden.placement-bottom ion-tab-bar {
pointer-events: none;
ion-tab-button {
height: auto;
}
}
}
ion-tab-button ion-icon.core-tab-icon {
text-overflow: unset;
overflow: visible;
text-align: center;
}
ion-tab-button.ios ion-icon.core-tab-icon {
font-size: 25px;
}
ion-tab-button.md ion-badge.core-tab-badge {
font-size: 12px;
font-weight: bold;
border-radius: 10px;
padding-left: 6px;
padding-right: 6px;
line-height: 14px;
}
ion-tab-button.tab-selected {
background: var(--background-selected);
}
ion-icon.core-tab-badge {
color: var(--core-bottom-tabs-badge-color);
padding: 3px 6px 2px;
@include position(8px, null, null, calc(50% + 6px));
min-width: 12px;
font-size: 8px;
font-weight: normal;
box-sizing: border-box;
position: absolute;
z-index: 1;
}
ion-badge.core-tab-badge {
--background: var(--core-bottom-tabs-badge-color);
--color: var(--core-bottom-tabs-badge-text-color);
}
ion-tabs.placement-bottom ion-tab-button {
ion-icon.core-tab-icon {
transition: margin 500ms ease-in-out, transform 300ms ease-in-out;
}
ion-icon.core-tab-badge,
ion-badge.core-tab-badge {
top: 8px;
}
} }
ion-tabs.placement-side { ion-tabs.placement-side {
flex-direction: row; --menutabbar-size: var(--side-tabs-size);
ion-tab-bar {
order: -1;
width: var(--menutabbar-size);
height: calc(100% - var(--ion-safe-area-top) - var(--ion-safe-area-bottom));
flex-direction: column;
@include border-end(var(--border));
border-top: 0;
justify-content: flex-start;
@include padding(var(--ion-safe-area-top), 0px, var(--ion-safe-area-bottom), var(--ion-safe-area-left));
ion-tab-button, core-user-menu-button {
width: 100%;
min-height: var(--menutabbar-size);
flex: 0;
ion-icon.core-tab-badge,
ion-badge.core-tab-badge {
top: calc(50% - 20px);
}
}
}
} }
--network-margin-bottom: 0px;
--network-message-background: transparent;
--network-message-offline: none;
--network-message-online: none;
--network-message-height: 16px;
}
:host-context(.core-online),
:host-context(.core-offline) {
.core-network-message {
visibility: visible;
height: var(--network-message-height);
padding-bottom: calc(var(--ion-safe-area-bottom, 0px) + var(--network-message-height));
}
}
:host-context(.core-online) {
--network-margin-bottom: 8px;
--network-message-background: var(--success);
--network-message-online: block;
}
:host-context(.core-offline) {
--network-margin-bottom: 8px;
--network-message-background: var(--danger);
--network-message-offline: block;
}
ion-tab-bar {
height: var(--menutabbar-size);
core-user-menu-button { core-user-menu-button {
align-items: center; align-items: center;
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.core-network-message { ion-tab-button {
--network-message-height: 16px; &.tab-selected {
position: absolute; background: var(--background-selected);
bottom: 0; }
left: 0;
right: 0;
padding-left: 10px;
padding-right: 10px;
text-align: center;
color: white;
visibility: hidden;
height: 0;
transition: all 500ms ease-in-out;
opacity: .8;
z-index: 12;
}
.core-online-message, ion-icon.core-tab-icon {
.core-offline-message { text-overflow: unset;
display: none; overflow: visible;
text-align: center;
font-size: 24px;
}
ion-badge.core-tab-badge {
font-size: 12px;
font-weight: bold;
border-radius: 10px;
padding-left: 6px;
padding-right: 6px;
line-height: 14px;
--background: var(--core-bottom-tabs-badge-color);
--color: var(--core-bottom-tabs-badge-text-color);
}
ion-icon.core-tab-badge {
color: var(--core-bottom-tabs-badge-color);
padding: 3px 6px 2px;
@include position(8px, null, null, calc(50% + 6px));
min-width: 12px;
font-size: 8px;
font-weight: normal;
box-sizing: border-box;
position: absolute;
z-index: 1;
}
} }
} }
:host-context(.core-online), ion-tabs.placement-bottom {
:host-context(.core-offline) { ion-tab-button {
ion-tabs.placement-bottom ion-tab-button ion-icon.core-tab-icon { ion-icon.core-tab-icon {
margin-bottom: 8px; margin-bottom: var(--network-margin-bottom);
transition: margin 500ms ease-in-out, transform 300ms ease-in-out;
}
ion-icon.core-tab-badge,
ion-badge.core-tab-badge {
top: 8px;
}
} }
ion-tabs.placement-bottom ion-tab-button.ios ion-icon.core-tab-icon { @if ($core-always-show-main-menu) {
margin-bottom: 14px; ion-tab-bar {
} height: var(--menutabbar-size) !important;
visibility: visible !important;
transform: translateY(0) !important;
}
} @else {
&.tabshidden ion-tab-bar {
pointer-events: none;
.core-network-message { ion-tab-button {
visibility: visible; height: auto;
height: var(--network-message-height); }
padding-bottom: calc(var(--ion-safe-area-bottom, 0px) + var(--network-message-height)); }
pointer-events: none;
} }
} }
:host-context(.core-offline) .core-offline-message, ion-tabs.placement-side {
:host-context(.core-online) .core-online-message { flex-direction: row;
display: block;
ion-tab-bar {
order: -1;
width: var(--menutabbar-size);
height: calc(100% - var(--ion-safe-area-top) - var(--ion-safe-area-bottom));
flex-direction: column;
@include border-end(var(--border));
border-top: 0;
justify-content: flex-start;
@include padding(var(--ion-safe-area-top), 0px, var(--ion-safe-area-bottom), var(--ion-safe-area-left));
ion-tab-button {
--padding-start: 0;
--padding-end: 0;
ion-badge.core-tab-badge {
@include position(null, 1px, null, auto);
}
}
ion-tab-button, core-user-menu-button {
width: 100%;
min-height: var(--menutabbar-size);
flex: 0;
ion-icon.core-tab-badge,
ion-badge.core-tab-badge {
top: calc(50% - 20px);
}
}
}
} }
:host-context(.core-online) .core-network-message { .core-network-message {
background: var(--success); background: var(--network-message-background);
} pointer-events: none;
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding-left: 10px;
padding-right: 10px;
text-align: center;
color: white;
visibility: hidden;
height: 0;
transition: all 500ms ease-in-out;
opacity: .8;
z-index: 12;
:host-context(.core-offline) .core-network-message { .core-online {
background: var(--danger); display: var(--network-message-online);
}
.core-offline {
display: var(--network-message-offline);
}
} }

View File

@ -14,5 +14,5 @@
(onLoadingContent)="contentLoading()"> (onLoadingContent)="contentLoading()">
</core-site-plugins-plugin-content> </core-site-plugins-plugin-content>
<core-course-module-navigation collapsible-footer *ngIf="module" [courseId]="courseId" [currentModule]="module"> <core-course-module-navigation collapsible-footer *ngIf="module" [courseId]="courseId" [currentModuleId]="module.id">
</core-course-module-navigation> </core-course-module-navigation>

View File

@ -1,4 +1,4 @@
<ion-item button class="divider ion-text-wrap" detail="true" (click)="gotoBlock()" detail="true"> <ion-item button class="divider ion-text-wrap" detail="true" (click)="gotoBlock()">
<ion-label> <ion-label>
<h2>{{ title | translate }}</h2> <h2>{{ title | translate }}</h2>
</ion-label> </ion-label>

View File

@ -17,7 +17,7 @@
<ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap" lines="full"> <ion-item class="ion-text-center core-user-profile-maininfo ion-text-wrap" lines="full">
<core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="!canChangeProfilePicture"> <core-user-avatar [user]="user" [userId]="user.id" [linkProfile]="false" [checkOnline]="!canChangeProfilePicture">
<ion-button class="edit-avatar" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()" <ion-button class="edit-avatar" *ngIf="canChangeProfilePicture" (click)="changeProfilePicture()"
[attr.aria-label]="'core.user.newpicture' | translate" fill="clear" color="dark"> [attr.aria-label]="'core.user.newpicture' | translate" fill="clear">
<ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon> <ion-icon slot="icon-only" name="fas-pen" aria-hidden="true"></ion-icon>
</ion-button> </ion-button>
</core-user-avatar> </core-user-avatar>
@ -94,7 +94,7 @@
</a></p> </a></p>
</ion-label> </ion-label>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" *ngIf="interests" class="core-user-profile-interests"> <ion-item class="ion-text-wrap core-user-profile-interests" *ngIf="interests">
<ion-label> <ion-label>
<h2>{{ 'core.user.interests' | translate}}</h2> <h2>{{ 'core.user.interests' | translate}}</h2>
<ion-badge *ngFor="let interest of interests" role="link" (click)="openInterest(interest)"> <ion-badge *ngFor="let interest of interests" role="link" (click)="openInterest(interest)">

View File

@ -25,7 +25,6 @@ interface ColorComponents {
* Ionic color names. * Ionic color names.
*/ */
export enum CoreIonicColorNames { export enum CoreIonicColorNames {
BRAND = 'brand',
PRIMARY = 'primary', PRIMARY = 'primary',
SECONDARY = 'secondary', SECONDARY = 'secondary',
SUCCESS = 'success', SUCCESS = 'success',

View File

@ -17,7 +17,7 @@ $gray-900: #1d2125 !default; // Copy text
$black: #000000 !default; // Avoid usage $black: #000000 !default; // Avoid usage
$blue: #0f6cbf !default; $blue: #0f6cbf !default;
$cyan: #008196 !default; $cyan: #008196 !default; // Not used.
$green: #357a32 !default; $green: #357a32 !default;
$red: #ca3120 !default; $red: #ca3120 !default;
$yellow: #f0ad4e !default; $yellow: #f0ad4e !default;
@ -39,19 +39,19 @@ $ion-item-background-rgb: color-to-rgb-list($ion-item-background) !default;
$ion-item-background-dark: $gray-900 !default; $ion-item-background-dark: $gray-900 !default;
$ion-item-background-dark-rgb: color-to-rgb-list($ion-item-background-dark) !default; $ion-item-background-dark-rgb: color-to-rgb-list($ion-item-background-dark) !default;
$primary: $blue !default; $primary: $brand-color !default;
$secondary: $gray-400 !default; $secondary: $gray-300 !default;
$danger: $red !default; $danger: $red !default;
$warning: $yellow !default; $warning: $yellow !default;
$success: $green !default; $success: $green !default;
$info: $cyan !default; $info: $blue !default;
$light: $gray-100 !default; $light: $gray-100 !default;
$medium: $gray-600 !default; $medium: $gray-600 !default;
$dark: $gray-800 !default; $dark: $gray-800 !default;
$colors: ( $colors: (
primary: (light: $primary), primary: (light: $primary, dark: $primary),
secondary: (light: $secondary), secondary: (light: $secondary, dark: $gray-700),
success: (light: $success), success: (light: $success),
warning: (light: $warning), warning: (light: $warning),
danger: (light: $danger), danger: (light: $danger),
@ -59,7 +59,6 @@ $colors: (
light: (light: $light, dark: $dark), light: (light: $light, dark: $dark),
medium: (light: $medium, dark: $gray-200), medium: (light: $medium, dark: $gray-200),
dark: (light: $dark, dark: $light), dark: (light: $dark, dark: $light),
brand: (light: $brand-color, dark: $brand-color),
) !default; ) !default;
/** /**

View File

@ -370,6 +370,10 @@ ion-button.button.button-clear.button-has-icon-only {
--border-radius: var(--huge-radius); --border-radius: var(--huge-radius);
} }
ion-button.button.button-clear {
--color: var(--dark);
}
ion-button.button.button-solid, ion-button.button.button-solid,
ion-button.button.button-outline { ion-button.button.button-outline {
--border-radius: var(--core-input-radius); --border-radius: var(--core-input-radius);

View File

@ -65,7 +65,7 @@
} }
} }
--core-link-color: var(--primary-tint); --core-link-color: var(--info-tint);
--core-header-toolbar-background: var(--gray-900); --core-header-toolbar-background: var(--gray-900);
--core-header-toolbar-color: var(--white); --core-header-toolbar-color: var(--white);

View File

@ -47,7 +47,8 @@
@include generate-color($color-name, $colors); @include generate-color($color-name, $colors);
} }
--brand-color: var(--brand); --brand-color: var(--primary);
--brand-contrast: var(--primary-contrast);
// Accessibility vars. // Accessibility vars.
--a11y-min-target-size: 44px; --a11y-min-target-size: 44px;
@ -112,11 +113,12 @@
--core-bottom-tabs-background: var(--white); --core-bottom-tabs-background: var(--white);
--core-bottom-tabs-color: var(--gray-700); --core-bottom-tabs-color: var(--gray-700);
--core-bottom-tabs-color-selected: var(--brand); --core-bottom-tabs-color-selected: var(--brand-color);
--core-bottom-tabs-background-selected: transparent; --core-bottom-tabs-background-selected: transparent;
--core-bottom-tabs-badge-color: var(--brand); --core-bottom-tabs-badge-color: var(--brand-color);
--core-bottom-tabs-badge-text-color: var(--brand-contrast); --core-bottom-tabs-badge-text-color: var(--brand-contrast);
--bottom-tabs-size: 48px; --bottom-tabs-size: 48px;
--side-tabs-size: 56px;
ion-tab-bar.mainmenu-tabs { ion-tab-bar.mainmenu-tabs {
--background: var(--core-bottom-tabs-background); --background: var(--core-bottom-tabs-background);
--color: var(--core-bottom-tabs-color); --color: var(--core-bottom-tabs-color);
@ -124,7 +126,7 @@
--background-selected: var(--core-bottom-tabs-background-selected); --background-selected: var(--core-bottom-tabs-background-selected);
} }
--core-link-color: var(--primary); --core-link-color: var(--info);
a { a {
color: var(--core-link-color); color: var(--core-link-color);
} }
@ -201,7 +203,7 @@
ion-action-sheet { ion-action-sheet {
--button-color: var(--ion-text-color); --button-color: var(--ion-text-color);
--button-color-selected: var(--ion-text-color); --button-color-selected: var(--ion-text-color);
--title-border-color: var(--brand); --title-border-color: var(--brand-color);
.action-sheet-title { .action-sheet-title {
--color: var(--ion-text-color); --color: var(--ion-text-color);
@ -223,7 +225,7 @@
--core-tab-color: var(--subdued-text-color); --core-tab-color: var(--subdued-text-color);
--core-tab-border-color: var(--stroke); --core-tab-border-color: var(--stroke);
--core-tab-color-active: var(--dark); --core-tab-color-active: var(--dark);
--core-tab-border-color-active: var(--brand); --core-tab-border-color-active: var(--brand-color);
--core-tab-font-weight-active: normal; --core-tab-font-weight-active: normal;
--core-tabs-height: 48px; --core-tabs-height: 48px;
core-tabs, core-tabs-outlet { core-tabs, core-tabs-outlet {
@ -237,7 +239,7 @@
} }
} }
--core-loading-spinner: var(--brand); --core-loading-spinner: var(--brand-color);
ion-loading { ion-loading {
--spinner-color: var(--core-loading-spinner); --spinner-color: var(--core-loading-spinner);
} }
@ -248,7 +250,7 @@
} }
--core-progressbar-height: 8px; --core-progressbar-height: 8px;
--core-progressbar-color: var(--brand); --core-progressbar-color: var(--brand-color);
--core-progressbar-text-color: var(--medium); --core-progressbar-text-color: var(--medium);
--core-progressbar-background: var(--brand-tint); --core-progressbar-background: var(--brand-tint);
@ -302,7 +304,7 @@
--core-login-input-background: var(--white); --core-login-input-background: var(--white);
--core-login-input-color: var(--gray-900); --core-login-input-color: var(--gray-900);
--core-star-color: var(--brand); --core-star-color: var(--brand-color);
--core-large-avatar-size: 90px; --core-large-avatar-size: 90px;
--core-avatar-size: var(--a11y-min-target-size); --core-avatar-size: var(--a11y-min-target-size);