diff --git a/src/core/components/tabs/tab.ts b/src/core/components/tabs/tab.ts
index 2d3166fd5..c98e10472 100644
--- a/src/core/components/tabs/tab.ts
+++ b/src/core/components/tabs/tab.ts
@@ -65,7 +65,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase {
return this.isEnabled;
}
- @Input() id?: string; // An ID to identify the tab.
+ @Input() id = ''; // An ID to identify the tab.
@Output() ionSelect: EventEmitter
= new EventEmitter();
@ContentChild(TemplateRef) template?: TemplateRef; // Template defined by the content.
@@ -82,7 +82,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase {
element: ElementRef,
) {
this.element = element.nativeElement;
-
+ this.id = this.id || 'core-tab-' + CoreUtils.getUniqueId('CoreTabComponent');
this.element.setAttribute('role', 'tabpanel');
this.element.setAttribute('tabindex', '0');
this.element.setAttribute('aria-hidden', 'true');
@@ -92,7 +92,6 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase {
* Component being initialized.
*/
ngOnInit(): void {
- this.id = this.id || 'core-tab-' + CoreUtils.getUniqueId('CoreTabComponent');
this.element.setAttribute('aria-labelledby', this.id + '-tab');
this.element.setAttribute('id', this.id);
@@ -120,9 +119,6 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase {
this.loaded = true;
this.ionSelect.emit(this);
this.showHideNavBarButtons(true);
-
- // Setup tab scrolling.
- this.tabs.listenContentScroll(this.element, this.id!);
}
/**
diff --git a/src/core/components/tabs/tabs.scss b/src/core/components/tabs/tabs.scss
index 04a50ba1b..69d09150f 100644
--- a/src/core/components/tabs/tabs.scss
+++ b/src/core/components/tabs/tabs.scss
@@ -14,7 +14,7 @@
position: relative;
}
- ion-tab-bar.core-tabs-bar {
+ ion-tab-bar {
position: relative;
background: var(--tabs-background);
@include safe-area-padding-end(null, 0px);
@@ -22,57 +22,65 @@
color: var(--tabs-color);
border-bottom: 1px solid var(--stroke);
display: flex;
- align-items: flex-end;
+ flex-direction: row;
+ justify-content: space-between;
flex-shrink: 0;
- ion-row {
- width: 100%;
+ ion-spinner {
+ flex-grow: 1;
}
- .tab-slide {
- border-bottom: 2px solid transparent;
- min-width: 100px;
- min-height: var(--height);
- cursor: pointer;
- overflow: hidden;
-
- ion-tab-button {
- max-width: 100%;
- ion-label {
- font-size: 16px;
- font-weight: 400;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- word-wrap: break-word;
- max-width: 100%;
- line-height: 1.2em;
- margin-top: 16px;
- margin-bottom: 16px;
- }
- }
-
- &[aria-selected=true],
- &.selected {
- color: var(--color-active);
- border-bottom-color: var(--border-color-active);
- ion-tab-button {
- color: var(--color-active);
- ion-label {
- font-weight: var(--font-weight-active);
- }
- }
+ ion-button.arrow-button {
+ flex-shrink: 1;
+ margin: 0;
+ padding: 0;
+ --padding-start: 0;
+ --padding-end: 0;
+ min-width: 30px;
+ height: var(--height);
+ --border-radius: 0;
+ ion-icon {
+ font-size: 16px;
}
}
- ion-col {
+ ion-slides {
text-align: center;
line-height: 1.6rem;
+ flex-grow: 1;
- &.col-with-arrow {
- display: flex;
- justify-content: center;
- align-items: center;
+ ion-slide {
+ border-bottom: 2px solid transparent;
+ min-width: 100px;
+ height: var(--height);
+ cursor: pointer;
+ overflow: hidden;
+
+ ion-tab-button {
+ max-width: 100%;
+ ion-label {
+ font-size: 14px;
+ font-weight: 400;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ word-wrap: break-word;
+ max-width: 100%;
+ line-height: 1.2em;
+ }
+ }
+
+ &[aria-selected=true],
+ &.selected {
+ color: var(--color-active);
+ border-bottom-color: var(--border-color-active);
+ ion-tab-button {
+ color: var(--color-active);
+ ion-label {
+ font-weight: var(--font-weight-active);
+ }
+ }
+ }
}
}
@@ -109,8 +117,3 @@
position: relative;
}
}
-
-
-:host-context(.ios) {
- --height: 53px;
-}
diff --git a/src/core/components/tabs/tabs.ts b/src/core/components/tabs/tabs.ts
index a0fef9e06..a603c3ef8 100644
--- a/src/core/components/tabs/tabs.ts
+++ b/src/core/components/tabs/tabs.ts
@@ -51,12 +51,6 @@ export class CoreTabsComponent extends CoreTabsBaseComponent i
protected originalTabsContainer?: HTMLElement; // The container of the original tabs. It will include each tab's content.
- constructor(
- element: ElementRef,
- ) {
- super(element);
- }
-
/**
* View has been initialized.
*/
@@ -67,7 +61,6 @@ export class CoreTabsComponent extends CoreTabsBaseComponent i
return;
}
- this.tabsElement = this.element.nativeElement;
this.originalTabsContainer = this.originalTabsRef?.nativeElement;
}
@@ -85,21 +78,13 @@ export class CoreTabsComponent extends CoreTabsBaseComponent i
*/
addTab(tab: CoreTabComponent): void {
// Check if tab is already in the list.
- if (this.getTabIndex(tab.id!) == -1) {
+ if (this.getTabIndex(tab.id) === -1) {
this.tabs.push(tab);
this.sortTabs();
setTimeout(() => {
this.calculateSlides();
});
-
- if (this.initialized && this.tabs.length > 1 && this.tabBarHeight == 0) {
- // Calculate the tabBarHeight again now that there is more than 1 tab and the bar will be seen.
- // Use timeout to wait for the view to be rendered. 0 ms should be enough, use 50 to be sure.
- setTimeout(() => {
- this.calculateTabBarHeight();
- }, 50);
- }
}
}
@@ -109,7 +94,7 @@ export class CoreTabsComponent extends CoreTabsBaseComponent i
* @param tab The tab to remove.
*/
removeTab(tab: CoreTabComponent): void {
- const index = this.getTabIndex(tab.id!);
+ const index = this.getTabIndex(tab.id);
this.tabs.splice(index, 1);
this.calculateSlides();
diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts
index 7ead926a9..f0b7c90ad 100644
--- a/src/core/directives/collapsible-footer.ts
+++ b/src/core/directives/collapsible-footer.ts
@@ -50,6 +50,9 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
protected endContentScrollListener?: EventListener;
protected resizeListener?: CoreEventObserver;
protected slotPromise?: CoreCancellablePromise;
+ protected calcPending = false;
+ protected pageDidEnterListener?: EventListener;
+ protected page?: HTMLElement;
constructor(el: ElementRef, protected ionContent: IonContent) {
this.element = el.nativeElement;
@@ -82,6 +85,14 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
* Calculate the height of the footer.
*/
protected async calculateHeight(): Promise {
+ if (!CoreDom.isElementVisible(this.element)) {
+ this.calcPending = true;
+
+ return;
+ }
+
+ this.calcPending = false;
+
this.element.classList.remove('is-active');
await CoreUtils.nextTick();
@@ -159,6 +170,16 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
this.resizeListener = CoreDom.onWindowResize(() => {
this.calculateHeight();
}, 50);
+
+ this.page = this.content.closest('.ion-page') || undefined;
+ this.page?.addEventListener(
+ 'ionViewDidEnter',
+ this.pageDidEnterListener = () => {
+ if (this.calcPending) {
+ this.calculateHeight();
+ }
+ },
+ );
}
/**
@@ -228,6 +249,9 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
if (this.content && this.endContentScrollListener) {
this.content.removeEventListener('ionScrollEnd', this.endContentScrollListener);
}
+ if (this.page && this.pageDidEnterListener) {
+ this.page.removeEventListener('ionViewDidEnter', this.pageDidEnterListener);
+ }
this.resizeListener?.off();
this.slotPromise?.cancel();
diff --git a/src/core/directives/collapsible-header.ts b/src/core/directives/collapsible-header.ts
index 1cb15b1d6..5bb3d05cf 100644
--- a/src/core/directives/collapsible-header.ts
+++ b/src/core/directives/collapsible-header.ts
@@ -16,6 +16,7 @@ import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChang
import { CorePromisedValue } from '@classes/promised-value';
import { CoreLoadingComponent } from '@components/loading/loading';
import { CoreTabsOutletComponent } from '@components/tabs-outlet/tabs-outlet';
+import { CoreTabsComponent } from '@components/tabs/tabs';
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
import { ScrollDetail } from '@ionic/core';
import { CoreUtils } from '@services/utils/utils';
@@ -77,6 +78,8 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
protected isWithinContent = false;
protected enteredPromise = new CorePromisedValue();
protected mutationObserver?: MutationObserver;
+ protected firstEnter = true;
+ protected initPending = false;
constructor(el: ElementRef) {
this.collapsedHeader = el.nativeElement;
@@ -145,14 +148,19 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
this.page.addEventListener(
'ionViewDidEnter',
this.pageDidEnterListener = () => {
- clearTimeout(timeout);
- this.enteredPromise.resolve();
+ if (this.firstEnter) {
+ this.firstEnter = false;
+ clearTimeout(timeout);
+ this.enteredPromise.resolve();
+ } else if (this.initPending) {
+ this.initializeFloatingTitle();
+ }
},
- { once: true },
);
// Timeout in case event is never fired.
const timeout = window.setTimeout(() => {
+ this.firstEnter = false;
this.enteredPromise.reject(new Error('[collapsible-header] Waiting for ionViewDidEnter timeout reached'));
}, 5000);
@@ -223,8 +231,12 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
* Search the page content, initialize it, and wait until it's ready for the transition to trigger on scroll.
*/
protected async initializeContent(): Promise {
+ if (!this.page) {
+ return;
+ }
+
// Initialize from tabs.
- const tabs = CoreComponentsRegistry.resolve(this.page?.querySelector('core-tabs-outlet'), CoreTabsOutletComponent);
+ const tabs = CoreComponentsRegistry.resolve(this.page.querySelector('core-tabs-outlet'), CoreTabsOutletComponent);
if (tabs) {
const outlet = tabs.getOutlet();
@@ -242,7 +254,7 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
}
// Initialize from page content.
- const content = this.page?.querySelector('ion-content:not(.disable-scroll-y)');
+ const content = this.page.querySelector('ion-content:not(.disable-scroll-y)');
if (!content) {
throw new Error('[collapsible-header] Couldn\'t get content');
@@ -259,6 +271,14 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
throw new Error('[collapsible-header] Couldn\'t create floating title');
}
+ if (!CoreDom.isElementVisible(this.expandedHeader)) {
+ this.initPending = true;
+
+ return;
+ }
+
+ this.initPending = false;
+
this.page.classList.remove('collapsible-header-page-is-active');
CoreUtils.nextTick();
@@ -342,7 +362,19 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
return;
}
+ // Wait loadings to finish.
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-loading', CoreLoadingComponent);
+
+ // Wait tabs to be ready.
+ await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-tabs', CoreTabsComponent);
+ await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-tabs-outlet', CoreTabsOutletComponent);
+
+ // Wait loadings to finish, inside tabs (if any).
+ await CoreComponentsRegistry.waitComponentsReady(
+ this.page,
+ 'core-tab core-loading, ion-router-outlet core-loading',
+ CoreLoadingComponent,
+ );
}
/**
diff --git a/src/core/directives/collapsible-item.ts b/src/core/directives/collapsible-item.ts
index 3bac8a97c..6e95242f2 100644
--- a/src/core/directives/collapsible-item.ts
+++ b/src/core/directives/collapsible-item.ts
@@ -56,6 +56,9 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
protected darkModeListener?: Subscription;
protected domPromise?: CoreCancellablePromise;
protected uniqueId: string;
+ protected calcPending = false;
+ protected pageDidEnterListener?: EventListener;
+ protected page?: HTMLElement;
constructor(el: ElementRef) {
this.element = el.nativeElement;
@@ -93,6 +96,15 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
await this.calculateHeight();
+ this.page?.addEventListener(
+ 'ionViewDidEnter',
+ this.pageDidEnterListener = () => {
+ if (this.calcPending) {
+ this.calculateHeight();
+ }
+ },
+ );
+
this.resizeListener = CoreDom.onWindowResize(() => {
this.calculateHeight();
}, 50);
@@ -112,13 +124,12 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
await this.domPromise;
- const page = this.element.closest('.ion-page');
-
- if (!page) {
+ this.page = this.element.closest('.ion-page') || undefined;
+ if (!this.page) {
return;
}
- await CoreComponentsRegistry.waitComponentsReady(page, 'core-loading', CoreLoadingComponent);
+ await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-loading', CoreLoadingComponent);
}
/**
@@ -137,6 +148,15 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
await this.waitFormatTextsRendered();
+ if (!this.element.clientHeight) {
+ this.calcPending = true;
+ this.element.classList.remove('collapsible-loading-height');
+
+ return;
+ }
+
+ this.calcPending = false;
+
this.expandedHeight = this.element.getBoundingClientRect().height;
// Restore the max height now.
@@ -278,6 +298,10 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
this.resizeListener?.off();
this.darkModeListener?.unsubscribe();
this.domPromise?.cancel();
+
+ if (this.page && this.pageDidEnterListener) {
+ this.page.removeEventListener('ionViewDidEnter', this.pageDidEnterListener);
+ }
}
}
diff --git a/src/core/features/course/components/course-format/course-format.scss b/src/core/features/course/components/course-format/course-format.scss
index 869e69a96..da38b60b6 100644
--- a/src/core/features/course/components/course-format/course-format.scss
+++ b/src/core/features/course/components/course-format/course-format.scss
@@ -10,6 +10,8 @@
overflow: hidden;
text-transform: none;
flex: 1;
+ margin-left: 4px;
+ margin-right: 4px;
}
}
diff --git a/src/core/features/course/components/course-index/course-index.scss b/src/core/features/course/components/course-index/course-index.scss
index f4575ba22..7804c82f3 100644
--- a/src/core/features/course/components/course-index/course-index.scss
+++ b/src/core/features/course/components/course-index/course-index.scss
@@ -74,7 +74,7 @@ ion-item.item {
}
&.restricted {
- font-size: 14px;
+ font-size: var(--text-size);
}
}
}
diff --git a/src/core/features/course/components/module-info/course-module-info.scss b/src/core/features/course/components/module-info/course-module-info.scss
index 8b6c8feb0..d6aa6ad69 100644
--- a/src/core/features/course/components/module-info/course-module-info.scss
+++ b/src/core/features/course/components/module-info/course-module-info.scss
@@ -29,6 +29,10 @@
margin: 8px;
padding: 8px;
+ &:empty {
+ display: none;
+ }
+
::ng-deep ion-item {
--ion-item-background: var(--light);
--background: var(--light);
diff --git a/src/core/features/course/components/module-navigation/core-course-module-navigation.html b/src/core/features/course/components/module-navigation/core-course-module-navigation.html
index 5ca66de46..67afb3dc5 100644
--- a/src/core/features/course/components/module-navigation/core-course-module-navigation.html
+++ b/src/core/features/course/components/module-navigation/core-course-module-navigation.html
@@ -1,17 +1,16 @@
-
-
-
-
- {{ 'core.previous' | translate }}
+
+
+
+
+ {{ 'core.course.previousactivity' | translate }}
-
-
- {{ 'core.next' | translate }}
-
+
+
+ {{ 'core.course.nextactivity' | translate }}
+
diff --git a/src/core/features/course/components/module-navigation/module-navigation.scss b/src/core/features/course/components/module-navigation/module-navigation.scss
index 4b4eb2a8c..6b8ce25f6 100644
--- a/src/core/features/course/components/module-navigation/module-navigation.scss
+++ b/src/core/features/course/components/module-navigation/module-navigation.scss
@@ -3,7 +3,7 @@
:host {
--height: var(--core-navigation-max-height);
--background: var(--core-navigation-background);
- --button-vertical-margin: 2px;
+ --button-color: var(--gray-700);
height: var(--height);
width: 100%;
@@ -16,18 +16,42 @@
--loading-inline-min-height: var(--height);
}
- ion-button,
- ::ng-deep ion-button {
- margin-top: var(--button-vertical-margin);
- margin-bottom: var(--button-vertical-margin);
- }
-
&.empty {
display: none;
}
+
+ .core-course-module-navigation-arrow {
+ ion-button {
+ margin: 0;
+ --border-radius: 0;
+ width: 100%;
+ text-transform: none;
+ font-size: 12px;
+ font-weight: normal;
+ --color: var(--button-color);
+
+ .button-text {
+ width:100%;
+ }
+
+ ion-icon {
+ font-size: 12px;
+ }
+ }
+ .core-course-previous-module {
+ text-align: start;
+ }
+ .core-course-next-module {
+ text-align: end;
+ }
+ }
}
:host-context(core-course-format.core-course-format-singleactivity) {
opacity: 0 !important;
height: 0 !important;
}
+
+:host-context(body.dark) {
+ --button-color: var(--gray-100);
+}
diff --git a/src/core/features/course/components/module-navigation/module-navigation.ts b/src/core/features/course/components/module-navigation/module-navigation.ts
index 63211dbc2..cf1327ebd 100644
--- a/src/core/features/course/components/module-navigation/module-navigation.ts
+++ b/src/core/features/course/components/module-navigation/module-navigation.ts
@@ -215,7 +215,7 @@ export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy {
if (!module) {
// It seems the module was hidden. Show a message.
CoreDomUtils.instance.showErrorModal(
- next ? 'core.course.gotonextactivitynotfound' : 'core.course.gotopreviousactivitynotfound',
+ next ? 'core.course.nextactivitynotfound' : 'core.course.previousactivitynotfound',
true,
);
diff --git a/src/core/features/course/components/module/module.scss b/src/core/features/course/components/module/module.scss
index 2ef99974b..3485350cf 100644
--- a/src/core/features/course/components/module/module.scss
+++ b/src/core/features/course/components/module/module.scss
@@ -3,7 +3,6 @@
:host {
--horizontal-margin: 10px;
--vertical-margin: 10px;
- --core-course-module-not-viewed-border-color: var(--gray-500);
ion-card {
margin: var(--vertical-margin) var(--horizontal-margin);
@@ -93,10 +92,6 @@
display: none;
}
- &.core-course-module-not-viewed ion-card.core-course-module-with-view {
- --ion-card-border-color: var(--core-course-module-not-viewed-border-color);
- }
-
.core-course-last-module-viewed {
padding: 8px 12px;
color: var(--subdued-text-color);
diff --git a/src/core/features/course/lang.json b/src/core/features/course/lang.json
index 1103a9902..8195622c0 100644
--- a/src/core/features/course/lang.json
+++ b/src/core/features/course/lang.json
@@ -20,11 +20,11 @@
"confirmdownload": "You are about to download {{size}}.{{availableSpace}} Are you sure you want to continue?",
"confirmdownloadunknownsize": "It was not possible to calculate the size of the download.{{availableSpace}} Are you sure you want to continue?",
"confirmdownloadzerosize": "You are about to start downloading.{{availableSpace}} Are you sure you want to continue?",
- "confirmpartialdownloadsize": "You are about to download at least {{size}}.{{availableSpace}} Are you sure you want to continue?",
"confirmlimiteddownload": "You are not currently connected to Wi-Fi. ",
- "courseindex": "Course index",
+ "confirmpartialdownloadsize": "You are about to download at least {{size}}.{{availableSpace}} Are you sure you want to continue?",
"couldnotloadsectioncontent": "Could not load the section content. Please try again later.",
"couldnotloadsections": "Could not load the sections. Please try again later.",
+ "courseindex": "Course index",
"coursesummary": "Course summary",
"done": "Done",
"downloadcourse": "Download course",
@@ -35,20 +35,20 @@
"errordownloadingsection": "Error downloading section.",
"errorgetmodule": "Error getting activity data.",
"failed": "Failed",
- "gotonextactivity": "Go to next activity",
- "gotonextactivitynotfound": "Next activity not found. It's possible that it has been hidden or deleted.",
- "gotopreviousactivity": "Go to previous activity",
- "gotopreviousactivitynotfound": "Previous activity not found. It's possible that it has been hidden or deleted.",
"hiddenfromstudents": "Hidden from students",
"hiddenoncoursepage": "Available but not shown on course page",
"highlighted": "Highlighted",
- "insufficientavailablespace": "You are trying to download {{size}}. This will leave your device with insufficient space to operate normally. Please clear some storage space first.",
"insufficientavailablequota": "Your device could not allocate space to save this download. It may be reserving space for app and system updates. Please clear some storage space first.",
+ "insufficientavailablespace": "You are trying to download {{size}}. This will leave your device with insufficient space to operate normally. Please clear some storage space first.",
"lastaccessedactivity": "Last accessed activity",
"manualcompletionnotsynced": "Manual completion not synchronised.",
"modulenotfound": "Resource or activity not found, please make sure you're online and it's still available.",
+ "nextactivity": "Next activity",
+ "nextactivitynotfound": "Next activity not found. It's possible that it has been hidden or deleted.",
"nocontentavailable": "No content available at the moment.",
"overriddennotice": "Your final grade from this activity was manually adjusted.",
+ "previousactivity": "Previous activity",
+ "previousactivitynotfound": "Previous activity not found. It's possible that it has been hidden or deleted.",
"refreshcourse": "Refresh course",
"section": "Section",
"startdate": "Course start date",
diff --git a/src/core/features/course/pages/index/index.ts b/src/core/features/course/pages/index/index.ts
index fdd5e47c8..462a97c56 100644
--- a/src/core/features/course/pages/index/index.ts
+++ b/src/core/features/course/pages/index/index.ts
@@ -131,6 +131,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
} catch (error) {
CoreDomUtils.showErrorModal(error);
CoreNavigator.back();
+ this.loaded = true;
return;
}
@@ -224,9 +225,9 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy {
// Select the tab if needed.
this.firstTabName = undefined;
if (tabToLoad) {
- setTimeout(() => {
- this.tabsComponent?.selectByIndex(tabToLoad!);
- });
+ await CoreUtils.nextTick();
+
+ this.tabsComponent?.selectByIndex(tabToLoad);
}
}
diff --git a/src/core/features/grades/pages/course/course.scss b/src/core/features/grades/pages/course/course.scss
index bed25f18e..fff8ae719 100644
--- a/src/core/features/grades/pages/course/course.scss
+++ b/src/core/features/grades/pages/course/course.scss
@@ -98,7 +98,7 @@
}
.expandable-status-icon {
- font-size: 14px;
+ font-size: var(--text-size);
@include margin-horizontal(0, 2px);
@include core-transition(transform, 200ms);
diff --git a/src/core/singletons/components-registry.ts b/src/core/singletons/components-registry.ts
index 32b08e3dd..0a5e18cea 100644
--- a/src/core/singletons/components-registry.ts
+++ b/src/core/singletons/components-registry.ts
@@ -15,6 +15,7 @@
import { Component } from '@angular/core';
import { AsyncComponent } from '@classes/async-component';
import { CoreUtils } from '@services/utils/utils';
+import { CoreLogger } from './logger';
/**
* Registry to keep track of component instances.
@@ -22,6 +23,7 @@ import { CoreUtils } from '@services/utils/utils';
export class CoreComponentsRegistry {
private static instances: WeakMap = new WeakMap();
+ protected static logger = CoreLogger.getInstance('CoreComponentsRegistry');
/**
* Register a component instance.
@@ -78,6 +80,8 @@ export class CoreComponentsRegistry {
): Promise {
const instance = this.resolve(element, componentClass);
if (!instance) {
+ this.logger.error('No instance registered for element ' + componentClass, element);
+
return;
}
@@ -97,15 +101,21 @@ export class CoreComponentsRegistry {
selector: string,
componentClass?: ComponentConstructor,
): Promise {
+ let elements: Element[] = [];
+
if (element.matches(selector)) {
// Element to wait is myself.
- await CoreComponentsRegistry.waitComponentReady(element, componentClass);
+ elements = [element];
} else {
- await Promise.all(Array
- .from(element.querySelectorAll(selector))
- .map(element => CoreComponentsRegistry.waitComponentReady(element, componentClass)));
+ elements = Array.from(element.querySelectorAll(selector));
}
+ if (!elements.length) {
+ return;
+ }
+
+ await Promise.all(elements.map(element => CoreComponentsRegistry.waitComponentReady(element, componentClass)));
+
// Wait for next tick to ensure components are completely rendered.
await CoreUtils.nextTick();
}
diff --git a/src/theme/components/collapsible-header.scss b/src/theme/components/collapsible-header.scss
index 04304a443..eed43f951 100644
--- a/src/theme/components/collapsible-header.scss
+++ b/src/theme/components/collapsible-header.scss
@@ -1,4 +1,4 @@
-.collapsible-header-page {
+body:not(.core-iframe-fullscreen) .collapsible-header-page {
--collapsible-header-progress: 0;
--collapsible-header-collapsed-height: 0px;
--collapsible-header-expanded-y-delta: 0px;
@@ -27,10 +27,10 @@
&:not(.collapsible-header-page-is-collapsed) .collapsible-header-collapsed {
--core-header-toolbar-border-width: 0;
+ --core-header-buttons-background: var(--ion-background-color);
+ --core-header-buttons-color: var(--text-color);
ion-toolbar {
--background: transparent;
- --core-header-buttons-background: var(--ion-background-color);
- --core-header-buttons-color: var(--text-color);
}
h1 {
diff --git a/src/theme/components/collapsible-item.scss b/src/theme/components/collapsible-item.scss
index a40ea19c4..616bcb02e 100644
--- a/src/theme/components/collapsible-item.scss
+++ b/src/theme/components/collapsible-item.scss
@@ -36,6 +36,8 @@
color: var(--collapsible-toggle-text);
min-height: var(--toggle-size);
min-width: var(--toggle-size);
+ height: var(--toggle-size);
+ width: var(--toggle-size);
--border-radius: var(--huge-radius);
border-radius: var(--border-radius);
--padding-start: 0px;
diff --git a/src/theme/components/format-text.scss b/src/theme/components/format-text.scss
index 808d38dbc..d2a47fe51 100644
--- a/src/theme/components/format-text.scss
+++ b/src/theme/components/format-text.scss
@@ -210,7 +210,7 @@ core-rich-text-editor .core-rte-editor {
p, ul, ol, li {
// Normalize font-size inside formatted text.
- font-size: 14px;
+ font-size: var(--text-size);
}
p {
diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss
index a97d2eea2..b10ac0d47 100644
--- a/src/theme/theme.base.scss
+++ b/src/theme/theme.base.scss
@@ -96,7 +96,7 @@ body {
&.item-heading-secondary {
@include margin(2px, 0);
- font-size: 14px;
+ font-size: var(--text-size);
font-weight: normal;
line-height: normal;
@@ -112,7 +112,7 @@ body {
&.item-heading-secondary {
@include margin(0, 0, 3px);
- font-size: 14px;
+ font-size: var(--text-size);
font-weight: normal;
line-height: normal;
@@ -154,9 +154,6 @@ ion-header {
z-index: 12; // To hide ion-slides on scroll.
ion-toolbar {
- --core-header-buttons-background: var(--core-header-toolbar-background);
- --core-header-buttons-color: var(--core-header-toolbar-color);
-
ion-spinner {
margin: 10px;
}
@@ -225,7 +222,7 @@ ion-header {
h1 + h2,
h1 + .subheading {
- font-size: 14px;
+ font-size: var(--text-size);
font-weight: 400;
}
@@ -245,7 +242,7 @@ ion-header {
h1 + h2,
h1 + .subheading {
- font-size: 14px;
+ font-size: var(--text-size);
font-weight: 400;
}
}
@@ -579,14 +576,19 @@ body.core-iframe-fullscreen ion-router-outlet {
}
}
- --core-header-toolbar-height: 48px;
- --core-header-toolbar-color: white;
- --core-header-toolbar-background: black;
- --core-header-toolbar-border-width: 0px;
+ .ion-page ion-header {
+ --core-header-toolbar-height: 48px;
+ --core-header-toolbar-color: white;
+ --core-header-toolbar-background: black;
+ --core-header-buttons-background: var(--core-header-toolbar-background);
+ --core-header-buttons-background: var(--core-header-toolbar-background);
+ --core-header-buttons-color: var(--core-header-toolbar-color);
+ --core-header-toolbar-border-width: 0px;
- ion-header ion-toolbar {
- h1, ion-back-button {
- display: none;
+ ion-toolbar {
+ h1, ion-back-button {
+ display: none;
+ }
}
}
@@ -688,7 +690,7 @@ body.core-iframe-fullscreen ion-router-outlet {
font-style: italic;
margin-top: 0;
margin-bottom: 10px;
- font-size: 14px;
+ font-size: var(--text-size);
}
// Item styles
@@ -712,7 +714,7 @@ body.core-iframe-fullscreen ion-router-outlet {
}
p.item-heading {
- font-size: 14px;
+ font-size: var(--text-size);
}
p {
@@ -765,6 +767,7 @@ body.core-iframe-fullscreen ion-router-outlet {
--color: var(--color-shade);
--inner-border-width: 0px;
--border-width: 0px;
+ font-size: var(--text-size);
ion-label, ion-label > p {
--color: var(--color-shade);
@@ -860,6 +863,7 @@ ion-content.limited-width > :not([slot]) {
ion-content.limited-width > :not([slot]) {
display: flex;
flex-direction: column;
+ min-height: 100%;
}
ion-toolbar h1 img.core-bar-button-image,
@@ -1225,6 +1229,7 @@ audio.core-media-adapt-width {
}
ion-item {
+ font-size: var(--text-size);
--inner-border-width: 0px;
}
@@ -1281,7 +1286,7 @@ html.md div.fake-ion-item {
h6 {
@include margin(2px, 0);
- font-size: 14px;
+ font-size: var(--text-size);
font-weight: normal;
line-height: normal;
@@ -1289,7 +1294,7 @@ html.md div.fake-ion-item {
p {
@include margin(0, 0, 2px);
- font-size: 14px;
+ font-size: var(--text-size);
line-height: 20px;
text-overflow: inherit;
overflow: inherit;
@@ -1297,7 +1302,7 @@ html.md div.fake-ion-item {
}
html.ios div.fake-ion-item {
- font-size: 14px;
+ font-size: var(--text-size);
@include padding(null, 10px, null, 20px);
@include margin(10px, 8px, 10px, null);
@@ -1318,14 +1323,14 @@ html.ios div.fake-ion-item {
h5,
h6 {
@include margin(0, 0, 3px);
- font-size: 14px;
+ font-size: var(--text-size);
font-weight: normal;
line-height: normal;
}
p {
@include margin(0, 0, 2px 0);
- font-size: 14px;
+ font-size: var(--text-size);
line-height: normal;
text-overflow: inherit;
overflow: inherit;
@@ -1496,6 +1501,7 @@ ion-content.disable-scroll-y::part(scroll) {
}
iframe {
+ flex-grow: 1;
border: 0;
display: block;
max-width: 100%;
@@ -1585,11 +1591,8 @@ ion-header.no-title {
--core-header-toolbar-border-width: 0;
--core-header-toolbar-background: transparent;
--core-header-shadow: none !important;
- ion-toolbar {
- --core-header-buttons-background: var(--ion-background-color);
- --core-header-buttons-color: var(--text-color);
- }
-
+ --core-header-buttons-background: var(--ion-background-color);
+ --core-header-buttons-color: var(--text-color);
}
// To make core-swipe-slides fill the remaining height.
diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss
index 21e9485e1..14da0eacf 100644
--- a/src/theme/theme.light.scss
+++ b/src/theme/theme.light.scss
@@ -59,6 +59,7 @@
--huge-radius: 24px;
--text-color: #{$text-color};
+ --text-size: 14px;
--background-color: #{$background-color};
--stroke: var(--gray-300);
@@ -148,6 +149,8 @@
--core-header-toolbar-color: var(--text-color);
--core-header-toolbar-height: 48px;
--core-header-shadow: none;
+ --core-header-buttons-background: var(--core-header-toolbar-background);
+ --core-header-buttons-color: var(--core-header-toolbar-color);
ion-header {
box-shadow: var(--core-header-shadow, none);