// (C) Copyright 2015 Moodle Pty Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CorePlatform } from '@services/platform'; /** * Singleton with helper functions to wait. */ export class CoreWait { /** * Wait until the next tick. * * @returns Promise resolved when tick has been done. */ static async nextTick(): Promise { return CoreWait.wait(0); } /** * Wait until several next ticks. * * @param numTicks Number of ticks to wait. */ static async nextTicks(numTicks = 0): Promise { for (let i = 0; i < numTicks; i++) { await CoreWait.wait(0); } } /** * Wait some time. * * @param milliseconds Number of milliseconds to wait. * @returns Promise resolved after the time has passed. */ static wait(milliseconds: number): Promise { return new Promise(resolve => setTimeout(resolve, milliseconds)); } /** * Wait until a given condition is met. * * @param condition Condition. * @returns Cancellable promise. */ static waitFor(condition: () => boolean): CoreCancellablePromise; static waitFor(condition: () => boolean, options: CoreWaitOptions): CoreCancellablePromise; static waitFor(condition: () => boolean, interval: number): CoreCancellablePromise; static waitFor(condition: () => boolean, optionsOrInterval: CoreWaitOptions | number = {}): CoreCancellablePromise { const options = typeof optionsOrInterval === 'number' ? { interval: optionsOrInterval } : optionsOrInterval; if (condition()) { return CoreCancellablePromise.resolve(); } const startTime = Date.now(); let intervalId: number | undefined; return new CoreCancellablePromise( async (resolve) => { intervalId = window.setInterval(() => { if (!condition() && (!options.timeout || (Date.now() - startTime < options.timeout))) { return; } resolve(); window.clearInterval(intervalId); }, options.interval ?? 50); }, () => window.clearInterval(intervalId), ); } /** * In iOS the resize event is triggered before the window size changes. Wait for the size to change. * Use of this function is discouraged. Please use CoreDom.onWindowResize to check window resize event. * * @param windowWidth Initial window width. * @param windowHeight Initial window height. * @param retries Number of retries done. * @returns Promise resolved when done. */ static async waitForResizeDone(windowWidth?: number, windowHeight?: number, retries = 0): Promise { if (!CorePlatform.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 CoreWait.wait(50); return CoreWait.waitForResizeDone(windowWidth, windowHeight, retries+1); } } /** * Options for waiting. */ export type CoreWaitOptions = { interval?: number; timeout?: number; };