diff --git a/src/addons/calendar/components/reminder-time-modal/reminder-time-modal.ts b/src/addons/calendar/components/reminder-time-modal/reminder-time-modal.ts
index 871530664..1a10a9c27 100644
--- a/src/addons/calendar/components/reminder-time-modal/reminder-time-modal.ts
+++ b/src/addons/calendar/components/reminder-time-modal/reminder-time-modal.ts
@@ -15,7 +15,6 @@
import { AddonCalendar, AddonCalendarReminderUnits, AddonCalendarValueAndUnit } from '@addons/calendar/services/calendar';
import { Component, Input, OnInit } from '@angular/core';
import { CoreDomUtils } from '@services/utils/dom';
-import { CoreUtils } from '@services/utils/utils';
import { ModalController } from '@singletons';
/**
@@ -166,11 +165,9 @@ export class AddonCalendarReminderTimeModalComponent implements OnInit {
this.radioValue = 'custom';
- await CoreUtils.nextTick();
-
- const target =
ev.target;
- if (target && 'focus' in target) {
- target.focus();
+ const target = ev.target;
+ if (target) {
+ CoreDomUtils.focusElement(target);
}
}
diff --git a/src/core/directives/auto-focus.ts b/src/core/directives/auto-focus.ts
index 9a37a208f..d84252ad6 100644
--- a/src/core/directives/auto-focus.ts
+++ b/src/core/directives/auto-focus.ts
@@ -49,19 +49,7 @@ export class CoreAutoFocusDirective implements AfterViewInit {
await CoreDom.waitToBeInDOM(this.element);
- let focusElement = this.element;
-
- if ('getInputElement' in focusElement) {
- // If it's an Ionic element get the right input to use.
- focusElement.componentOnReady && await focusElement.componentOnReady();
- focusElement = await focusElement.getInputElement();
- }
-
- if (!focusElement) {
- return;
- }
-
- CoreDomUtils.focusElement(focusElement);
+ CoreDomUtils.focusElement(this.element);
}
diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts
index 4a44fa0b9..73e9dbd5a 100644
--- a/src/core/directives/collapsible-footer.ts
+++ b/src/core/directives/collapsible-footer.ts
@@ -50,11 +50,10 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
protected contentScrollListener?: EventListener;
protected endContentScrollListener?: EventListener;
protected resizeListener?: CoreEventObserver;
- protected domPromise?: CoreCancellablePromise;
+ protected slotPromise?: CoreCancellablePromise;
constructor(el: ElementRef, protected ionContent: IonContent) {
this.element = el.nativeElement;
- this.element.setAttribute('slot', 'fixed'); // Just in case somebody forgets to add it.
}
/**
@@ -63,9 +62,9 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
async ngOnInit(): Promise {
// Only if not present or explicitly falsy it will be false.
this.appearOnBottom = !CoreUtils.isFalseOrZero(this.appearOnBottom);
- this.domPromise = CoreDom.waitToBeInDOM(this.element);
+ this.slotPromise = CoreDom.slotOnContent(this.element);
- await this.domPromise;
+ await this.slotPromise;
await this.waitLoadingsDone();
await this.waitFormatTextsRendered();
@@ -229,7 +228,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
}
this.resizeListener?.off();
- this.domPromise?.cancel();
+ this.slotPromise?.cancel();
}
}
diff --git a/src/core/directives/fab.ts b/src/core/directives/fab.ts
index 90f700fc5..fe18f8274 100644
--- a/src/core/directives/fab.ts
+++ b/src/core/directives/fab.ts
@@ -31,19 +31,18 @@ export class CoreFabDirective implements OnInit, OnDestroy {
protected element: HTMLElement;
protected content?: HTMLIonContentElement | null;
protected initialPaddingBottom = 0;
- protected domPromise?: CoreCancellablePromise;
+ protected slotPromise?: CoreCancellablePromise;
constructor(el: ElementRef) {
this.element = el.nativeElement;
- this.element.setAttribute('slot', 'fixed');
}
/**
* @inheritdoc
*/
async ngOnInit(): Promise {
- this.domPromise = CoreDom.waitToBeInDOM(this.element);
- await this.domPromise;
+ this.slotPromise = CoreDom.slotOnContent(this.element);
+ await this.slotPromise;
this.content = this.element.closest('ion-content');
@@ -70,12 +69,6 @@ export class CoreFabDirective implements OnInit, OnDestroy {
}
const initialHeight = this.element.getBoundingClientRect().height || 56;
-
- // Move element to the nearest ion-content if it's not the parent
- if (this.element.parentElement?.nodeName != 'ION-CONTENT') {
- this.content.appendChild(this.element);
- }
-
this.content.style.setProperty('--padding-bottom', this.initialPaddingBottom + initialHeight + 'px');
}
@@ -86,7 +79,7 @@ export class CoreFabDirective implements OnInit, OnDestroy {
if (this.content) {
this.content.style.setProperty('--padding-bottom', this.initialPaddingBottom + 'px');
}
- this.domPromise?.cancel();
+ this.slotPromise?.cancel();
}
}
diff --git a/src/core/features/block/components/side-blocks-button/side-blocks-button.ts b/src/core/features/block/components/side-blocks-button/side-blocks-button.ts
index e8b369c29..e748b67aa 100644
--- a/src/core/features/block/components/side-blocks-button/side-blocks-button.ts
+++ b/src/core/features/block/components/side-blocks-button/side-blocks-button.ts
@@ -12,9 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-import { Component, ElementRef, Input, ViewChild } from '@angular/core';
+import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { CoreCancellablePromise } from '@classes/cancellable-promise';
import { CoreUserTours, CoreUserToursAlignment, CoreUserToursSide } from '@features/usertours/services/user-tours';
import { CoreDomUtils } from '@services/utils/dom';
+import { CoreDom } from '@singletons/dom';
import { CoreBlockSideBlocksTourComponent } from '../side-blocks-tour/side-blocks-tour';
import { CoreBlockSideBlocksComponent } from '../side-blocks/side-blocks';
@@ -26,11 +28,25 @@ import { CoreBlockSideBlocksComponent } from '../side-blocks/side-blocks';
templateUrl: 'side-blocks-button.html',
styleUrls: ['side-blocks-button.scss'],
})
-export class CoreBlockSideBlocksButtonComponent {
+export class CoreBlockSideBlocksButtonComponent implements OnInit, OnDestroy {
@Input() courseId!: number;
@ViewChild('button', { read: ElementRef }) button?: ElementRef;
+ protected element: HTMLElement;
+ protected slotPromise?: CoreCancellablePromise;
+
+ constructor(el: ElementRef) {
+ this.element = el.nativeElement;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ async ngOnInit(): Promise {
+ this.slotPromise = CoreDom.slotOnContent(this.element);
+ }
+
/**
* Open side blocks.
*/
@@ -62,4 +78,11 @@ export class CoreBlockSideBlocksButtonComponent {
});
}
+ /**
+ * @inheritdoc
+ */
+ ngOnDestroy(): void {
+ this.slotPromise?.cancel();
+ }
+
}
diff --git a/src/core/features/course/format/singleactivity/components/core-course-format-single-activity.html b/src/core/features/course/format/singleactivity/components/core-course-format-single-activity.html
index 68eedcebf..aa42eeadb 100644
--- a/src/core/features/course/format/singleactivity/components/core-course-format-single-activity.html
+++ b/src/core/features/course/format/singleactivity/components/core-course-format-single-activity.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/core/features/courses/pages/dashboard/dashboard.html b/src/core/features/courses/pages/dashboard/dashboard.html
index 1e9771413..38dc1f17e 100644
--- a/src/core/features/courses/pages/dashboard/dashboard.html
+++ b/src/core/features/courses/pages/dashboard/dashboard.html
@@ -15,7 +15,7 @@
-
+
diff --git a/src/core/features/login/pages/credentials/credentials.html b/src/core/features/login/pages/credentials/credentials.html
index bac39ab1b..e8703bdfa 100644
--- a/src/core/features/login/pages/credentials/credentials.html
+++ b/src/core/features/login/pages/credentials/credentials.html
@@ -46,7 +46,7 @@
+ class="ion-margin core-login-login-button ion-text-wrap">
{{ 'core.login.loginbutton' | translate }}
diff --git a/src/core/features/login/pages/reconnect/reconnect.html b/src/core/features/login/pages/reconnect/reconnect.html
index 7854dfa37..8c6b71f6e 100644
--- a/src/core/features/login/pages/reconnect/reconnect.html
+++ b/src/core/features/login/pages/reconnect/reconnect.html
@@ -51,20 +51,15 @@
-
-
-
-
- {{ 'core.login.cancel' | translate }}
-
-
-
-
- {{ 'core.login.loginbutton' | translate }}
-
-
-
-
+
+
+ {{ 'core.login.cancel' | translate }}
+
+
+ {{ 'core.login.loginbutton' | translate }}
+
+
{{ 'core.login.or' | translate }}
diff --git a/src/core/features/sitehome/pages/index/index.html b/src/core/features/sitehome/pages/index/index.html
index 97f7ba85a..f7c3d0856 100644
--- a/src/core/features/sitehome/pages/index/index.html
+++ b/src/core/features/sitehome/pages/index/index.html
@@ -45,7 +45,7 @@
-
+
diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts
index b42da0973..9d2bc991a 100644
--- a/src/core/services/utils/dom.ts
+++ b/src/core/services/utils/dom.ts
@@ -336,12 +336,22 @@ export class CoreDomUtilsProvider {
/**
* Focus an element and open keyboard.
*
- * @param focusElement HTML element to focus.
+ * @param element HTML element to focus.
*/
- async focusElement(focusElement: HTMLElement): Promise {
+ async focusElement(
+ element: HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSearchbarElement | HTMLElement,
+ ): Promise {
let retries = 10;
- if (!focusElement.focus) {
+ let focusElement = element;
+
+ if ('getInputElement' in focusElement) {
+ // If it's an Ionic element get the right input to use.
+ focusElement.componentOnReady && await focusElement.componentOnReady();
+ focusElement = await focusElement.getInputElement();
+ }
+
+ if (!focusElement || !focusElement.focus) {
throw new CoreError('Element to focus cannot be focused');
}
diff --git a/src/core/singletons/dom.ts b/src/core/singletons/dom.ts
index 7bb8be177..fdd0dd9d0 100644
--- a/src/core/singletons/dom.ts
+++ b/src/core/singletons/dom.ts
@@ -205,6 +205,38 @@ export class CoreDom {
return CoreDom.scrollToElement(container, '.core-input-error');
}
+ /**
+ * Move element to content so it can be slotted.
+ *
+ * @param element HTML Element.
+ * @param slot Slot name.
+ * @return Promise resolved when done.
+ */
+ static slotOnContent(element: HTMLElement, slot = 'fixed'): CoreCancellablePromise {
+ element.setAttribute('slot', slot);
+ if (element.parentElement?.nodeName === 'ION-CONTENT') {
+ return CoreCancellablePromise.resolve();
+ }
+
+ const domPromise = CoreDom.waitToBeInDOM(element);
+
+ return new CoreCancellablePromise(
+ async (resolve) => {
+ await domPromise;
+
+ // Move element to the nearest ion-content if it's not the parent
+ if (element.parentElement?.nodeName !== 'ION-CONTENT') {
+ element.closest('ion-content')?.appendChild(element);
+ }
+
+ resolve();
+ },
+ () => {
+ domPromise.cancel();
+ },
+ );
+ }
+
/**
* Wait an element to be added to the root DOM.
*