From ef0ed6c7fb90ef1c84cb9cb8b019b30c151ce6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 11 May 2021 11:54:30 +0200 Subject: [PATCH] MOBILE-3753 calendar: Fix calendar navigation --- .../calendar/addon-calendar-calendar.html | 132 +++++++++++------- .../components/calendar/calendar.scss | 2 + .../calendar/components/calendar/calendar.ts | 40 +++++- .../calendar/pages/edit-event/edit-event.html | 75 ++++------ src/addons/calendar/services/calendar.ts | 1 + src/core/classes/aria-role-button.ts | 8 +- .../rich-text-editor/rich-text-editor.ts | 34 ++++- 7 files changed, 179 insertions(+), 113 deletions(-) diff --git a/src/addons/calendar/components/calendar/addon-calendar-calendar.html b/src/addons/calendar/components/calendar/addon-calendar-calendar.html index d80b34e36..7fe5c0da7 100644 --- a/src/addons/calendar/components/calendar/addon-calendar-calendar.html +++ b/src/addons/calendar/components/calendar/addon-calendar-calendar.html @@ -18,7 +18,7 @@ -

{{ periodName }}

+

{{ periodName }}

@@ -29,58 +29,88 @@ - - - - - {{ day.shortname | translate }} - {{ day.fullname | translate }} - - + +
+ + + + {{ day.fullname | translate }} + + + + +
+
- - - - - -

{{ day.mday }}

- - -

- - -
- -
- - - - - {{ event.timestart * 1000 | coreFormatDate: timeFormat }} - - - - {{ 'addon.calendar.type' + event.formattedType | translate }} - {{ event.iconTitle }} - - {{event.name}} -
-
-

- {{ 'core.nummore' | translate:{$a: day.filteredEvents.length - 3} }} + + + + + +

+ + {{ day.periodName | translate }}

-
-
- - -
+ + +

+ + +
+ +
+ + + + + {{ event.timestart * 1000 | coreFormatDate: timeFormat }} + + + + + {{ 'addon.calendar.type' + event.formattedType | translate }} + {{ event.iconTitle }} + + {{event.name}} +
+
+

+ {{ 'core.nummore' | translate:{$a: day.filteredEvents.length - 3} }} +

+
+ + + + +
diff --git a/src/addons/calendar/components/calendar/calendar.scss b/src/addons/calendar/components/calendar/calendar.scss index 848d6357c..5e22f595f 100644 --- a/src/addons/calendar/components/calendar/calendar.scss +++ b/src/addons/calendar/components/calendar/calendar.scss @@ -71,6 +71,7 @@ overflow: hidden; white-space: nowrap; color: var(--text-color); + min-height: auto; &.addon-calendar-event-past { opacity: 0.5; @@ -102,6 +103,7 @@ .addon-calendar-weekday { border-bottom: 1px solid var(--addon-calendar-border-color); + font-weight: bold; } .addon-calendar-day-events { diff --git a/src/addons/calendar/components/calendar/calendar.ts b/src/addons/calendar/components/calendar/calendar.ts index 34eb7ee31..5c28a9b69 100644 --- a/src/addons/calendar/components/calendar/calendar.ts +++ b/src/addons/calendar/components/calendar/calendar.ts @@ -41,6 +41,7 @@ import { AddonCalendarOffline } from '../../services/calendar-offline'; import { CoreCategoryData, CoreCourses } from '@features/courses/services/courses'; import { CoreApp } from '@services/app'; import { CoreLocalNotifications } from '@services/local-notifications'; +import { CoreAriaRoleButton } from '@classes/aria-role-button'; /** * Component that displays a calendar. @@ -67,6 +68,8 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro timeFormat?: string; isCurrentMonth = false; isPastMonth = false; + dayAction: AddonCalendarDayButton; + eventAction: AddonCalendarEventButton; protected year?: number; protected month?: number; @@ -88,6 +91,9 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro differs: KeyValueDiffers, ) { + this.dayAction = new AddonCalendarDayButton(this); + this.eventAction = new AddonCalendarEventButton(this); + this.currentSiteId = CoreSites.getCurrentSiteId(); if (CoreLocalNotifications.isAvailable()) { @@ -233,6 +239,10 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro this.weeks.forEach((week) => { week.days.forEach((day) => { + day.periodName = CoreTimeUtils.userDate( + new Date(this.year!, this.month! - 1, day.mday).getTime(), + 'core.strftimedaydate', + ); day.eventsFormated = day.eventsFormated || []; day.filteredEvents = day.filteredEvents || []; day.events.forEach((event) => { @@ -372,7 +382,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro * @param calendarEvent Calendar event.. * @param event Mouse event. */ - eventClicked(calendarEvent: AddonCalendarEventToDisplay, event: MouseEvent): void { + eventClicked(calendarEvent: AddonCalendarEventToDisplay, event: Event): void { this.onEventClicked.emit(calendarEvent.id); event.stopPropagation(); } @@ -525,3 +535,31 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro } } + +/** + * Helper class to manage day button. + */ +class AddonCalendarDayButton extends CoreAriaRoleButton { + + /** + * @inheritdoc + */ + click(event: Event, day: number): void { + this.componentInstance.dayClicked(day); + } + +} + +/** + * Helper class to manage event button. + */ +class AddonCalendarEventButton extends CoreAriaRoleButton { + + /** + * @inheritdoc + */ + click(event: Event, calendarEvent: AddonCalendarEventToDisplay): void { + this.componentInstance.eventClicked(calendarEvent, event); + } + +} diff --git a/src/addons/calendar/pages/edit-event/edit-event.html b/src/addons/calendar/pages/edit-event/edit-event.html index 78c05e1fb..fb22f3bd9 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.html +++ b/src/addons/calendar/pages/edit-event/edit-event.html @@ -16,9 +16,7 @@ -

- {{ 'addon.calendar.eventname' | translate }} -

+

{{ 'addon.calendar.eventname' | translate }}

@@ -27,11 +25,7 @@ - -

- {{ 'core.date' | translate }} -

-
+

{{ 'core.date' | translate }}

@@ -40,13 +34,15 @@ - -

- {{ 'addon.calendar.eventkind' | translate }} -

+ +

{{ 'addon.calendar.eventkind' | translate }}

- +

{{eventTypes[0].name | translate }}

+ {{ type.name | translate }} @@ -55,12 +51,8 @@ - -

- {{ 'core.category' | translate }} -

-
-

{{ 'core.category' | translate }}

+ {{ category.name }} @@ -70,12 +62,8 @@ - -

- {{ 'core.course' | translate }} -

-
-

{{ 'core.course' | translate }}

+ {{ course.fullname }} @@ -85,12 +73,8 @@ - -

- {{ 'core.course' | translate }} -

-
-

{{ 'core.course' | translate }}

+ @@ -104,12 +88,8 @@
- -

- {{ 'core.group' | translate }} -

-
-

{{ 'core.group' | translate }}

+ {{ group.name }} @@ -121,23 +101,20 @@
- +

{{ 'core.showmore' | translate }}

{{ 'core.showless' | translate }}

-
+
- -

{{ 'core.description' | translate }}

-
-

{{ 'core.description' | translate }}

+
@@ -154,9 +131,7 @@ -

- {{ 'addon.calendar.eventduration' | translate }} -

+

{{ 'addon.calendar.eventduration' | translate }}

@@ -200,9 +175,7 @@ -

- {{ 'addon.calendar.repeatedevents' | translate }} -

+

{{ 'addon.calendar.repeatedevents' | translate }}

diff --git a/src/addons/calendar/services/calendar.ts b/src/addons/calendar/services/calendar.ts index c1a01b8ec..b3b00e040 100644 --- a/src/addons/calendar/services/calendar.ts +++ b/src/addons/calendar/services/calendar.ts @@ -2026,6 +2026,7 @@ export type AddonCalendarWeekDay = AddonCalendarDay & { ispast?: boolean; // Calculated in the app. Whether the day is in the past. filteredEvents?: AddonCalendarEventToDisplay[]; // Calculated in the app. Filtered events. eventsFormated?: AddonCalendarEventToDisplay[]; // Events. + periodName?: string; }; /** diff --git a/src/core/classes/aria-role-button.ts b/src/core/classes/aria-role-button.ts index db15a0f9a..28a019a14 100644 --- a/src/core/classes/aria-role-button.ts +++ b/src/core/classes/aria-role-button.ts @@ -36,13 +36,14 @@ export abstract class CoreAriaRoleButton { * A11y key functionality that translates space and enter keys to click action. * * @param event Event. + * @param args Additional args. */ - keyUp(event: KeyboardEvent): void { + keyUp(event: KeyboardEvent, ...args: unknown[]): void { if ((event.key == ' ' || event.key == 'Enter') && this.isAllowed()) { event.preventDefault(); event.stopPropagation(); - this.click(event); + this.click(event, ...args); } } @@ -50,9 +51,10 @@ export abstract class CoreAriaRoleButton { * A11y click functionality. * * @param event Event. + * @param args Additional args. */ // eslint-disable-next-line @typescript-eslint/no-unused-vars - click(event?: Event): void { + click(event?: Event, ...args: unknown[]): void { // Nothing defined here. } diff --git a/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts b/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts index b1990106d..0b53152f3 100644 --- a/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts +++ b/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts @@ -89,8 +89,8 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn protected resetObserver?: CoreEventObserver; protected initHeightInterval?: number; protected isCurrentView = true; - protected toolbarButtonWidth = 40; - protected toolbarArrowWidth = 28; + protected toolbarButtonWidth = 44; + protected toolbarArrowWidth = 44; protected pageInstance: string; protected autoSaveInterval?: number; protected hideMessageTimeout?: number; @@ -100,6 +100,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn protected resizeFunction?: () => Promise; protected selectionChangeFunction?: () => void; protected languageChangedSubscription?: Subscription; + protected resizeObserver?: IntersectionObserver; rteEnabled = false; isPhone = false; @@ -127,6 +128,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn initialSlide: 0, slidesPerView: 6, centerInsufficientSlides: true, + watchSlidesVisibility: true, }; constructor( @@ -136,6 +138,14 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn this.contentChanged = new EventEmitter(); this.element = elementRef.nativeElement as HTMLDivElement; this.pageInstance = 'app_' + Date.now(); // Generate a "unique" ID based on timestamp. + + if ('IntersectionObserver' in window) { + this.resizeObserver = new IntersectionObserver((observerEntry: IntersectionObserverEntry[]) => { + if (observerEntry[0].boundingClientRect.width > 0) { + this.updateToolbarButtons(); + } + }); + } } /** @@ -231,8 +241,12 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn }); this.resizeFunction = this.maximizeEditorSize.bind(this); - this.selectionChangeFunction = this.updateToolbarStyles.bind(this); window.addEventListener('resize', this.resizeFunction!); + + // Start observing the target node for configured mutations + this.resizeObserver?.observe(this.element); + + this.selectionChangeFunction = this.updateToolbarStyles.bind(this); document.addEventListener('selectionchange', this.selectionChangeFunction!); this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, (kbHeight: number) => { @@ -273,7 +287,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn setTimeout(async () => { // Editor is ready, adjust Height if needed. - let height; + let height: number; if (CoreApp.isAndroid()) { // In Android we ignore the keyboard height because it is not part of the web view. @@ -760,6 +774,11 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn * Show the toolbar. */ showToolbar(event: Event): void { + if (!('IntersectionObserver' in window)) { + // Fallback if IntersectionObserver is not supported. + this.updateToolbarButtons(); + } + this.element.classList.add('ion-touched'); this.element.classList.remove('ion-untouched'); this.element.classList.add('has-focus'); @@ -776,7 +795,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn * @param event Event. */ stopBubble(event: Event): void { - if (event.type != 'mouseup' && event.type != 'keyup') { + if (event.type != 'touchend' &&event.type != 'mouseup' && event.type != 'keyup') { event.preventDefault(); } event.stopPropagation(); @@ -840,7 +859,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn * Update the number of toolbar buttons displayed. */ async updateToolbarButtons(): Promise { - if (!this.isCurrentView || !this.toolbar || !this.toolbarSlides) { + if (!this.isCurrentView || !this.toolbar || !this.toolbarSlides || this.element.offsetParent == null) { // Don't calculate if component isn't in current view, the calculations are wrong. return; } @@ -856,7 +875,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn return; } - if (width > length * this.toolbarButtonWidth) { + if (length > 0 && width > length * this.toolbarButtonWidth) { this.slidesOpts = { ...this.slidesOpts, slidesPerView: length }; this.toolbarArrows = false; } else { @@ -1096,6 +1115,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn clearInterval(this.initHeightInterval); clearInterval(this.autoSaveInterval); clearTimeout(this.hideMessageTimeout); + this.resizeObserver?.disconnect(); this.resetObserver?.off(); this.keyboardObserver?.off(); }