commit
598f710678
|
@ -9,6 +9,12 @@
|
|||
color: white;
|
||||
border-radius: 50%;
|
||||
padding: 0.7rem;
|
||||
--margin-vertical: 12px;
|
||||
--margin-end: 12px;
|
||||
margin-top: var(--margin-vertical);
|
||||
margin-bottom: var(--margin-vertical);
|
||||
@include margin-horizontal(null, var(--margin-end));
|
||||
|
||||
}
|
||||
|
||||
@each $category, $value in $calendar-event-category-colors {
|
||||
|
|
|
@ -496,7 +496,6 @@ class AddonCalendarMonthSlidesItemsManagerSource extends CoreSwipeSlidesDynamicI
|
|||
const weeks = result.weeks as AddonCalendarWeek[];
|
||||
const currentDay = new Date().getDate();
|
||||
const currentTime = CoreTimeUtils.timestamp();
|
||||
let isPast = true;
|
||||
|
||||
const preloadedMonth: PreloadedMonth = {
|
||||
...month,
|
||||
|
@ -523,8 +522,7 @@ class AddonCalendarMonthSlidesItemsManagerSource extends CoreSwipeSlidesDynamicI
|
|||
|
||||
if (preloadedMonth.isCurrentMonth) {
|
||||
day.istoday = day.mday == currentDay;
|
||||
day.ispast = isPast && !day.istoday;
|
||||
isPast = day.ispast;
|
||||
day.ispast = preloadedMonth.isPastMonth || day.mday < currentDay;
|
||||
|
||||
if (day.istoday) {
|
||||
day.eventsFormated?.forEach((event) => {
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
</ion-label>
|
||||
<ion-radio slot="end" value="custom"></ion-radio>
|
||||
</ion-item>
|
||||
<ion-item class="ion-text-wrap">
|
||||
<ion-item class="ion-text-wrap" (click)="customInputClicked($event)">
|
||||
<ion-label></ion-label>
|
||||
|
||||
<div class="flex-row">
|
||||
|
|
|
@ -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 = <HTMLInputElement | Element | null> ev.target;
|
||||
if (target && 'focus' in target) {
|
||||
target.focus();
|
||||
const target = <HTMLInputElement | HTMLElement | null> ev.target;
|
||||
if (target) {
|
||||
CoreDomUtils.focusElement(target);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -50,11 +50,10 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
|
|||
protected contentScrollListener?: EventListener;
|
||||
protected endContentScrollListener?: EventListener;
|
||||
protected resizeListener?: CoreEventObserver;
|
||||
protected domPromise?: CoreCancellablePromise<void>;
|
||||
protected slotPromise?: CoreCancellablePromise<void>;
|
||||
|
||||
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<void> {
|
||||
// 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,19 +31,18 @@ export class CoreFabDirective implements OnInit, OnDestroy {
|
|||
protected element: HTMLElement;
|
||||
protected content?: HTMLIonContentElement | null;
|
||||
protected initialPaddingBottom = 0;
|
||||
protected domPromise?: CoreCancellablePromise<void>;
|
||||
protected slotPromise?: CoreCancellablePromise<void>;
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
this.element = el.nativeElement;
|
||||
this.element.setAttribute('slot', 'fixed');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<HTMLElement>;
|
||||
|
||||
protected element: HTMLElement;
|
||||
protected slotPromise?: CoreCancellablePromise<void>;
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
this.element = el.nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.slotPromise = CoreDom.slotOnContent(this.element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open side blocks.
|
||||
*/
|
||||
|
@ -62,4 +78,11 @@ export class CoreBlockSideBlocksButtonComponent {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.slotPromise?.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<core-dynamic-component [component]="componentClass" [data]="data"></core-dynamic-component>
|
||||
|
||||
<core-block-side-blocks-button *ngIf="course && hasBlocks" [courseId]="course.id">
|
||||
<core-block-side-blocks-button slot="fixed" *ngIf="course && hasBlocks" [courseId]="course.id">
|
||||
</core-block-side-blocks-button>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</ng-container>
|
||||
</ion-list>
|
||||
|
||||
<core-block-side-blocks-button *ngIf="hasSideBlocks"></core-block-side-blocks-button>
|
||||
<core-block-side-blocks-button slot="fixed" *ngIf="hasSideBlocks"></core-block-side-blocks-button>
|
||||
|
||||
<core-empty-box *ngIf="blocks.length == 0" icon="fas-cubes" [message]="'core.course.nocontentavailable' | translate">
|
||||
</core-empty-box>
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
</core-show-password>
|
||||
</ion-item>
|
||||
<ion-button expand="block" type="submit" [disabled]="siteChecked && !isBrowserSSO && !credForm.valid"
|
||||
class="ion-margin core-login-login-button">
|
||||
class="ion-margin core-login-login-button ion-text-wrap">
|
||||
{{ 'core.login.loginbutton' | translate }}
|
||||
</ion-button>
|
||||
<!-- Remove this once Ionic fixes this bug: https://github.com/ionic-team/ionic-framework/issues/19368 -->
|
||||
|
|
|
@ -51,20 +51,15 @@
|
|||
</ion-input>
|
||||
</core-show-password>
|
||||
</ion-item>
|
||||
<ion-grid class="ion-padding">
|
||||
<ion-row>
|
||||
<ion-col>
|
||||
<ion-button expand="block" fill="outline" (click)="cancel($event)">
|
||||
{{ 'core.login.cancel' | translate }}
|
||||
</ion-button>
|
||||
</ion-col>
|
||||
<ion-col>
|
||||
<ion-button type="submit" expand="block" [disabled]="!credForm.valid">
|
||||
{{ 'core.login.loginbutton' | translate }}
|
||||
</ion-button>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</ion-grid>
|
||||
<div class="adaptable-buttons-row">
|
||||
<ion-button expand="block" fill="outline" (click)="cancel($event)" class="ion-margin ion-text-wrap">
|
||||
{{ 'core.login.cancel' | translate }}
|
||||
</ion-button>
|
||||
<ion-button type="submit" expand="block" [disabled]="!credForm.valid"
|
||||
class="ion-margin core-login-login-button ion-text-wrap">
|
||||
{{ 'core.login.loginbutton' | translate }}
|
||||
</ion-button>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="showScanQR">
|
||||
<div class="ion-text-center ion-padding">{{ 'core.login.or' | translate }}</div>
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
</ng-container>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
<core-block-side-blocks-button *ngIf="hasBlocks" [courseId]="siteHomeId">
|
||||
<core-block-side-blocks-button slot="fixed" *ngIf="hasBlocks" [courseId]="siteHomeId">
|
||||
</core-block-side-blocks-button>
|
||||
|
||||
<core-empty-box *ngIf="!hasContent" icon="fas-box-open" [message]="'core.course.nocontentavailable' | translate">
|
||||
|
|
|
@ -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<void> {
|
||||
async focusElement(
|
||||
element: HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSearchbarElement | HTMLElement,
|
||||
): Promise<void> {
|
||||
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');
|
||||
}
|
||||
|
||||
|
|
|
@ -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<void> {
|
||||
element.setAttribute('slot', slot);
|
||||
if (element.parentElement?.nodeName === 'ION-CONTENT') {
|
||||
return CoreCancellablePromise.resolve();
|
||||
}
|
||||
|
||||
const domPromise = CoreDom.waitToBeInDOM(element);
|
||||
|
||||
return new CoreCancellablePromise<void>(
|
||||
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.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue