fix(input): scroll-assist

This commit is contained in:
Manu Mtz.-Almeida
2018-02-27 17:57:28 +01:00
parent 3a31d6482d
commit a69ec36f84
17 changed files with 374 additions and 203 deletions

View File

@@ -49,14 +49,6 @@ export class Content {
this.scrollEl = null;
}
hostData() {
return {
class: {
'statusbar-padding': this.config.getBoolean('statusbarPadding')
}
};
}
/**
* Scroll to the top of the content component.
*
@@ -79,7 +71,17 @@ export class Content {
return this.scrollEl.scrollToBottom(duration);
}
resize() {
@Method()
scrollByPoint(x: number, y: number, duration: number, done?: Function): Promise<any> {
return this.scrollEl.scrollByPoint(x, y, duration, done);
}
@Method()
scrollToPoint(x: number, y: number, duration: number, done?: Function): Promise<any> {
return this.scrollEl.scrollToPoint(x, y, duration, done);
}
private resize() {
if (!this.scrollEl) {
return;
}
@@ -114,6 +116,14 @@ export class Content {
}
}
hostData() {
return {
class: {
'statusbar-padding': this.config.getBoolean('statusbarPadding')
}
};
}
render() {
this.resize();

View File

@@ -56,6 +56,9 @@ to transparent.
## Methods
#### scrollByPoint()
#### scrollToBottom()
Scroll to the bottom of the content component.
@@ -64,6 +67,9 @@ Duration of the scroll animation in milliseconds. Defaults to `300`.
Returns a promise which is resolved when the scroll has completed.
#### scrollToPoint()
#### scrollToTop()
Scroll to the top of the content component.

View File

@@ -0,0 +1,96 @@
const RELOCATED_KEY= '$ionRelocated';
export function relocateInput(
componentEl: HTMLElement,
inputEl: HTMLInputElement,
shouldRelocate: boolean,
inputRelativeY: number = 0
) {
if ((componentEl as any)[RELOCATED_KEY] === shouldRelocate) {
return;
}
console.debug(`native-input, hideCaret, shouldHideCaret: ${shouldRelocate}, input value: ${inputEl.value}`);
if (shouldRelocate) {
// this allows for the actual input to receive the focus from
// the user's touch event, but before it receives focus, it
// moves the actual input to a location that will not screw
// up the app's layout, and does not allow the native browser
// to attempt to scroll the input into place (messing up headers/footers)
// the cloned input fills the area of where native input should be
// while the native input fakes out the browser by relocating itself
// before it receives the actual focus event
// We hide the focused input (with the visible caret) invisiable by making it scale(0),
cloneInputComponent(componentEl, inputEl);
const tx = document.dir === 'rtl' ? 9999 : -9999;
inputEl.style.transform= `translate3d(${tx}px,${inputRelativeY}px,0)`;
// TODO
// inputEle.style.opacity = '0';
} else {
removeClone(componentEl, inputEl);
}
(componentEl as any)[RELOCATED_KEY] = shouldRelocate;
}
export function isFocused(input: HTMLInputElement): boolean {
return input === document.activeElement;
}
function removeClone(componentEl: HTMLElement, inputEl: HTMLElement) {
if (componentEl && componentEl.parentElement) {
const clonedInputEles = componentEl.parentElement.querySelectorAll('.cloned-input');
for (let i = 0; i < clonedInputEles.length; i++) {
clonedInputEles[i].parentNode.removeChild(clonedInputEles[i]);
}
componentEl.style.pointerEvents = '';
}
(<any>inputEl.style)['transform'] = '';
inputEl.style.opacity = '';
}
function cloneInputComponent(componentEl: HTMLElement, inputEl: HTMLInputElement) {
// Make sure we kill all the clones before creating new ones
// It is a defensive, removeClone() should do nothing
// removeClone(plt, srcComponentEle, srcNativeInputEle);
// given a native <input> or <textarea> element
// find its parent wrapping component like <ion-input> or <ion-textarea>
// then clone the entire component
const parentElement = componentEl.parentElement;
if (componentEl && parentElement) {
// DOM READ
const srcTop = componentEl.offsetTop;
const srcLeft = componentEl.offsetLeft;
const srcWidth = componentEl.offsetWidth;
const srcHeight = componentEl.offsetHeight;
// DOM WRITE
// not using deep clone so we don't pull in unnecessary nodes
const clonedComponentEle = document.createElement('div');
const clonedStyle = clonedComponentEle.style;
clonedComponentEle.classList.add(...Array.from(componentEl.classList));
clonedComponentEle.classList.add('cloned-input');
clonedComponentEle.setAttribute('aria-hidden', 'true');
clonedStyle.pointerEvents = 'none';
clonedStyle.position = 'absolute';
clonedStyle.top = srcTop + 'px';
clonedStyle.left = srcLeft + 'px';
clonedStyle.width = srcWidth + 'px';
clonedStyle.height = srcHeight + 'px';
const clonedInputEl = document.createElement('input');
clonedInputEl.classList.add(...Array.from(inputEl.classList));
// Object.assign(clonedInputEl, input);
//const clonedInputEl = <HTMLInputElement>inputEl.cloneNode(false);
clonedInputEl.value = inputEl.value;
clonedInputEl.type = inputEl.type;
clonedInputEl.placeholder = inputEl.placeholder;
clonedInputEl.tabIndex = -1;
clonedComponentEle.appendChild(clonedInputEl);
parentElement.appendChild(clonedComponentEle);
componentEl.style.pointerEvents = 'none';
}
inputEl.style.transform = 'scale(0)';
}

View File

@@ -1,7 +1,7 @@
import { isFocused, relocateInput } from "./common";
const RELOCATED_KEY= '$ionRelocated';
export default function enableHideCaretOnScroll(componentEl: HTMLElement, inputEl: HTMLInputElement, scrollEl: HTMLIonScrollElement, keyboardHeight: number) {
export default function enableHideCaretOnScroll(componentEl: HTMLElement, inputEl: HTMLInputElement, scrollEl: HTMLIonScrollElement) {
if(!scrollEl || !inputEl) {
return () => {};
}
@@ -10,11 +10,11 @@ export default function enableHideCaretOnScroll(componentEl: HTMLElement, inputE
const scrollHideCaret = (shouldHideCaret: boolean) => {
// console.log('scrollHideCaret', shouldHideCaret)
if (isFocused(inputEl)) {
relocateInput(componentEl, inputEl, keyboardHeight, shouldHideCaret);
relocateInput(componentEl, inputEl, shouldHideCaret);
}
};
const onBlur = () => relocateInput(componentEl, inputEl, keyboardHeight, false);
const onBlur = () => relocateInput(componentEl, inputEl, false);
const hideCaret = () => scrollHideCaret(true);
const showCaret = () => scrollHideCaret(false);
@@ -28,102 +28,3 @@ export default function enableHideCaretOnScroll(componentEl: HTMLElement, inputE
inputEl.addEventListener('ionBlur', onBlur);
};
}
function removeClone(componentEl: HTMLElement, inputEl: HTMLElement) {
if (componentEl && componentEl.parentElement) {
const clonedInputEles = componentEl.parentElement.querySelectorAll('.cloned-input');
for (let i = 0; i < clonedInputEles.length; i++) {
clonedInputEles[i].parentNode.removeChild(clonedInputEles[i]);
}
componentEl.style.pointerEvents = '';
}
(<any>inputEl.style)['transform'] = '';
inputEl.style.opacity = '';
}
function cloneInputComponent(componentEl: HTMLElement, inputEl: HTMLInputElement) {
// Make sure we kill all the clones before creating new ones
// It is a defensive, removeClone() should do nothing
// removeClone(plt, srcComponentEle, srcNativeInputEle);
// given a native <input> or <textarea> element
// find its parent wrapping component like <ion-input> or <ion-textarea>
// then clone the entire component
const parentElement = componentEl.parentElement;
if (componentEl && parentElement) {
// DOM READ
const srcTop = componentEl.offsetTop;
const srcLeft = componentEl.offsetLeft;
const srcWidth = componentEl.offsetWidth;
const srcHeight = componentEl.offsetHeight;
// DOM WRITE
// not using deep clone so we don't pull in unnecessary nodes
const clonedComponentEle = document.createElement('div');
const clonedStyle = clonedComponentEle.style;
clonedComponentEle.classList.add(...Array.from(componentEl.classList));
clonedComponentEle.classList.add('cloned-input');
clonedComponentEle.setAttribute('aria-hidden', 'true');
clonedStyle.pointerEvents = 'none';
clonedStyle.position = 'absolute';
clonedStyle.top = srcTop + 'px';
clonedStyle.left = srcLeft + 'px';
clonedStyle.width = srcWidth + 'px';
clonedStyle.height = srcHeight + 'px';
const clonedInputEl = document.createElement('input');
clonedInputEl.classList.add(...Array.from(inputEl.classList));
// Object.assign(clonedInputEl, input);
//const clonedInputEl = <HTMLInputElement>inputEl.cloneNode(false);
clonedInputEl.value = inputEl.value;
clonedInputEl.type = inputEl.type;
clonedInputEl.tabIndex = -1;
clonedComponentEle.appendChild(clonedInputEl);
parentElement.appendChild(clonedComponentEle);
componentEl.style.pointerEvents = 'none';
}
inputEl.style.transform = 'scale(0)';
}
function relocateInput(
componentEl: HTMLElement,
inputEle: HTMLInputElement,
_keyboardHeight: number,
shouldRelocate: boolean
) {
console.log('relocateInput',shouldRelocate );
if ((componentEl as any)[RELOCATED_KEY] === shouldRelocate) {
return;
}
console.debug(`native-input, hideCaret, shouldHideCaret: ${shouldRelocate}, input value: ${inputEle.value}`);
if (shouldRelocate) {
// this allows for the actual input to receive the focus from
// the user's touch event, but before it receives focus, it
// moves the actual input to a location that will not screw
// up the app's layout, and does not allow the native browser
// to attempt to scroll the input into place (messing up headers/footers)
// the cloned input fills the area of where native input should be
// while the native input fakes out the browser by relocating itself
// before it receives the actual focus event
// We hide the focused input (with the visible caret) invisiable by making it scale(0),
cloneInputComponent(componentEl, inputEle);
// TODO
// const inputRelativeY = getScrollData(componentEl, inputEle, keyboardHeight).scrollAmount;
// const inputRelativeY = 9999;
// fix for #11817
const tx = document.dir === 'rtl' ? 9999 : -9999;
inputEle.style.transform= `translate3d(${tx}px,${0}px,0)`;
// inputEle.style.opacity = '0';
} else {
removeClone(componentEl, inputEle);
}
(componentEl as any)[RELOCATED_KEY] = shouldRelocate;
}
function isFocused(input: HTMLInputElement): boolean {
return input === document.activeElement;
}

View File

@@ -11,9 +11,6 @@ export default function enableInputBlurring(app: App) {
focused = true;
}
document.addEventListener('focusin', onFocusin, true);
document.addEventListener('touchend', onTouchend, false);
function onTouchend(ev: any) {
// if app did scroll return early
if (app.didScroll) {
@@ -51,6 +48,10 @@ export default function enableInputBlurring(app: App) {
}
}, 50);
}
document.addEventListener('focusin', onFocusin, true);
document.addEventListener('touchend', onTouchend, false);
return () => {
document.removeEventListener('focusin', onFocusin, true);
document.removeEventListener('touchend', onTouchend, false);

View File

@@ -0,0 +1,90 @@
import { pointerCoord } from "../../../utils/helpers";
import { relocateInput, isFocused } from "./common";
import { getScrollData } from "./scroll-data";
export default function enableScrollAssist(
componentEl: HTMLElement,
inputEl: HTMLInputElement,
contentEl: HTMLIonContentElement,
keyboardHeight: number
) {
let coord: any;
const touchStart = (ev: UIEvent) => {
coord = pointerCoord(ev);
console.debug(`input-base, pointerStart, type: ${ev.type}`);
};
const touchEnd = (ev: UIEvent) => {
// input cover touchend/mouseup
console.debug(`input-base, pointerEnd, type: ${ev.type}`);
if (!coord) {
return;
}
// get where the touchend/mouseup ended
const endCoord = pointerCoord(ev);
// focus this input if the pointer hasn't moved XX pixels
// and the input doesn't already have focus
if (!hasPointerMoved(6, coord, endCoord) && !isFocused(inputEl)) {
ev.preventDefault();
ev.stopPropagation();
// begin the input focus process
jsSetFocus(componentEl, inputEl, contentEl, keyboardHeight);
}
};
componentEl.addEventListener('touchstart', touchStart, true);
componentEl.addEventListener('touchend', touchEnd, true);
return () => {
componentEl.removeEventListener('touchstart', touchStart, true);
componentEl.removeEventListener('touchend', touchEnd, true);
};
}
function jsSetFocus(
componentEl: HTMLElement,
inputEl: HTMLInputElement,
contentEl: HTMLIonContentElement,
keyboardHeight: number
) {
const scrollData = getScrollData(componentEl, contentEl, keyboardHeight);
if (Math.abs(scrollData.scrollAmount) < 4) {
// the text input is in a safe position that doesn't
// require it to be scrolled into view, just set focus now
inputEl.focus();
return;
}
// temporarily move the focus to the focus holder so the browser
// doesn't freak out while it's trying to get the input in place
// at this point the native text input still does not have focus
relocateInput(componentEl, inputEl, true, scrollData.inputSafeY);
inputEl.focus();
// scroll the input into place
contentEl.scrollByPoint(0, scrollData.scrollAmount, scrollData.scrollDuration, () => {
// the scroll view is in the correct position now
// give the native text input focus
relocateInput(componentEl, inputEl, false, scrollData.inputSafeY);
// ensure this is the focused input
inputEl.focus();
});
}
function hasPointerMoved(threshold: number, startCoord: PointerCoordinates, endCoord: PointerCoordinates) {
if (startCoord && endCoord) {
const deltaX = (startCoord.x - endCoord.x);
const deltaY = (startCoord.y - endCoord.y);
const distance = deltaX * deltaX + deltaY * deltaY;
return distance > (threshold * threshold);
}
return false;
}
export interface PointerCoordinates {
x?: number;
y?: number;
}

View File

@@ -5,41 +5,7 @@ export interface ScrollData {
scrollAmount: number;
scrollPadding: number;
scrollDuration: number;
}
export function calcScrollData(
inputRect: ClientRect,
contentRect: ClientRect,
keyboardHeight: number,
plaformHeight: number
): ScrollData {
// compute input's Y values relative to the body
const inputTop = inputRect.top;
const inputBottom = inputRect.bottom;
// compute safe area
const safeAreaTop = contentRect.top;
const safeAreaBottom = Math.min(contentRect.bottom, plaformHeight - keyboardHeight);
// figure out if each edge of teh input is within the safe area
const distanceToBottom = safeAreaBottom - inputBottom;
const distanceToTop = safeAreaTop - inputTop;
const scrollAmount = Math.round((distanceToBottom < 0 )
? distanceToBottom
: (distanceToTop < 0 )
? distanceToTop
: 0);
const distance = Math.abs(scrollAmount);
const duration = distance / SCROLL_ASSIST_SPEED;
const scrollDuration = Math.min(400, Math.max(150, duration));
return {
scrollAmount,
scrollDuration,
scrollPadding: keyboardHeight,
};
inputSafeY: number;
}
export function getScrollData(componentEl: HTMLElement, contentEl: HTMLElement, keyboardHeight: number): ScrollData {
@@ -48,6 +14,7 @@ export function getScrollData(componentEl: HTMLElement, contentEl: HTMLElement,
scrollAmount: 0,
scrollPadding: 0,
scrollDuration: 0,
inputSafeY: 0,
};
}
// const scrollData = (componentEl as any)[SCROLL_DATA_KEY];
@@ -63,4 +30,46 @@ export function getScrollData(componentEl: HTMLElement, contentEl: HTMLElement,
);
// (componentEl as any)[SCROLL_DATA_KEY] = newScrollData;
return newScrollData;
}
}
function calcScrollData(
inputRect: ClientRect,
contentRect: ClientRect,
keyboardHeight: number,
plaformHeight: number
): ScrollData {
// compute input's Y values relative to the body
const inputTop = inputRect.top;
const inputBottom = inputRect.bottom;
// compute visible area
const visibleAreaTop = contentRect.top;
const visibleAreaBottom = Math.min(contentRect.bottom, plaformHeight - keyboardHeight);
// compute safe area
const safeAreaTop = visibleAreaTop + 10;
const safeAreaBottom = visibleAreaBottom / 2.0;
// figure out if each edge of teh input is within the safe area
const distanceToBottom = safeAreaBottom - inputBottom;
const distanceToTop = safeAreaTop - inputTop;
// The scrollAmount is the negated distance to the safe area.
const scrollAmount = Math.round((distanceToBottom < 0)
? -distanceToBottom
: (distanceToTop > 0)
? -distanceToTop
: 0);
const distance = Math.abs(scrollAmount);
const duration = distance / SCROLL_ASSIST_SPEED;
const scrollDuration = Math.min(400, Math.max(150, duration));
return {
scrollAmount,
scrollDuration,
scrollPadding: keyboardHeight,
inputSafeY: -(inputTop - safeAreaTop) + 4
};
}

View File

@@ -0,0 +1,45 @@
const PADDING_TIMER_KEY = '$ionPaddingTimer';
export default function enableScrollPadding(keyboardHeight: number) {
console.debug('Input: enableInputBlurring');
function onFocusin(ev: any) {
setScrollPadding(ev.target, keyboardHeight);
}
function onFocusout(ev: any) {
setScrollPadding(ev.target, 0);
}
document.addEventListener('focusin', onFocusin);
document.addEventListener('focusout', onFocusout);
return () => {
document.removeEventListener('focusin', onFocusin);
document.removeEventListener('focusout', onFocusout);
};
}
function setScrollPadding(input: HTMLElement, keyboardHeight: number) {
if (input.tagName !== 'INPUT') {
return;
}
if (input.parentElement.tagName === 'ION-INPUT') {
return;
}
const el = input.closest('.scroll-inner') as HTMLElement;
if (!el) {
return;
}
const timer = (el as any)[PADDING_TIMER_KEY];
if (timer) {
clearTimeout(timer);
}
if (keyboardHeight > 0) {
el.style.paddingBottom = keyboardHeight + 'px';
} else {
(el as any)[PADDING_TIMER_KEY] = setTimeout(() => {
el.style.paddingBottom = '';
}, 120)
}
}

View File

@@ -1,19 +1,4 @@
// export function enableScrollPadding(componentEl: HTMLElement, inputEl: HTMLElement, contentEl: HTMLElement, keyboardHeight: number) {
// console.debug('Input: enableScrollPadding');
// debugger;
// const onFocus = () => {
// const scrollPadding = getScrollData(componentEl, contentEl, keyboardHeight).scrollPadding;
// contentEl.addScrollPadding(scrollPadding);
// content.clearScrollPaddingFocusOut();
// };
// inputEl.addEventListener('focus', onFocus);
// return () => {
// inputEl.removeEventListener('focus', onFocus);
// };
// }
// export function enableScrollMove(
// componentEl: HTMLElement,
// inputEl: HTMLElement,

View File

@@ -3,6 +3,13 @@ import { App, Config } from "../..";
import enableHideCaretOnScroll from "./hacks/hide-caret";
import enableInputBlurring from "./hacks/input-blurring";
import enableScrollAssist from "./hacks/scroll-assist";
import enableScrollPadding from "./hacks/scroll-padding";
const INPUT_BLURRING = true;
const SCROLL_ASSIST = true;
const SCROLL_PADDING = true;
const HIDE_CARET = true;
@Component({
tag: 'ion-input-shims',
@@ -11,21 +18,29 @@ export class InputShims {
private didLoad = false;
private hideCaret = false;
private scrollAssist = false;
private keyboardHeight = 0;
private hideCaretMap = new WeakMap<HTMLElement, Function>();
private scrollAssistMap = new WeakMap<HTMLElement, Function>();
@Prop({context: 'config'}) config: Config;
@Prop() app: App;
componentDidLoad() {
this.keyboardHeight = this.config.getNumber('keyboardHeight', 200);
this.keyboardHeight = this.config.getNumber('keyboardHeight', 290);
this.scrollAssist = this.config.getBoolean('scrollAssist', true);
this.hideCaret = this.config.getBoolean('hideCaretOnScroll', true);
const inputBlurring = this.config.getBoolean('inputBlurring', true);
if (inputBlurring) {
if (inputBlurring && INPUT_BLURRING) {
enableInputBlurring(this.app);
}
const scrollPadding = this.config.getBoolean('scrollPadding', true);
if (scrollPadding && SCROLL_PADDING) {
enableScrollPadding(this.keyboardHeight);
}
// Input might be already loaded in the DOM before ion-device-hacks did.
// At this point we need to look for all the ion-inputs not registered yet
// and register them.
@@ -53,21 +68,32 @@ export class InputShims {
}
private registerInput(componentEl: HTMLElement) {
if (this.hideCaret && !this.hideCaretMap.has(componentEl)) {
const rmFn = enableHideCaretOnScroll(
componentEl,
componentEl.querySelector('input'),
componentEl.closest('ion-scroll'),
this.keyboardHeight
);
const inputEl = componentEl.querySelector('input');
const scrollEl = componentEl.closest('ion-scroll');
const contentEl = componentEl.closest('ion-content');
if (HIDE_CARET && this.hideCaret && !this.hideCaretMap.has(componentEl)) {
const rmFn = enableHideCaretOnScroll(componentEl, inputEl, scrollEl);
this.hideCaretMap.set(componentEl, rmFn);
}
if (SCROLL_ASSIST && this.scrollAssist && !this.scrollAssistMap.has(componentEl)) {
const rmFn = enableScrollAssist(componentEl, inputEl, contentEl, this.keyboardHeight);
this.scrollAssistMap.set(componentEl, rmFn);
}
}
private unregisterInput(componentEl: HTMLElement) {
if (this.hideCaret) {
if (HIDE_CARET && this.hideCaret) {
const fn = this.hideCaretMap.get(componentEl);
fn && fn();
this.hideCaretMap.delete(componentEl);
}
if (SCROLL_ASSIST && this.scrollAssist) {
const fn = this.scrollAssistMap.get(componentEl);
fn && fn();
this.scrollAssistMap.delete(componentEl);
}
}
}

View File

@@ -87,6 +87,11 @@
</ion-button>
</div>
<ion-item>
<ion-label>Clear Input</ion-label>
<ion-input clear-input value="reallylonglonglonginputtoseetheedgesreallylonglonglonginputtoseetheedges"></ion-input>
</ion-item>
</ion-content>
</ion-page>

View File

@@ -4,7 +4,6 @@ import { Animation } from '../../../index';
* iOS Popover Enter Animation
*/
export default function iosEnterAnimation(Animation: Animation, baseEl: HTMLElement, ev?: Event): Promise<Animation> {
debugger;
let originY = 'top';
let originX = 'left';

View File

@@ -86,6 +86,9 @@ Emitted when the scroll has started.
## Methods
#### scrollByPoint()
#### scrollToBottom()

View File

@@ -117,6 +117,11 @@ export class Scroll {
return this.scrollToPoint(0, y, duration);
}
@Method()
scrollByPoint(x: number, y: number, duration: number, done?: Function): Promise<any> {
return this.scrollToPoint(x + this.el.scrollLeft, y + this.el.scrollTop, duration, done);
}
@Method()
scrollToPoint(x: number, y: number, duration: number, done?: Function): Promise<any> {
// scroll animation loop w/ easing

View File

@@ -1,5 +1,5 @@
import { Component, Element, EventListenerEnable, Listen, Prop } from '@stencil/core';
import { now, pointerCoordX, pointerCoordY } from '../../utils/helpers';
import { now, pointerCoord } from '../../utils/helpers';
@Component({
@@ -110,8 +110,7 @@ export class TapClick {
clearTimeout(this.activeDefer);
this.activeDefer = null;
const eventX = pointerCoordX(ev);
const eventY = pointerCoordY(ev);
const {x, y} = pointerCoord(ev);
// unactivate selected
if (activatableEle) {
@@ -119,7 +118,7 @@ export class TapClick {
throw new Error('internal error');
}
if (!activatableEle.classList.contains(ACTIVATED)) {
this.addActivated(activatableEle, eventX, eventY);
this.addActivated(activatableEle, x, y);
}
this.removeActivated(true);
}
@@ -134,7 +133,7 @@ export class TapClick {
el.classList.remove(ACTIVATED);
this.activeDefer = setTimeout(() => {
this.addActivated(el, eventX, eventY);
this.addActivated(el, x, y);
this.activeDefer = null;
}, ADD_ACTIVATED_DEFERS);
}

View File

@@ -22,6 +22,9 @@ export const PLATFORM_CONFIGS: PlatformConfig[] = [
{
name: IPAD,
settings: {
keyboardHeight: 500,
},
isMatch: (url, userAgent) => isPlatformMatch(url, userAgent, IPAD, [IPAD], WINDOWS_PHONE)
},
@@ -33,9 +36,10 @@ export const PLATFORM_CONFIGS: PlatformConfig[] = [
{
name: IOS,
settings: {
mode: "ios",
mode: 'ios',
tabsHighlight: false,
statusbarPadding: isCordova(),
keyboardHeight: 250,
isDevice: true,
deviceHacks: true,
},
@@ -45,8 +49,9 @@ export const PLATFORM_CONFIGS: PlatformConfig[] = [
{
name: ANDROID,
settings: {
isDevice: true,
mode: 'md',
isDevice: true,
keyboardHeight: 300,
},
isMatch: (url, userAgent) => isPlatformMatch(url, userAgent, ANDROID, [ANDROID, 'silk'], WINDOWS_PHONE)
},

View File

@@ -69,19 +69,20 @@ export function now(ev: UIEvent) {
return ev.timeStamp || Date.now();
}
export function pointerCoordX(ev: any): number {
export function 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) {
return changedTouches[0].clientX;
const touch = changedTouches[0];
return {x: touch.clientX, y: touch.clientY};
}
if (ev.pageX !== undefined) {
return ev.pageX;
return {x: ev.pageX, y: ev.pageY};
}
}
return 0;
return {x: 0, y: 0};
}
export function updateDetail(ev: any, detail: any) {
@@ -104,21 +105,6 @@ export function updateDetail(ev: any, detail: any) {
detail.currentY = y;
}
export function pointerCoordY(ev: any): number {
// get Y 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) {
return changedTouches[0].clientY;
}
if (ev.pageY !== undefined) {
return ev.pageY;
}
}
return 0;
}
export type ElementRef = 'child' | 'parent' | 'body' | 'document' | 'window';
export function getElementReference(el: any, ref: ElementRef) {