From d973bd3028255052140918cc161be0423fef436c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Tue, 1 Mar 2022 15:38:22 +0100
Subject: [PATCH 1/3] MOBILE-3814 messages: Fix on some styles
---
.../messages/pages/discussion/discussion.html | 7 +-
src/addons/mod/chat/pages/chat/chat.html | 6 +-
.../session-messages/session-messages.html | 6 +-
.../comments/pages/viewer/viewer.html | 12 +-
.../components/user-menu/user-menu.ts | 2 +-
src/theme/components/discussion.scss | 342 +++++++++---------
src/theme/theme.light.scss | 6 +-
7 files changed, 184 insertions(+), 197 deletions(-)
diff --git a/src/addons/messages/pages/discussion/discussion.html b/src/addons/messages/pages/discussion/discussion.html
index 7427dbd18..cc9770632 100644
--- a/src/addons/messages/pages/discussion/discussion.html
+++ b/src/addons/messages/pages/discussion/discussion.html
@@ -69,8 +69,7 @@
{{ title }}
-
+
{{ message.timecreated | coreFormatDate: "strftimedayshort" }}
@@ -100,10 +99,10 @@
-
+
-
+
{{ message.timecreated | coreFormatDate: "strftimetime" }}
diff --git a/src/addons/mod/chat/pages/chat/chat.html b/src/addons/mod/chat/pages/chat/chat.html
index 0fc26f280..92e022753 100644
--- a/src/addons/mod/chat/pages/chat/chat.html
+++ b/src/addons/mod/chat/pages/chat/chat.html
@@ -93,13 +93,13 @@
{{ message.userfullname }}
-
+
-
+
- {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}
+ {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}
diff --git a/src/addons/mod/chat/pages/session-messages/session-messages.html b/src/addons/mod/chat/pages/session-messages/session-messages.html
index 7d0a57911..501e76cf8 100644
--- a/src/addons/mod/chat/pages/session-messages/session-messages.html
+++ b/src/addons/mod/chat/pages/session-messages/session-messages.html
@@ -86,13 +86,13 @@
{{ message.userfullname }}
-
+
-
- {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}
+
+ {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}
diff --git a/src/core/features/comments/pages/viewer/viewer.html b/src/core/features/comments/pages/viewer/viewer.html
index 4e1336a18..8a909686e 100644
--- a/src/core/features/comments/pages/viewer/viewer.html
+++ b/src/core/features/comments/pages/viewer/viewer.html
@@ -38,7 +38,7 @@
-
+
@@ -56,13 +56,13 @@
{{ comment.fullname }}
-
+
-
+
-
+
{{ comment.timecreated * 1000 | coreFormatDate: 'strftimetime' }}
@@ -94,11 +94,11 @@
{{ 'core.thereisdatatosync' | translate:{$a: 'core.comments.comments' | translate | lowercase } }}
-
+
-
+
{{ 'core.notsent' | translate }}
diff --git a/src/core/features/mainmenu/components/user-menu/user-menu.ts b/src/core/features/mainmenu/components/user-menu/user-menu.ts
index a43cb3f66..87cd958f9 100644
--- a/src/core/features/mainmenu/components/user-menu/user-menu.ts
+++ b/src/core/features/mainmenu/components/user-menu/user-menu.ts
@@ -207,7 +207,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
const closeAll = await CoreDomUtils.openSideModal({
component: CoreLoginSitesComponent,
- cssClass: 'core-modal-lateral-sm',
+ cssClass: 'core-modal-lateral core-modal-lateral-sm',
});
if (closeAll) {
diff --git a/src/theme/components/discussion.scss b/src/theme/components/discussion.scss
index be9ec19d3..d6756b142 100644
--- a/src/theme/components/discussion.scss
+++ b/src/theme/components/discussion.scss
@@ -1,185 +1,173 @@
@import "~theme/globals.scss";
-:host {
- ion-content {
- --background: var(--background-alternative);
-
- &::part(scroll) {
- padding-bottom: 0 !important;
- }
- }
-
- .addon-messages-discussion-container {
- display: flex;
- flex-direction: column;
- padding-bottom: 15px;
- background: var(--background-alternative);
- }
-
- .addon-messages-date {
- font-weight: normal;
- font-size: 0.9rem;
- }
-
- // Message item.
- ion-item.addon-message {
- border: 0;
- border-radius: var(--small-radius);
- padding: 0 8px 0 8px;
- margin: 10px 8px 0 8px;
- --background: var(--addon-messages-message-bg);
- background: var(--background);
- align-self: flex-start;
- width: 90%;
- max-width: 90%;
- --min-height: var(--a11y-min-target-size);
- position: relative;
- @include core-transition(width);
- // This is needed to display bubble tails.
- overflow: visible;
-
- &::part(native) {
- --inner-border-width: 0px;
- --inner-padding-end: 0px;
- padding: 0;
- margin: 0;
- }
-
- core-format-text > p:only-child {
- display: inline;
- }
-
- .addon-message-user {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- margin-bottom: .5rem;
- margin-top: 0;
- color: var(--ion-text-color);
-
- core-user-avatar {
- display: block;
- --core-avatar-size: var(--addon-messages-avatar-size);
- margin: 0;
- }
-
- div {
- font-weight: 500;
- flex-grow: 1;
- @include padding-horizontal(.5rem);
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- }
-
- ion-note {
- color: var(--addon-messages-message-note-text);
- font-size: var(--addon-messages-message-note-font-size);
- margin: 0;
- padding: 0 0 8px 0;
- align-self: flex-end;
- }
-
- &[tappable]:active {
- --background: var(--addon-messages-message-activated-bg);
- }
-
- ion-label {
- margin: 0;
- padding: 8px 0;
- }
-
- .addon-message-text {
- display: inline-flex;
- * {
- color: var(--ion-text-color);
- }
- }
-
- .tail {
- content: '';
- width: 0;
- height: 0;
- border: 0.5rem solid transparent;
- position: absolute;
- touch-action: none;
- bottom: 0;
- }
-
- // Defines when an item-message is the user's.
- &.addon-message-mine {
- --background: var(--addon-messages-message-mine-bg);
- align-self: flex-end;
-
- &[tappable]:active {
- --background: var(--addon-messages-message-mine-activated-bg);
- }
-
- .spinner {
- @include float(end);
- @include margin(2px, -3px, -2px, 5px);
-
- svg {
- width: 16px;
- height: 16px;
- }
- }
-
- .tail {
- @include position(null, -8px, null, null);
- @include margin-horizontal(null, -0.5rem);
- border-bottom-color: var(--addon-messages-message-mine-bg);
- }
-
- &[tappable]:active .tail {
- border-bottom-color: var(--addon-messages-message-mine-activated-bg);
- }
- }
-
- &.addon-message-not-mine .tail {
- border-bottom-color: var(--addon-messages-message-bg);
- @include position(null, null, null, -8px);
- @include margin-horizontal(-0.5rem, null);
- }
-
- &[tappable].addon-message-not-mine.activated .tail {
- border-bottom-color: var(--addon-messages-message-activated-bg);
- }
-
- .addon-messages-delete-button {
- min-height: initial;
- line-height: initial;
- @include margin(0, null, 0, null);
- height: var(--a11y-min-target-size) !important;
- align-self: flex-end;
-
- ion-icon {
- font-size: 1.4em;
- line-height: initial;
- color: var(--danger);
- }
- }
-
- &.addon-message-no-user {
- margin-top: 8px;
- }
- }
-
- ion-item.addon-message.addon-message-mine + ion-item.addon-message.addon-message-no-user.addon-message-mine,
- ion-item.addon-message.addon-message-not-mine + ion-item.addon-message.addon-message-no-user.addon-message-not-mine {
- .item-heading {
- margin-bottom: 0;
- }
- padding-top: 0;
- }
-
-}
-
:host-context(.ios) {
ion-footer .toolbar:last-child {
padding-bottom: 4px;
min-height: 0;
}
}
+
+ion-content {
+ --content-background: var(--background-alternative);
+ --background: var(--content-background);
+
+ &::part(scroll) {
+ padding-bottom: 0 !important;
+ }
+}
+
+.addon-messages-discussion-container {
+ display: flex;
+ flex-direction: column;
+ padding-bottom: 16px !important;
+ background: var(--content-background);
+}
+
+.addon-messages-date {
+ font-weight: normal;
+ font-size: 0.9rem;
+}
+
+// Message item.
+ion-item.addon-message {
+ --message-background: var(--addon-messages-message-bg);
+ --message-activated-background: var(--addon-messages-message-activated-bg);
+ --message-alignment: flex-start;
+
+ border: 0;
+ border-radius: var(--medium-radius);
+ padding: 0 8px 0 8px;
+ margin: 8px;
+ --background: var(--message-background);
+ background: var(--message-background);
+ align-self: var(--message-alignment);
+ width: 90%;
+ max-width: var(--list-item-max-width);
+ --min-height: var(--a11y-min-target-size);
+ position: relative;
+ @include core-transition(width);
+ // This is needed to display bubble tails.
+ overflow: visible;
+
+ &::part(native) {
+ --inner-border-width: 0px;
+ --inner-padding-end: 0px;
+ padding: 0;
+ margin: 0;
+ }
+
+ &:hover {
+ filter: drop-shadow(2px 2px 2px rgba(0,0,0,.3));
+ }
+
+ core-format-text > p:only-child {
+ display: inline;
+ }
+
+ .addon-message-user {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: .5rem;
+ margin-top: 0;
+ color: var(--ion-text-color);
+
+ core-user-avatar {
+ display: block;
+ --core-avatar-size: var(--addon-messages-avatar-size);
+ margin: 0;
+ }
+
+ div {
+ font-weight: 500;
+ flex-grow: 1;
+ padding-left: .5rem;
+ padding-right: .5rem;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+ }
+
+ ion-note {
+ color: var(--addon-messages-message-note-text);
+ font-size: var(--addon-messages-message-note-font-size);
+ margin: 0;
+ padding: 8px 0;
+ align-self: flex-start;
+ }
+
+ &[tappable]:active {
+ --message-background: var(--message-activated-background);
+ }
+
+ ion-label {
+ margin: 0;
+ padding: 8px 0;
+ }
+
+ .addon-message-text {
+ display: inline-flex;
+ * {
+ color: var(--ion-text-color);
+ }
+ }
+
+ .tail {
+ content: '';
+ width: 0;
+ height: 0;
+ border: 0.5rem solid transparent;
+ position: absolute;
+ touch-action: none;
+ bottom: 0;
+ border-bottom-color: var(--message-background);
+ }
+
+ // Defines when an item-message is the user's.
+ &.addon-message-mine {
+ --message-background: var(--addon-messages-message-mine-bg);
+ --message-activated-background: var(--addon-messages-message-mine-activated-bg);
+ --message-alignment: flex-end;
+
+ .spinner {
+ @include float(end);
+ @include margin(2px, -3px, -2px, 5px);
+
+ svg {
+ width: 16px;
+ height: 16px;
+ }
+ }
+
+ .tail {
+ @include position(null, -8px, null, null);
+ @include margin-horizontal(null, -0.5rem);
+ }
+ }
+
+ &.addon-message-not-mine .tail {
+ @include position(null, null, null, -8px);
+ @include margin-horizontal(-0.5rem, null);
+ }
+
+ .addon-messages-delete-button {
+ min-height: initial;
+ line-height: initial;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ height: var(--a11y-min-target-size) !important;
+ align-self: flex-end;
+
+ ion-icon {
+ font-size: 1.4em;
+ line-height: initial;
+ color: var(--danger);
+ }
+ }
+
+ &.addon-message-no-user {
+ margin-top: 0px;
+ }
+}
diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss
index e04f70066..5b44db892 100644
--- a/src/theme/theme.light.scss
+++ b/src/theme/theme.light.scss
@@ -104,7 +104,7 @@
ion-content {
--background: var(--ion-background-color);
- --background-alternative: var(--light);
+ --background-alternative: var(--gray-200);
}
--core-bottom-tabs-background: var(--white);
@@ -324,8 +324,8 @@
--addon-messages-message-activated-bg: var(--gray-200);
--addon-messages-message-note-text: var(--gray-500);
--addon-messages-message-note-font-size: 75%;
- --addon-messages-message-mine-bg: var(--gray-200);
- --addon-messages-message-mine-activated-bg: var(--gray-300);
+ --addon-messages-message-mine-bg: var(--gray-300);
+ --addon-messages-message-mine-activated-bg: var(--gray-400);
--addon-messages-avatar-size: 30px;
--addon-messages-discussion-badge: var(--primary);
--addon-messages-discussion-badge-text: var(--white);
From a91b19aedb3d38bc73a69f27eb3b659d3a2190a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Tue, 1 Mar 2022 15:38:39 +0100
Subject: [PATCH 2/3] MOBILE-3814 styles: Improve side modal widths
---
src/theme/globals.variables.scss | 2 --
src/theme/theme.base.scss | 60 ++++++++++----------------------
src/theme/theme.light.scss | 3 ++
3 files changed, 21 insertions(+), 44 deletions(-)
diff --git a/src/theme/globals.variables.scss b/src/theme/globals.variables.scss
index 5ab1d48fb..09430b3a4 100644
--- a/src/theme/globals.variables.scss
+++ b/src/theme/globals.variables.scss
@@ -79,8 +79,6 @@ $screen-breakpoints: (
xl: 1200px
) !default;
-$modal-lateral-width: 360px;
-
$core-course-image-background: #81ecec, #74b9ff, #a29bfe, #dfe6e9, #00b894, #0984e3, #b2bec3, #fdcb6e, #fd79a8, #6c5ce7 !default;
$core-dd-question-colors: #FFFFFF, #B0C4DE, #DCDCDC, #D8BFD8, #87CEFA, #DAA520, #FFD700, #F0E68C !default;
$core-text-hightlight-background-color: lighten($blue, 40%) !default;
diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss
index 2c79ec6b5..3181dbb72 100644
--- a/src/theme/theme.base.scss
+++ b/src/theme/theme.base.scss
@@ -628,55 +628,31 @@ body.core-iframe-fullscreen ion-router-outlet {
z-index: 100000 !important;
}
-.core-modal-lateral .modal-wrapper {
- @include margin-horizontal(16px, null);
-}
+.core-modal-lateral {
+ --ion-safe-area-left: 0px;
+ --ion-safe-area-right: 0px;
-@media only screen and (min-height: 400px) and (min-width: #{$modal-lateral-width}) {
- .core-modal-lateral {
- --ion-safe-area-left: 0px;
- --ion-safe-area-right: 0px;
+ .modal-wrapper {
+ @include margin-horizontal(var(--modal-lateral-margin), null);
- .modal-wrapper {
- position: absolute;
- @include position(0 !important, 0 !important, 0 !important, unset !important);
- display: block;
- height: 100% !important;
- width: auto;
- min-width: calc(#{$modal-lateral-width} - 16px);
- box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
- }
- ion-backdrop {
- visibility: visible;
- }
+ position: absolute;
+ @include position(0 !important, 0 !important, 0 !important, unset !important);
+ display: block;
+ height: 100% !important;
+ width: calc(100% - var(--modal-lateral-margin));
+ max-width: calc(var(--modal-lateral-max-width));
+ box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
+ }
+
+ ion-backdrop {
+ visibility: visible;
}
}
@each $breakpoint, $width in $screen-breakpoints {
- .core-modal-lateral-#{$breakpoint} .modal-wrapper {
- @include margin-horizontal(16px, null);
+ .core-modal-lateral-#{$breakpoint} {
+ --modal-lateral-max-width: #{$width};
}
-
- @media only screen and (min-height: 400px) and (min-width: #{$width}) {
- .core-modal-lateral-#{$breakpoint} {
- --ion-safe-area-left: 0px;
- --ion-safe-area-right: 0px;
-
- .modal-wrapper {
- position: absolute;
- @include position(0 !important, 0 !important, 0 !important, unset !important);
- display: block;
- height: 100% !important;
- width: auto;
- min-width: #{$width};
- box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
- }
- ion-backdrop {
- visibility: visible;
- }
- }
- }
-
}
// Hidden submit button.
diff --git a/src/theme/theme.light.scss b/src/theme/theme.light.scss
index 5b44db892..99cc6f2a9 100644
--- a/src/theme/theme.light.scss
+++ b/src/theme/theme.light.scss
@@ -81,6 +81,9 @@
--list-item-max-width: 768px;
+ --modal-lateral-max-width: 320px;
+ --modal-lateral-margin: 56px;
+
--contrast-background: white;
--ion-text-color: var(--text-color);
From 389a1c896411fd5a4900e079ffce3ebdb1701e86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?=
Date: Tue, 1 Mar 2022 14:23:29 +0100
Subject: [PATCH 3/3] MOBILE-3814 format-text: Fix expandable items height
---
src/core/directives/collapsible-footer.ts | 81 ++++++++++++++++-------
src/core/directives/collapsible-item.ts | 62 +++++++++++------
src/core/directives/format-text.ts | 35 ++++++----
src/theme/globals.mixins.scss | 14 ++--
4 files changed, 126 insertions(+), 66 deletions(-)
diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts
index 71fd0b7fd..4f87f379f 100644
--- a/src/core/directives/collapsible-footer.ts
+++ b/src/core/directives/collapsible-footer.ts
@@ -17,6 +17,10 @@ import { ScrollDetail } from '@ionic/core';
import { IonContent } from '@ionic/angular';
import { CoreUtils } from '@services/utils/utils';
import { CoreMath } from '@singletons/math';
+import { CoreComponentsRegistry } from '@singletons/components-registry';
+import { CoreFormatTextDirective } from './format-text';
+import { CoreDomUtils } from '@services/utils/dom';
+import { CoreEventLoadingChangedData, CoreEventObserver, CoreEvents } from '@singletons/events';
/**
* Directive to make an element fixed at the bottom collapsible when scrolling.
@@ -32,11 +36,12 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
protected element: HTMLElement;
protected initialHeight = 0;
- protected initialPaddingBottom = 0;
+ protected initialPaddingBottom = '0px';
protected previousTop = 0;
protected previousHeight = 0;
protected stickTimeout?: number;
protected content?: HTMLIonContentElement | null;
+ protected loadingChangedListener?: CoreEventObserver;
constructor(el: ElementRef, protected ionContent: IonContent) {
this.element = el.nativeElement;
@@ -44,30 +49,28 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
}
/**
- * Setup scroll event listener.
- *
- * @param retries Number of retries left.
+ * Calculate the height of the footer.
*/
- protected async listenScrollEvents(retries = 5): Promise {
- // Already initialized.
- if (this.initialHeight > 0) {
- return;
- }
+ protected async calculateHeight(): Promise {
+ await this.waitFormatTextsRendered(this.element);
- this.initialHeight = this.element.getBoundingClientRect().height;
-
- if (this.initialHeight == 0 && retries > 0) {
- await CoreUtils.nextTicks(50);
-
- this.listenScrollEvents(retries - 1);
-
- return;
- }
+ await CoreUtils.nextTick();
// Set a minimum height value.
- this.initialHeight = this.initialHeight || 48;
+ this.initialHeight = this.element.getBoundingClientRect().height || 48;
this.previousHeight = this.initialHeight;
+ this.setBarHeight(this.initialHeight);
+ }
+
+ /**
+ * Setup scroll event listener.
+ */
+ protected async listenScrollEvents(): Promise {
+ if (this.content) {
+ return;
+ }
+
this.content = this.element.closest('ion-content');
if (!this.content) {
@@ -82,12 +85,15 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
}
// Set a padding to not overlap elements.
- this.initialPaddingBottom = parseFloat(this.content.style.getPropertyValue('--padding-bottom') || '0');
- this.content.style.setProperty('--padding-bottom', this.initialPaddingBottom + this.initialHeight + 'px');
+ this.initialPaddingBottom = this.content.style.getPropertyValue('--padding-bottom') || this.initialPaddingBottom;
+ this.content.style.setProperty(
+ '--padding-bottom',
+ `calc(${this.initialPaddingBottom} + var(--core-collapsible-footer-height, 0px))`,
+ );
+
const scroll = await this.content.getScrollElement();
this.content.scrollEvents = true;
- this.setBarHeight(this.initialHeight);
this.content.addEventListener('ionScroll', (e: CustomEvent): void => {
if (!this.content) {
return;
@@ -98,6 +104,19 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
}
+ /**
+ * Wait until all children inside the element are done rendering.
+ *
+ * @param element Element.
+ */
+ protected async waitFormatTextsRendered(element: Element): Promise {
+ const formatTexts = Array
+ .from(element.querySelectorAll('core-format-text'))
+ .map(element => CoreComponentsRegistry.resolve(element, CoreFormatTextDirective));
+
+ await Promise.all(formatTexts.map(formatText => formatText?.rendered()));
+ }
+
/**
* On scroll function.
*
@@ -144,15 +163,29 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
/**
* @inheritdoc
*/
- ngOnInit(): void {
+ async ngOnInit(): Promise {
+ // Calculate the height now.
+ await this.calculateHeight();
+ setTimeout(() => this.calculateHeight(), 200); // Try again, sometimes the first calculation is wrong.
+
this.listenScrollEvents();
+
+ // Recalculate the height if a parent core-loading displays the content.
+ this.loadingChangedListener =
+ CoreEvents.on(CoreEvents.CORE_LOADING_CHANGED, async (data: CoreEventLoadingChangedData) => {
+ if (data.loaded && CoreDomUtils.closest(this.element.parentElement, '#' + data.uniqueId)) {
+ // The format-text is inside the loading, re-calculate the height.
+ await this.calculateHeight();
+ setTimeout(() => this.calculateHeight(), 200);
+ }
+ });
}
/**
* @inheritdoc
*/
async ngOnDestroy(): Promise {
- this.content?.style.setProperty('--padding-bottom', this.initialPaddingBottom + 'px');
+ this.content?.style.setProperty('--padding-bottom', this.initialPaddingBottom);
}
}
diff --git a/src/core/directives/collapsible-item.ts b/src/core/directives/collapsible-item.ts
index 5556d8669..3188421e9 100644
--- a/src/core/directives/collapsible-item.ts
+++ b/src/core/directives/collapsible-item.ts
@@ -14,8 +14,11 @@
import { Directive, ElementRef, Input, OnInit } from '@angular/core';
import { CoreDomUtils } from '@services/utils/dom';
+import { CoreUtils } from '@services/utils/utils';
import { Translate } from '@singletons';
+import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreEventLoadingChangedData, CoreEventObserver, CoreEvents } from '@singletons/events';
+import { CoreFormatTextDirective } from './format-text';
const defaultMaxHeight = 56;
const buttonHeight = 44;
@@ -54,7 +57,7 @@ export class CoreCollapsibleItemDirective implements OnInit {
/**
* @inheritdoc
*/
- ngOnInit(): void {
+ async ngOnInit(): Promise {
if (typeof this.height === 'string') {
this.maxHeight = this.height === ''
? defaultMaxHeight
@@ -70,31 +73,44 @@ export class CoreCollapsibleItemDirective implements OnInit {
}
// Calculate the height now.
- this.calculateHeight();
+ await this.calculateHeight();
setTimeout(() => this.calculateHeight(), 200); // Try again, sometimes the first calculation is wrong.
- this.setExpandButtonEnabled(false);
-
// Recalculate the height if a parent core-loading displays the content.
this.loadingChangedListener =
- CoreEvents.on(CoreEvents.CORE_LOADING_CHANGED, (data: CoreEventLoadingChangedData) => {
+ CoreEvents.on(CoreEvents.CORE_LOADING_CHANGED, async (data: CoreEventLoadingChangedData) => {
if (data.loaded && CoreDomUtils.closest(this.element.parentElement, '#' + data.uniqueId)) {
- // The format-text is inside the loading, re-calculate the height.
- this.calculateHeight();
+ // The element is inside the loading, re-calculate the height.
+ await this.calculateHeight();
setTimeout(() => this.calculateHeight(), 200);
}
});
}
+ /**
+ * Wait until all children inside the element are done rendering.
+ *
+ * @param element Element.
+ */
+ protected async waitFormatTextsRendered(element: Element): Promise {
+ const formatTexts = Array
+ .from(element.querySelectorAll('core-format-text'))
+ .map(element => CoreComponentsRegistry.resolve(element, CoreFormatTextDirective));
+
+ await Promise.all(formatTexts.map(formatText => formatText?.rendered()));
+ }
+
/**
* Calculate the height and check if we need to display show more or not.
*/
- protected calculateHeight(): void {
- // @todo: Work on calculate this height better.
+ protected async calculateHeight(): Promise {
+ await this.waitFormatTextsRendered(this.element);
// Remove max-height (if any) to calculate the real height.
const initialMaxHeight = this.element.style.maxHeight;
- this.element.style.maxHeight = '';
+ this.element.style.maxHeight = 'none';
+
+ await CoreUtils.nextTick();
const height = CoreDomUtils.getElementHeight(this.element) || 0;
@@ -102,7 +118,7 @@ export class CoreCollapsibleItemDirective implements OnInit {
this.element.style.maxHeight = initialMaxHeight;
// If cannot calculate height, shorten always.
- this.setExpandButtonEnabled(!height || height > this.maxHeight);
+ this.setExpandButtonEnabled(!height || height >= this.maxHeight);
}
/**
@@ -115,9 +131,7 @@ export class CoreCollapsibleItemDirective implements OnInit {
this.element.classList.toggle('collapsible-enabled', enable);
if (!enable || this.element.querySelector('ion-button.collapsible-toggle')) {
- this.element.style.maxHeight = !enable || this.expanded
- ? ''
- : this.maxHeight + 'px';
+ this.setMaxHeight(!enable || this.expanded? undefined : this.maxHeight);
return;
}
@@ -141,6 +155,19 @@ export class CoreCollapsibleItemDirective implements OnInit {
this.toggleExpand(this.expanded);
}
+ /**
+ * Set max height to element.
+ *
+ * @param maxHeight Max height if collapsed or undefined if expanded.
+ */
+ protected setMaxHeight(maxHeight?: number): void {
+ if (maxHeight) {
+ this.element.style.setProperty('--max-height', maxHeight + buttonHeight + 'px');
+ } else {
+ this.element.style.removeProperty('--max-height');
+ }
+ }
+
/**
* Expand or collapse text.
*
@@ -151,13 +178,8 @@ export class CoreCollapsibleItemDirective implements OnInit {
expand = !this.expanded;
}
this.expanded = expand;
- this.element.classList.toggle('collapsible-expanded', expand);
this.element.classList.toggle('collapsible-collapsed', !expand);
- if (expand) {
- this.element.style.setProperty('--max-height', this.maxHeight + buttonHeight + 'px');
- } else {
- this.element.style.removeProperty('--max-height');
- }
+ this.setMaxHeight(!expand? this.maxHeight: undefined);
const toggleButton = this.element.querySelector('ion-button.collapsible-toggle');
const toggleText = toggleButton?.querySelector('.collapsible-toggle-text');
diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts
index 5171ae54b..8d93e24d6 100644
--- a/src/core/directives/format-text.ts
+++ b/src/core/directives/format-text.ts
@@ -272,15 +272,19 @@ export class CoreFormatTextDirective implements OnChanges {
/**
* Calculate the height and check if we need to display show more or not.
*/
- protected calculateHeight(): void {
+ protected async calculateHeight(): Promise {
// @todo: Work on calculate this height better.
if (!this.maxHeight) {
return;
}
+ await this.rendered();
+
// Remove max-height (if any) to calculate the real height.
const initialMaxHeight = this.element.style.maxHeight;
- this.element.style.maxHeight = '';
+ this.element.style.maxHeight = 'none';
+
+ await CoreUtils.nextTick();
const height = this.getElementHeight(this.element);
@@ -288,7 +292,20 @@ export class CoreFormatTextDirective implements OnChanges {
this.element.style.maxHeight = initialMaxHeight;
// If cannot calculate height, shorten always.
- this.setExpandButtonEnabled(!height || height > this.maxHeight);
+ this.setExpandButtonEnabled(!height || height >= this.maxHeight);
+ }
+
+ /**
+ * Set max height to element.
+ *
+ * @param maxHeight Max height if collapsed or undefined if expanded.
+ */
+ protected setMaxHeight(maxHeight?: number): void {
+ if (maxHeight) {
+ this.element.style.setProperty('--max-height', maxHeight + 'px');
+ } else {
+ this.element.style.removeProperty('--max-height');
+ }
}
/**
@@ -301,9 +318,7 @@ export class CoreFormatTextDirective implements OnChanges {
this.element.classList.toggle('collapsible-enabled', enable);
if (!enable || this.element.querySelector('ion-button.collapsible-toggle')) {
- this.element.style.maxHeight = !enable || this.expanded
- ? ''
- : this.maxHeight + 'px';
+ this.setMaxHeight(!enable || this.expanded? undefined : this.maxHeight);
return;
}
@@ -337,13 +352,9 @@ export class CoreFormatTextDirective implements OnChanges {
expand = !this.expanded;
}
this.expanded = expand;
- this.element.classList.toggle('collapsible-expanded', expand);
this.element.classList.toggle('collapsible-collapsed', !expand);
- if (expand) {
- this.element.style.setProperty('--max-height', this.maxHeight + 'px');
- } else {
- this.element.style.removeProperty('--max-height');
- }
+ this.setMaxHeight(!expand? this.maxHeight: undefined);
+
const toggleButton = this.element.querySelector('ion-button.collapsible-toggle');
const toggleText = toggleButton?.querySelector('.collapsible-toggle-text');
if (!toggleButton || !toggleText) {
diff --git a/src/theme/globals.mixins.scss b/src/theme/globals.mixins.scss
index e77e74181..cbde34e92 100644
--- a/src/theme/globals.mixins.scss
+++ b/src/theme/globals.mixins.scss
@@ -235,6 +235,7 @@
@include media-breakpoint-down(sm) {
&.collapsible-enabled {
position:relative;
+ padding-bottom: var(--collapsible-min-button-height); // So the Show less button can fit.
--display-toggle: block;
.collapsible-toggle {
@@ -262,6 +263,8 @@
background-position: center;
background-repeat: no-repeat;
background-size: 14px 14px;
+ transform: rotate(-90deg);
+
@include core-transition(transform, 500ms);
@include push-arrow-color(626262, true);
@@ -275,7 +278,7 @@
&.collapsible-collapsed {
overflow: hidden;
min-height: calc(var(--collapsible-min-button-height) + 12px);
- max-height: calc(var(--max-height), auto);
+ max-height: calc(var(--max-height, auto));
.collapsible-toggle-arrow {
transform: rotate(90deg);
@@ -291,15 +294,6 @@
z-index: 6;
}
}
-
- &.collapsible-expanded {
- max-height: none !important;
- padding-bottom: var(--collapsible-min-button-height); // So the Show less button can fit.
-
- .collapsible-toggle-arrow {
- transform: rotate(-90deg);
- }
- }
}
}
}