commit
e6ca385312
|
@ -174,6 +174,6 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<core-send-message-form *ngIf="footerType == 'message'" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard"
|
<core-send-message-form *ngIf="footerType == 'message'" (onSubmit)="sendMessage($event)" [showKeyboard]="showKeyboard"
|
||||||
[placeholder]="'addon.messages.newmessage' | translate" (onResize)="resizeContent()"></core-send-message-form>
|
[placeholder]="'addon.messages.newmessage' | translate"></core-send-message-form>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-footer>
|
</ion-footer>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { IonContent } from '@ionic/angular';
|
import { IonContent } from '@ionic/angular';
|
||||||
import { AlertOptions } from '@ionic/core';
|
import { AlertOptions } from '@ionic/core';
|
||||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||||
|
@ -76,6 +76,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
protected viewDestroyed = false;
|
protected viewDestroyed = false;
|
||||||
protected memberInfoObserver: CoreEventObserver;
|
protected memberInfoObserver: CoreEventObserver;
|
||||||
protected showLoadingModal = false; // Whether to show a loading modal while fetching data.
|
protected showLoadingModal = false; // Whether to show a loading modal while fetching data.
|
||||||
|
protected hostElement: HTMLElement;
|
||||||
|
|
||||||
conversationId?: number; // Conversation ID. Undefined if it's a new individual conversation.
|
conversationId?: number; // Conversation ID. Undefined if it's a new individual conversation.
|
||||||
conversation?: AddonMessagesConversationFormatted; // The conversation object (if it exists).
|
conversation?: AddonMessagesConversationFormatted; // The conversation object (if it exists).
|
||||||
|
@ -109,10 +110,13 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
newMessages = 0;
|
newMessages = 0;
|
||||||
scrollElement?: HTMLElement;
|
scrollElement?: HTMLElement;
|
||||||
unreadMessageFrom = 0;
|
unreadMessageFrom = 0;
|
||||||
|
initialized = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected route: ActivatedRoute,
|
protected route: ActivatedRoute,
|
||||||
|
protected elementRef: ElementRef<HTMLElement>,
|
||||||
) {
|
) {
|
||||||
|
this.hostElement = elementRef.nativeElement;
|
||||||
this.siteId = CoreSites.getCurrentSiteId();
|
this.siteId = CoreSites.getCurrentSiteId();
|
||||||
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
this.currentUserId = CoreSites.getCurrentSiteUserId();
|
||||||
this.groupMessagingEnabled = AddonMessages.isGroupMessagingEnabled();
|
this.groupMessagingEnabled = AddonMessages.isGroupMessagingEnabled();
|
||||||
|
@ -162,6 +166,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
this.route.queryParams.subscribe(async (params) => {
|
this.route.queryParams.subscribe(async (params) => {
|
||||||
const oldConversationId = this.conversationId;
|
const oldConversationId = this.conversationId;
|
||||||
const oldUserId = this.userId;
|
const oldUserId = this.userId;
|
||||||
|
let forceScrollToBottom = false;
|
||||||
this.conversationId = CoreNavigator.getRouteNumberParam('conversationId', { params }) || undefined;
|
this.conversationId = CoreNavigator.getRouteNumberParam('conversationId', { params }) || undefined;
|
||||||
this.userId = CoreNavigator.getRouteNumberParam('userId', { params }) || undefined;
|
this.userId = CoreNavigator.getRouteNumberParam('userId', { params }) || undefined;
|
||||||
this.showInfo = !params.hideInfo;
|
this.showInfo = !params.hideInfo;
|
||||||
|
@ -169,13 +174,15 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
if (oldConversationId != this.conversationId || oldUserId != this.userId) {
|
if (oldConversationId != this.conversationId || oldUserId != this.userId) {
|
||||||
// Showing reload again can break animations.
|
// Showing reload again can break animations.
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
|
this.initialized = false;
|
||||||
|
forceScrollToBottom = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showKeyboard = CoreNavigator.getRouteBooleanParam('showKeyboard', { params }) || false;
|
this.showKeyboard = CoreNavigator.getRouteBooleanParam('showKeyboard', { params }) || false;
|
||||||
|
|
||||||
await this.fetchData();
|
await this.fetchData();
|
||||||
|
|
||||||
this.scrollToBottom();
|
this.scrollToBottom(forceScrollToBottom);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +360,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
CoreDomUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingmessages', true);
|
CoreDomUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingmessages', true);
|
||||||
} finally {
|
} finally {
|
||||||
this.checkCanDelete();
|
this.checkCanDelete();
|
||||||
this.resizeContent();
|
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
this.setPolling(); // Make sure we're polling messages.
|
this.setPolling(); // Make sure we're polling messages.
|
||||||
this.setContactRequestInfo();
|
this.setContactRequestInfo();
|
||||||
|
@ -481,10 +487,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
message.showTail = this.showTail(message, this.messages[index + 1]);
|
message.showTail = this.showTail(message, this.messages[index + 1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Call resize to recalculate the dimensions.
|
|
||||||
// @todo probably not needed.
|
|
||||||
// this.content!.resize();
|
|
||||||
|
|
||||||
// If we received a new message while using group messaging, force mark messages as read.
|
// If we received a new message while using group messaging, force mark messages as read.
|
||||||
const last = this.messages[this.messages.length - 1];
|
const last = this.messages[this.messages.length - 1];
|
||||||
const forceMark = this.groupMessagingEnabled && last && last.useridfrom != this.currentUserId && this.lastMessage.text != ''
|
const forceMark = this.groupMessagingEnabled && last && last.useridfrom != this.currentUserId && this.lastMessage.text != ''
|
||||||
|
@ -537,7 +539,9 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = Array.from(document.querySelectorAll('.addon-message-not-mine')).slice(-this.newMessages).reverse();
|
const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine'))
|
||||||
|
.slice(-this.newMessages)
|
||||||
|
.reverse();
|
||||||
|
|
||||||
const newMessagesUnread = messages.findIndex((message) => {
|
const newMessagesUnread = messages.findIndex((message) => {
|
||||||
const elementRect = message.getBoundingClientRect();
|
const elementRect = message.getBoundingClientRect();
|
||||||
|
@ -1036,7 +1040,16 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
* @return Resolved when done.
|
* @return Resolved when done.
|
||||||
*/
|
*/
|
||||||
async loadPrevious(infiniteComplete?: () => void): Promise<void> {
|
async loadPrevious(infiniteComplete?: () => void): Promise<void> {
|
||||||
let infiniteHeight = this.infinite?.infiniteEl?.nativeElement.getBoundingClientRect().height || 0;
|
if (!this.initialized) {
|
||||||
|
// Don't load previous if the view isn't fully initialized.
|
||||||
|
// Don't put the initialized condition in the "enabled" input because then the load more is hidden and
|
||||||
|
// the scroll height changes when it appears.
|
||||||
|
infiniteComplete && infiniteComplete();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let infiniteHeight = this.infinite?.hostElement.getBoundingClientRect().height || 0;
|
||||||
const scrollHeight = (this.scrollElement?.scrollHeight || 0);
|
const scrollHeight = (this.scrollElement?.scrollHeight || 0);
|
||||||
|
|
||||||
// If there is an ongoing fetch, wait for it to finish.
|
// If there is an ongoing fetch, wait for it to finish.
|
||||||
|
@ -1051,7 +1064,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
// Try to keep the scroll position.
|
// Try to keep the scroll position.
|
||||||
const scrollBottom = scrollHeight - (this.scrollElement?.scrollTop || 0);
|
const scrollBottom = scrollHeight - (this.scrollElement?.scrollTop || 0);
|
||||||
|
|
||||||
const height = this.infinite?.infiniteEl?.nativeElement.getBoundingClientRect().height || 0;
|
const height = this.infinite?.hostElement.getBoundingClientRect().height || 0;
|
||||||
if (this.canLoadMore && infiniteHeight && this.infinite) {
|
if (this.canLoadMore && infiniteHeight && this.infinite) {
|
||||||
// The height of the infinite is different while spinner is shown. Add that difference.
|
// The height of the infinite is different while spinner is shown. Add that difference.
|
||||||
infiniteHeight = infiniteHeight - height;
|
infiniteHeight = infiniteHeight - height;
|
||||||
|
@ -1073,10 +1086,8 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keep scroll position after loading previous messages.
|
* Keep scroll position after loading previous messages.
|
||||||
* We don't use resizeContent because the approach used is different and it isn't easy to calculate these positions.
|
|
||||||
*/
|
*/
|
||||||
protected keepScroll(oldScrollHeight: number, oldScrollBottom: number, infiniteHeight: number, retries = 0): void {
|
protected keepScroll(oldScrollHeight: number, oldScrollBottom: number, infiniteHeight: number, retries = 0): void {
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newScrollHeight = (this.scrollElement?.scrollHeight || 0);
|
const newScrollHeight = (this.scrollElement?.scrollHeight || 0);
|
||||||
|
|
||||||
|
@ -1089,53 +1100,39 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scroll has changed, but maybe it hasn't reached the full height yet.
|
||||||
|
setTimeout(() => {
|
||||||
|
const newScrollHeight = (this.scrollElement?.scrollHeight || 0);
|
||||||
const scrollTo = newScrollHeight - oldScrollBottom + infiniteHeight;
|
const scrollTo = newScrollHeight - oldScrollBottom + infiniteHeight;
|
||||||
|
|
||||||
this.content!.scrollToPoint(0, scrollTo, 0);
|
this.content!.scrollToPoint(0, scrollTo, 0);
|
||||||
}, 30);
|
}, 30);
|
||||||
}
|
}, 30);
|
||||||
|
|
||||||
/**
|
|
||||||
* Content or scroll has been resized. For content, only call it if it's been added on top.
|
|
||||||
*/
|
|
||||||
resizeContent(): void {
|
|
||||||
/* @todo probably not needed.
|
|
||||||
let top = this.content!.getContentDimensions().scrollTop;
|
|
||||||
// @todo this.content.resize();
|
|
||||||
|
|
||||||
// Wait for new content height to be calculated.
|
|
||||||
setTimeout(() => {
|
|
||||||
// Visible content size changed, maintain the bottom position.
|
|
||||||
if (!this.viewDestroyed && (this.scrollElement?.clientHeight || 0) != this.oldContentHeight) {
|
|
||||||
if (!top) {
|
|
||||||
top = this.content!.getContentDimensions().scrollTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
top += this.oldContentHeight - (this.scrollElement?.clientHeight || 0);
|
|
||||||
this.oldContentHeight = (this.scrollElement?.clientHeight || 0);
|
|
||||||
|
|
||||||
this.content!.scrollToPoint(0, top, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scroll bottom when render has finished.
|
* Scroll bottom when render has finished.
|
||||||
|
*
|
||||||
|
* @param force Whether to force scroll to bottom.
|
||||||
*/
|
*/
|
||||||
scrollToBottom(): void {
|
async scrollToBottom(force = false): Promise<void> {
|
||||||
// Check if scroll is at bottom. If so, scroll bottom after rendering since there might be something new.
|
// Check if scroll is at bottom. If so, scroll bottom after rendering since there might be something new.
|
||||||
if (this.scrollBottom) {
|
if (this.scrollBottom || force) {
|
||||||
// Need a timeout to leave time to the view to be rendered.
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!this.viewDestroyed) {
|
|
||||||
this.content!.scrollToBottom(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.scrollBottom = false;
|
this.scrollBottom = false;
|
||||||
|
|
||||||
// Reset the badge.
|
// Reset the badge.
|
||||||
this.setNewMessagesBadge(0);
|
this.setNewMessagesBadge(0);
|
||||||
|
|
||||||
|
// Leave time for the view to be rendered.
|
||||||
|
await CoreUtils.nextTicks(5);
|
||||||
|
|
||||||
|
if (!this.viewDestroyed) {
|
||||||
|
this.content!.scrollToBottom(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (force) {
|
||||||
|
this.initialized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,7 +1141,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
|
||||||
*/
|
*/
|
||||||
scrollToFirstUnreadMessage(): void {
|
scrollToFirstUnreadMessage(): void {
|
||||||
if (this.newMessages > 0) {
|
if (this.newMessages > 0) {
|
||||||
const messages = Array.from(document.querySelectorAll('.addon-message-not-mine'));
|
const messages = Array.from(this.hostElement.querySelectorAll('.addon-message-not-mine'));
|
||||||
|
|
||||||
CoreDomUtils.scrollToElement(this.content!, <HTMLElement> messages[messages.length - this.newMessages]);
|
CoreDomUtils.scrollToElement(this.content!, <HTMLElement> messages[messages.length - this.newMessages]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -360,7 +360,7 @@ export class AddonQtypeDdImageOrTextQuestion {
|
||||||
this.pollForImageLoad();
|
this.pollForImageLoad();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resizeFunction = this.repositionDragsForQuestion.bind(this);
|
this.resizeFunction = this.windowResized.bind(this);
|
||||||
window.addEventListener('resize', this.resizeFunction!);
|
window.addEventListener('resize', this.resizeFunction!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,6 +679,15 @@ export class AddonQtypeDdImageOrTextQuestion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window resized.
|
||||||
|
*/
|
||||||
|
async windowResized(): Promise<void> {
|
||||||
|
await CoreDomUtils.waitForResizeDone();
|
||||||
|
|
||||||
|
this.repositionDragsForQuestion();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -601,7 +601,7 @@ export class AddonQtypeDdMarkerQuestion {
|
||||||
this.pollForImageLoad();
|
this.pollForImageLoad();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resizeFunction = this.redrawDragsAndDrops.bind(this);
|
this.resizeFunction = this.windowResized.bind(this);
|
||||||
window.addEventListener('resize', this.resizeFunction!);
|
window.addEventListener('resize', this.resizeFunction!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -869,6 +869,15 @@ export class AddonQtypeDdMarkerQuestion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window resized.
|
||||||
|
*/
|
||||||
|
async windowResized(): Promise<void> {
|
||||||
|
await CoreDomUtils.waitForResizeDone();
|
||||||
|
|
||||||
|
this.redrawDragsAndDrops();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -214,7 +214,7 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
|
|
||||||
this.positionDragItems();
|
this.positionDragItems();
|
||||||
|
|
||||||
this.resizeFunction = this.positionDragItems.bind(this);
|
this.resizeFunction = this.windowResized.bind(this);
|
||||||
window.addEventListener('resize', this.resizeFunction!);
|
window.addEventListener('resize', this.resizeFunction!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,6 +515,15 @@ export class AddonQtypeDdwtosQuestion {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Window resized.
|
||||||
|
*/
|
||||||
|
async windowResized(): Promise<void> {
|
||||||
|
await CoreDomUtils.waitForResizeDone();
|
||||||
|
|
||||||
|
this.positionDragItems();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange, ViewChild, ElementRef } from '@angular/core';
|
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange, ViewChild, ElementRef } from '@angular/core';
|
||||||
import { IonContent, IonInfiniteScroll } from '@ionic/angular';
|
import { IonInfiniteScroll } from '@ionic/angular';
|
||||||
import { CoreDomUtils } from '@services/utils/dom';
|
import { CoreDomUtils } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
|
||||||
|
@ -37,15 +37,16 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
|
||||||
@Output() action: EventEmitter<() => void>; // Will emit an event when triggered.
|
@Output() action: EventEmitter<() => void>; // Will emit an event when triggered.
|
||||||
|
|
||||||
@ViewChild('topbutton') topButton?: ElementRef;
|
@ViewChild('topbutton') topButton?: ElementRef;
|
||||||
@ViewChild('infinitescroll') infiniteEl?: ElementRef;
|
|
||||||
@ViewChild('bottombutton') bottomButton?: ElementRef;
|
@ViewChild('bottombutton') bottomButton?: ElementRef;
|
||||||
@ViewChild('spinnercontainer') spinnerContainer?: ElementRef;
|
@ViewChild('spinnercontainer') spinnerContainer?: ElementRef;
|
||||||
@ViewChild(IonInfiniteScroll) infiniteScroll?: IonInfiniteScroll;
|
@ViewChild(IonInfiniteScroll) infiniteScroll?: IonInfiniteScroll;
|
||||||
|
|
||||||
loadingMore = false; // Hide button and avoid loading more.
|
loadingMore = false; // Hide button and avoid loading more.
|
||||||
|
hostElement: HTMLElement;
|
||||||
|
|
||||||
constructor(protected element: ElementRef) {
|
constructor(protected element: ElementRef<HTMLElement>) {
|
||||||
this.action = new EventEmitter();
|
this.action = new EventEmitter();
|
||||||
|
this.hostElement = element.nativeElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,14 +77,14 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
|
||||||
await CoreUtils.nextTick();
|
await CoreUtils.nextTick();
|
||||||
|
|
||||||
// Calculate distance from edge.
|
// Calculate distance from edge.
|
||||||
const content = this.element.nativeElement.closest('ion-content') as IonContent;
|
const content = this.hostElement.closest('ion-content');
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const scrollElement = await content.getScrollElement();
|
const scrollElement = await content.getScrollElement();
|
||||||
|
|
||||||
const infiniteHeight = this.element.nativeElement.getBoundingClientRect().height;
|
const infiniteHeight = this.hostElement.getBoundingClientRect().height;
|
||||||
const scrollTop = scrollElement.scrollTop;
|
const scrollTop = scrollElement.scrollTop;
|
||||||
const height = scrollElement.offsetHeight;
|
const height = scrollElement.offsetHeight;
|
||||||
const threshold = height * THRESHOLD;
|
const threshold = height * THRESHOLD;
|
||||||
|
@ -141,11 +142,20 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
|
||||||
* @deprecated since 3.9.5
|
* @deprecated since 3.9.5
|
||||||
*/
|
*/
|
||||||
getHeight(): number {
|
getHeight(): number {
|
||||||
// return this.element.nativeElement.getBoundingClientRect().height;
|
return (this.position == 'top' ?
|
||||||
|
this.getElementHeight(this.topButton?.nativeElement) :
|
||||||
|
this.getElementHeight(this.bottomButton?.nativeElement)) +
|
||||||
|
this.getElementHeight(this.infiniteScrollElement) +
|
||||||
|
this.getElementHeight(this.spinnerContainer?.nativeElement);
|
||||||
|
}
|
||||||
|
|
||||||
return (this.position == 'top' ? this.getElementHeight(this.topButton): this.getElementHeight(this.bottomButton)) +
|
/**
|
||||||
this.getElementHeight(this.infiniteEl) +
|
* Get the infinite scroll element.
|
||||||
this.getElementHeight(this.spinnerContainer);
|
*
|
||||||
|
* @return Element or null.
|
||||||
|
*/
|
||||||
|
get infiniteScrollElement(): HTMLIonInfiniteScrollElement | null {
|
||||||
|
return this.hostElement.querySelector('ion-infinite-scroll');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -154,9 +164,9 @@ export class CoreInfiniteLoadingComponent implements OnChanges {
|
||||||
* @param element Element ref.
|
* @param element Element ref.
|
||||||
* @return Height.
|
* @return Height.
|
||||||
*/
|
*/
|
||||||
protected getElementHeight(element?: ElementRef): number {
|
protected getElementHeight(element?: HTMLElement | null): number {
|
||||||
if (element && element.nativeElement) {
|
if (element) {
|
||||||
return CoreDomUtils.getElementHeight(element.nativeElement, true, true, true);
|
return CoreDomUtils.getElementHeight(element, true, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1861,6 +1861,32 @@ export class CoreDomUtilsProvider {
|
||||||
CoreForms.triggerFormSubmittedEvent(formRef, online, siteId);
|
CoreForms.triggerFormSubmittedEvent(formRef, online, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In iOS the resize event is triggered before the window size changes. Wait for the size to change.
|
||||||
|
*
|
||||||
|
* @param windowWidth Initial window width.
|
||||||
|
* @param windowHeight Initial window height.
|
||||||
|
* @param retries Number of retries done.
|
||||||
|
*/
|
||||||
|
async waitForResizeDone(windowWidth?: number, windowHeight?: number, retries = 0): Promise<void> {
|
||||||
|
if (!CoreApp.isIOS()) {
|
||||||
|
return; // Only wait in iOS.
|
||||||
|
}
|
||||||
|
|
||||||
|
windowWidth = windowWidth || window.innerWidth;
|
||||||
|
windowHeight = windowHeight || window.innerHeight;
|
||||||
|
|
||||||
|
if (windowWidth != window.innerWidth || windowHeight != window.innerHeight || retries >= 10) {
|
||||||
|
// Window size changed or max number of retries reached, stop.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait a bit and try again.
|
||||||
|
await CoreUtils.wait(50);
|
||||||
|
|
||||||
|
return this.waitForResizeDone(windowWidth, windowHeight, retries+1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1666,6 +1666,15 @@ export class CoreUtilsProvider {
|
||||||
return this.wait(0);
|
return this.wait(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until several next ticks.
|
||||||
|
*/
|
||||||
|
async nextTicks(numTicks = 0): Promise<void> {
|
||||||
|
for (let i = 0; i < numTicks; i++) {
|
||||||
|
await this.wait(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given some options, check if a file should be opened with showOpenWithDialog.
|
* Given some options, check if a file should be opened with showOpenWithDialog.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue