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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user