MOBILE-3833 style: Shadow on collapsible footer only if not at bottom
parent
042619dd61
commit
602331d2c6
|
@ -445,13 +445,9 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
|||
return;
|
||||
}
|
||||
|
||||
// Don't use domUtils.getScrollHeight because it gives an outdated value after receiving a new message.
|
||||
const scrollHeight = this.scrollElement ? this.scrollElement.scrollHeight : 0;
|
||||
|
||||
// Check if we are at the bottom to scroll it after render.
|
||||
// Use a 5px error margin because in iOS there is 1px difference for some reason.
|
||||
this.scrollBottom = Math.abs(scrollHeight - (this.scrollElement?.scrollTop || 0) -
|
||||
(this.scrollElement?.clientHeight || 0)) < 5;
|
||||
this.scrollBottom = CoreDom.scrollIsBottom(this.scrollElement, 5);
|
||||
|
||||
if (this.messagesBeingSent > 0) {
|
||||
// Ignore polling due to a race condition.
|
||||
|
@ -510,39 +506,39 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
|||
* The scroll was moved. Update new messages count.
|
||||
*/
|
||||
scrollFunction(): void {
|
||||
if (this.newMessages > 0) {
|
||||
const scrollBottom = (this.scrollElement?.scrollTop || 0) + (this.scrollElement?.clientHeight || 0);
|
||||
const scrollHeight = (this.scrollElement?.scrollHeight || 0);
|
||||
if (scrollBottom > scrollHeight - 40) {
|
||||
// At the bottom, reset.
|
||||
this.setNewMessagesBadge(0);
|
||||
if (this.newMessages == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
if (CoreDom.scrollIsBottom(this.scrollElement, 40)) {
|
||||
// At the bottom, reset.
|
||||
this.setNewMessagesBadge(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollElRect = this.scrollElement?.getBoundingClientRect();
|
||||
const scrollBottomPos = (scrollElRect && scrollElRect.bottom) || 0;
|
||||
|
||||
if (scrollBottomPos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine'))
|
||||
.slice(-this.newMessages)
|
||||
.reverse();
|
||||
|
||||
const newMessagesUnread = messages.findIndex((message) => {
|
||||
const elementRect = message.getBoundingClientRect();
|
||||
if (!elementRect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const scrollElRect = this.scrollElement?.getBoundingClientRect();
|
||||
const scrollBottomPos = (scrollElRect && scrollElRect.bottom) || 0;
|
||||
return elementRect.bottom <= scrollBottomPos;
|
||||
});
|
||||
|
||||
if (scrollBottomPos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine'))
|
||||
.slice(-this.newMessages)
|
||||
.reverse();
|
||||
|
||||
const newMessagesUnread = messages.findIndex((message) => {
|
||||
const elementRect = message.getBoundingClientRect();
|
||||
if (!elementRect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return elementRect.bottom <= scrollBottomPos;
|
||||
});
|
||||
|
||||
if (newMessagesUnread > 0 && newMessagesUnread < this.newMessages) {
|
||||
this.setNewMessagesBadge(newMessagesUnread);
|
||||
}
|
||||
if (newMessagesUnread > 0 && newMessagesUnread < this.newMessages) {
|
||||
this.setNewMessagesBadge(newMessagesUnread);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import { CoreUrlUtils } from '@services/utils/url';
|
|||
import { CoreConstants } from '@/core/constants';
|
||||
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
|
||||
const MOODLE_VERSION_PREFIX = 'version-';
|
||||
const MOODLEAPP_VERSION_PREFIX = 'moodleapp-';
|
||||
|
@ -90,9 +91,21 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||
});
|
||||
|
||||
// Listen to scroll to add style when scroll is not 0.
|
||||
win.addEventListener('ionScroll', ({ detail, target }: CustomEvent<ScrollDetail>) => {
|
||||
const header = (target as HTMLElement).closest('.ion-page')?.querySelector('ion-header');
|
||||
header?.classList.toggle('core-header-shadow', detail.scrollTop > 0);
|
||||
win.addEventListener('ionScroll', async ({ detail, target }: CustomEvent<ScrollDetail>) => {
|
||||
if ((target as HTMLElement).tagName != 'ION-CONTENT') {
|
||||
return;
|
||||
}
|
||||
const content = (target as HTMLIonContentElement);
|
||||
|
||||
const page = content.closest('.ion-page');
|
||||
if (!page) {
|
||||
return;
|
||||
}
|
||||
|
||||
page.querySelector<HTMLIonHeaderElement>('ion-header')?.classList.toggle('core-header-shadow', detail.scrollTop > 0);
|
||||
|
||||
const scrollElement = await content.getScrollElement();
|
||||
content.classList.toggle('core-footer-shadow', !CoreDom.scrollIsBottom(scrollElement));
|
||||
});
|
||||
|
||||
// Listen for session expired events.
|
||||
|
|
|
@ -126,6 +126,9 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
|
|||
const scroll = await this.content.getScrollElement();
|
||||
this.content.scrollEvents = true;
|
||||
|
||||
// Init shadow.
|
||||
this.content.classList.toggle('core-footer-shadow', !CoreDom.scrollIsBottom(scroll));
|
||||
|
||||
this.content.addEventListener('ionScroll', this.contentScrollListener = (e: CustomEvent<ScrollDetail>): void => {
|
||||
if (!this.content) {
|
||||
return;
|
||||
|
|
|
@ -232,6 +232,21 @@ export class CoreDom {
|
|||
return CoreDom.scrollToElement(container, '.core-input-error');
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the scroll reached bottom?
|
||||
*
|
||||
* @param scrollElement Scroll Element.
|
||||
* @param marginError Error margin when calculating.
|
||||
* @return Wether the scroll reached the bottom.
|
||||
*/
|
||||
static scrollIsBottom(scrollElement?: HTMLElement, marginError = 0): boolean {
|
||||
if (!scrollElement) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return scrollElement.scrollTop + scrollElement.clientHeight >= scrollElement.scrollHeight - marginError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move element to content so it can be slotted.
|
||||
*
|
||||
|
|
|
@ -1434,8 +1434,11 @@ ion-grid.core-no-grid > ion-row {
|
|||
right: 0;
|
||||
}
|
||||
|
||||
[collapsible-footer] {
|
||||
.core-footer-shadow [collapsible-footer] {
|
||||
box-shadow: var(--drop-shadow-top, none);
|
||||
}
|
||||
[collapsible-footer] {
|
||||
transition: box-shadow 0.5s;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
|
|
Loading…
Reference in New Issue