mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-09 08:09:32 +08:00
118 lines
3.3 KiB
TypeScript
118 lines
3.3 KiB
TypeScript
import { EventEmitter } from '@stencil/core';
|
|
|
|
import { Side } from '../interface';
|
|
|
|
declare const __zone_symbol__requestAnimationFrame: any;
|
|
declare const requestAnimationFrame: any;
|
|
|
|
/**
|
|
* Patched version of requestAnimationFrame that avoids ngzone
|
|
* Use only when you know ngzone should not run
|
|
*/
|
|
export const raf = (h: any) => {
|
|
if (typeof __zone_symbol__requestAnimationFrame === 'function') {
|
|
return __zone_symbol__requestAnimationFrame(h);
|
|
}
|
|
if (typeof requestAnimationFrame === 'function') {
|
|
return requestAnimationFrame(h);
|
|
}
|
|
return setTimeout(h);
|
|
};
|
|
|
|
export const hasShadowDom = (el: HTMLElement) => {
|
|
return !!el.shadowRoot && !!(el as any).attachShadow;
|
|
};
|
|
|
|
export const findItemLabel = (componentEl: HTMLElement) => {
|
|
const itemEl = componentEl.closest('ion-item');
|
|
if (itemEl) {
|
|
return itemEl.querySelector('ion-label');
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const renderHiddenInput = (always: boolean, container: HTMLElement, name: string, value: string | undefined | null, disabled: boolean) => {
|
|
if (always || hasShadowDom(container)) {
|
|
let input = container.querySelector('input.aux-input') as HTMLInputElement | null;
|
|
if (!input) {
|
|
input = container.ownerDocument!.createElement('input');
|
|
input.type = 'hidden';
|
|
input.classList.add('aux-input');
|
|
container.appendChild(input);
|
|
}
|
|
input.disabled = disabled;
|
|
input.name = name;
|
|
input.value = value || '';
|
|
}
|
|
};
|
|
|
|
export const clamp = (min: number, n: number, max: number) => {
|
|
return Math.max(min, Math.min(n, max));
|
|
};
|
|
|
|
export const assert = (actual: any, reason: string) => {
|
|
if (!actual) {
|
|
const message = 'ASSERT: ' + reason;
|
|
console.error(message);
|
|
debugger; // tslint:disable-line
|
|
throw new Error(message);
|
|
}
|
|
};
|
|
|
|
export const now = (ev: UIEvent) => {
|
|
return ev.timeStamp || Date.now();
|
|
};
|
|
|
|
export const pointerCoord = (ev: any): { x: number, y: number } => {
|
|
// get X coordinates for either a mouse click
|
|
// or a touch depending on the given event
|
|
if (ev) {
|
|
const changedTouches = ev.changedTouches;
|
|
if (changedTouches && changedTouches.length > 0) {
|
|
const touch = changedTouches[0];
|
|
return { x: touch.clientX, y: touch.clientY };
|
|
}
|
|
if (ev.pageX !== undefined) {
|
|
return { x: ev.pageX, y: ev.pageY };
|
|
}
|
|
}
|
|
return { x: 0, y: 0 };
|
|
};
|
|
|
|
/**
|
|
* @hidden
|
|
* Given a side, return if it should be on the end
|
|
* based on the value of dir
|
|
* @param side the side
|
|
* @param isRTL whether the application dir is rtl
|
|
*/
|
|
export const isEndSide = (side: Side): boolean => {
|
|
const isRTL = document.dir === 'rtl';
|
|
switch (side) {
|
|
case 'start': return isRTL;
|
|
case 'end': return !isRTL;
|
|
default:
|
|
throw new Error(`"${side}" is not a valid value for [side]. Use "start" or "end" instead.`);
|
|
}
|
|
};
|
|
|
|
export const deferEvent = (event: EventEmitter): EventEmitter => {
|
|
return debounceEvent(event, 0);
|
|
};
|
|
|
|
export const debounceEvent = (event: EventEmitter, wait: number): EventEmitter => {
|
|
const original = (event as any)._original || event;
|
|
return {
|
|
_original: event,
|
|
emit: debounce(original.emit.bind(original), wait)
|
|
} as EventEmitter;
|
|
};
|
|
|
|
export const debounce = (func: (...args: any[]) => void, wait = 0) => {
|
|
let timer: any;
|
|
return (...args: any[]): any => {
|
|
clearTimeout(timer);
|
|
timer = setTimeout(func, wait, ...args);
|
|
};
|
|
};
|