From f24008353543b3523851bf142c0bb93f2a85153d Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Thu, 16 Jul 2015 14:04:15 -0500 Subject: [PATCH] wip --- ionic/animations/scroll-to.ts | 106 ++++++++++ ionic/components.ts | 4 +- ionic/components/app/app.ts | 15 ++ ionic/components/app/structure.scss | 3 +- ionic/components/app/util.scss | 2 +- ionic/components/content/content.ts | 36 +++- ionic/components/form/focus-holder.ts | 108 ++++++++++ ionic/components/form/form.ts | 88 ++++++++- ionic/components/form/{input => }/input.scss | 23 +++ ionic/components/form/input.ts | 198 +++++++++++++++++++ ionic/components/form/input/input.ts | 12 -- ionic/components/form/{label => }/label.scss | 0 ionic/components/form/label.ts | 7 + ionic/components/form/label/label.ts | 10 - ionic/components/form/test/input/e2e.ts | 1 + ionic/components/form/test/input/index.ts | 7 + ionic/components/form/test/input/main.html | 92 +++++++++ ionic/config/annotations.ts | 12 +- ionic/ionic.scss | 4 +- ionic/platform/registry.ts | 3 +- ionic/util/click-block.ts | 6 + ionic/util/dom.ts | 24 +++ ionic/util/tap.ts | 4 +- 23 files changed, 729 insertions(+), 36 deletions(-) create mode 100644 ionic/animations/scroll-to.ts create mode 100644 ionic/components/form/focus-holder.ts rename ionic/components/form/{input => }/input.scss (57%) create mode 100644 ionic/components/form/input.ts delete mode 100644 ionic/components/form/input/input.ts rename ionic/components/form/{label => }/label.scss (100%) create mode 100644 ionic/components/form/label.ts delete mode 100644 ionic/components/form/label/label.ts create mode 100644 ionic/components/form/test/input/e2e.ts create mode 100644 ionic/components/form/test/input/index.ts create mode 100644 ionic/components/form/test/input/main.html diff --git a/ionic/animations/scroll-to.ts b/ionic/animations/scroll-to.ts new file mode 100644 index 0000000000..1652344d73 --- /dev/null +++ b/ionic/animations/scroll-to.ts @@ -0,0 +1,106 @@ +import {raf} from '../util/dom'; + + +export class ScrollTo { + + constructor(ele, x, y, duration) { + if (typeof ele === 'string') { + // string query selector + ele = document.querySelector(ele); + } + + if (ele) { + if (ele.nativeElement) { + // angular ElementRef + ele = ele.nativeElement; + } + + if (ele.nodeType === 1) { + this._el = ele; + } + } + } + + start(x, y, duration, tolerance) { + // scroll animation loop w/ easing + // credit https://gist.github.com/dezinezync/5487119 + let self = this; + + if (!self._el) { + // invalid element + return Promise.resolve(); + } + + x = x || 0; + y = y || 0; + tolerance = tolerance || 0; + + let ele = self._el; + let fromY = ele.scrollTop; + let fromX = ele.scrollLeft; + + let xDistance = Math.abs(x - fromX); + let yDistance = Math.abs(y - fromY); + + if (yDistance <= tolerance && xDistance <= tolerance) { + // prevent scrolling if already close to there + this._el = ele = null; + return Promise.resolve(); + } + + return new Promise((resolve, reject) => { + + let start = Date.now(); + + // start scroll loop + self.isPlaying = true; + raf(step); + + // decelerating to zero velocity + function easeOutCubic(t) { + return (--t) * t * t + 1; + } + + // scroll loop + function step() { + let time = Math.min(1, ((Date.now() - start) / duration)); + + // where .5 would be 50% of time on a linear scale easedT gives a + // fraction based on the easing method + let easedT = easeOutCubic(time); + + if (fromY != y) { + ele.scrollTop = parseInt((easedT * (y - fromY)) + fromY, 10); + } + if (fromX != x) { + ele.scrollLeft = parseInt((easedT * (x - fromX)) + fromX, 10); + } + + if (time < 1 && self.isPlaying) { + raf(step); + + } else if (!self.isPlaying) { + // stopped + this._el = ele = null; + reject(); + + } else { + // done + this._el = ele = null; + resolve(); + } + } + + }); + } + + stop() { + this.isPlaying = false; + } + + dispose() { + this.stop(); + this._el = null; + } + +} diff --git a/ionic/components.ts b/ionic/components.ts index 479e651058..216549c947 100644 --- a/ionic/components.ts +++ b/ionic/components.ts @@ -8,8 +8,8 @@ export * from 'ionic/components/icon/icon' export * from 'ionic/components/item/item' export * from 'ionic/components/item/item-group' export * from 'ionic/components/form/form' -export * from 'ionic/components/form/input/input' -export * from 'ionic/components/form/label/label' +export * from 'ionic/components/form/input' +export * from 'ionic/components/form/label' export * from 'ionic/components/list/list' export * from 'ionic/components/modal/modal' export * from 'ionic/components/nav/nav' diff --git a/ionic/components/app/app.ts b/ionic/components/app/app.ts index 158516c6fe..808b562b8b 100644 --- a/ionic/components/app/app.ts +++ b/ionic/components/app/app.ts @@ -11,6 +11,7 @@ import * as util from '../../util/util'; // injectables import {ActionMenu} from '../action-menu/action-menu'; import {Modal} from '../modal/modal'; +import {FocusHolder} from '../form/focus-holder'; export class IonicApp { @@ -29,6 +30,13 @@ export class IonicApp { this._zone = this.injector().get(NgZone); } + focusHolder(val) { + if (arguments.length) { + this._focusHolder = val; + } + return this._focusHolder; + } + title(val) { document.title = val; } @@ -206,6 +214,13 @@ export function ionicBootstrap(component, config, router) { bootstrap(component, injectableBindings).then(appRef => { app.load(appRef); + // append the focus holder if its needed + if (config.setting('keyboardScrollAssist')) { + app.appendComponent(FocusHolder).then(ref => { + app.focusHolder(ref.instance); + }); + } + router.load(window, app, config).then(() => { // resolve that the app has loaded resolve(app); diff --git a/ionic/components/app/structure.scss b/ionic/components/app/structure.scss index 46354d4089..50e2fe30ea 100644 --- a/ionic/components/app/structure.scss +++ b/ionic/components/app/structure.scss @@ -1,10 +1,11 @@ html, body { + width: 100%; height: 100%; } body { - position: relative; + position: fixed; overflow: hidden; max-width: 100%; max-height: 100%; diff --git a/ionic/components/app/util.scss b/ionic/components/app/util.scss index fb39ef67ce..10ac93f4cd 100755 --- a/ionic/components/app/util.scss +++ b/ionic/components/app/util.scss @@ -90,7 +90,7 @@ $content-padding: 10px !default; left: 0; opacity: 0; z-index: $z-index-click-block; - transform: translate3d(-9999px, 0px, 0px); + transform: translate3d(-9999px, 0px, 0px);; //background: red; //opacity: .3; diff --git a/ionic/components/content/content.ts b/ionic/components/content/content.ts index df43d88743..4333b502ff 100644 --- a/ionic/components/content/content.ts +++ b/ionic/components/content/content.ts @@ -3,13 +3,17 @@ import {Component, View, ElementRef} from 'angular2/angular2'; import {Ion} from '../ion'; import {IonicConfig} from '../../config/config'; import {IonicComponent} from '../../config/annotations'; +import {ScrollTo} from '../../animations/scroll-to'; @Component({ selector: 'ion-content', properties: [ 'parallax' - ] + ], + host: { + ['[class.scroll-padding]']: 'scrollPadding' + } }) @View({ template: '
' @@ -17,6 +21,7 @@ import {IonicComponent} from '../../config/annotations'; export class Content extends Ion { constructor(elementRef: ElementRef, ionicConfig: IonicConfig) { super(elementRef, ionicConfig); + this.scrollPadding = false; } onIonInit() { @@ -32,4 +37,33 @@ export class Content extends Ion { this.scrollElement.removeEventListener('scroll', handler); } } + + addTouchMoveListener(handler) { + if(!this.scrollElement) { return; } + + this.scrollElement.addEventListener('touchmove', handler); + + return () => { + this.scrollElement.removeEventListener('touchmove', handler); + } + } + + scrollTo(x, y, duration, tolerance) { + if (this._scrollTo) { + this._scrollTo.dispose(); + } + + this._scrollTo = new ScrollTo(this.scrollElement); + + return this._scrollTo.start(x, y, duration, tolerance); + } + + get scrollPadding() { + return this._sp; + } + + set scrollPadding(val) { + this._sp = val; + } + } diff --git a/ionic/components/form/focus-holder.ts b/ionic/components/form/focus-holder.ts new file mode 100644 index 0000000000..415060fbc1 --- /dev/null +++ b/ionic/components/form/focus-holder.ts @@ -0,0 +1,108 @@ +import {Component, Directive, View, Parent, ElementRef, forwardRef} from 'angular2/angular2'; + +import {IonicConfig} from '../../config/config'; +import * as dom from '../../util/dom'; +import {Platform} from '../../platform/platform'; +import {IonInput} from './form'; + + +@Component({ + selector: 'focus-holder' +}) +@View({ + template: '', + directives: [forwardRef(() => FocusInput)] +}) +export class FocusHolder { + constructor() { + this.i = []; + } + + setFocusHolder(inputType) { + IonInput.clearTabIndexes(); + + this.i[1].tabIndex = ACTIVE_TAB_INDEX; + this.i[1].type = inputType; + this.i[1].focus(); + } + + setActiveInput(input) { + IonInput.clearTabIndexes(); + + this.i[1].tabIndex = -1; + + input.tabIndex = ACTIVE_TAB_INDEX; + } + + receivedFocus(tabIndex) { + if (tabIndex === PREVIOUS_TAB_INDEX) { + // they tabbed back one input + // reset the focus to the center focus holder + this.i[1].focus(); + + // focus on the previous input + IonInput.focusPrevious(); + + } else if (tabIndex === NEXT_TAB_INDEX) { + // they tabbed to the next input + // reset the focus to the center focus holder + this.i[1].focus(); + + // focus on the next input + IonInput.focusNext(); + } + } + + register(input) { + // register each of the focus holder inputs + // assign them their correct tab indexes + input.tabIndex = PREVIOUS_TAB_INDEX + this.i.length; + this.i.push(input); + } +} + + +@Directive({ + selector: 'input', + properties: [ + 'tabIndex' + ], + host: { + '[tabIndex]': 'tabIndex', + '[type]': 'type', + '(focus)': 'holder.receivedFocus(tabIndex)', + '(keydown)': 'keydown($event)' + } +}) +class FocusInput { + constructor(elementRef: ElementRef, @Parent() holder: FocusHolder) { + this.elementRef = elementRef; + holder.register(this); + this.holder = holder; + } + + focus() { + this.elementRef.nativeElement.focus(); + } + + keydown(ev) { + // prevent any keyboard typing when a holder has focus + if (ev.keyCode !== 9) { + ev.preventDefault(); + ev.stopPropagation(); + } + } + + get type() { + // default to text type if unknown + return this._t || 'text'; + } + + set type(val) { + this._t = val; + } +} + +const PREVIOUS_TAB_INDEX = 999; +const ACTIVE_TAB_INDEX = 1000; +const NEXT_TAB_INDEX = 1001; diff --git a/ionic/components/form/form.ts b/ionic/components/form/form.ts index 7d6cb4908d..af4e26c612 100644 --- a/ionic/components/form/form.ts +++ b/ionic/components/form/form.ts @@ -1 +1,87 @@ -// form +import {IonicConfig} from '../../config/config'; +import * as dom from '../../util/dom'; + +let inputRegistry = []; +let activeInput = null; +let lastInput = null; + + +export class IonInput { + constructor( + elementRef: ElementRef, + app: IonicApp, + scrollView: Content + ) { + this.elementRef = elementRef; + this.app = app; + this.scrollView = scrollView; + + inputRegistry.push(this); + } + + hasFocus() { + return dom.hasFocus(this.elementRef); + } + + focus() { + this.setFocus(); + } + + setFocus() { + // TODO: How do you do this w/ NG2? + this.elementRef.nativeElement.focus(); + } + + setFocusHolder(type) { + let focusHolder = this.app.focusHolder(); + focusHolder && focusHolder.setFocusHolder(type); + } + + isActiveInput(shouldBeActive) { + if (shouldBeActive) { + if (activeInput && activeInput !== lastInput) { + lastInput = activeInput; + } + + activeInput = this; + + let focusHolder = this.app.focusHolder(); + focusHolder && focusHolder.setActiveInput(activeInput); + + } else if (activeInput === this) { + lastInput = activeInput; + activeInput = null; + } + } + + sibling(inc) { + let index = inputRegistry.indexOf(this); + if (index > -1) { + return inputRegistry[index + inc]; + } + } + + static focusPrevious() { + this.focusMove(-1); + } + + static focusNext() { + this.focusMove(1); + } + + static focusMove(inc) { + let input = activeInput || lastInput; + if (input) { + let siblingInput = input.sibling(inc); + siblingInput && siblingInput.focus(); + } + } + + static clearTabIndexes() { + for (let i = 0; i < inputRegistry.length; i++) { + inputRegistry[i].tabIndex = -1; + } + } + +} + diff --git a/ionic/components/form/input/input.scss b/ionic/components/form/input.scss similarity index 57% rename from ionic/components/form/input/input.scss rename to ionic/components/form/input.scss index 86ca69285e..e93e4c50f4 100644 --- a/ionic/components/form/input/input.scss +++ b/ionic/components/form/input.scss @@ -2,6 +2,28 @@ $item-input-padding: 6px 0 5px 0px; ion-input { display: block; +} + +input.disable-focus, +textarea.disable-focus, +select.disable-focus { + //pointer-events: none; +} + +focus-holder input { + position: fixed; + top: 1px; + width: 9px; + left: -9999px; + z-index: 9999; +} + +.scroll-padding.scroll-padding .scroll-content { + padding-bottom: 1000px; +} + +/*ion-input { + display: block; position: relative; @@ -28,3 +50,4 @@ ion-input { background-color: transparent; } } +*/ diff --git a/ionic/components/form/input.ts b/ionic/components/form/input.ts new file mode 100644 index 0000000000..8ce028e227 --- /dev/null +++ b/ionic/components/form/input.ts @@ -0,0 +1,198 @@ +import {Directive, View, Parent, Ancestor, Optional, ElementRef, Attribute, forwardRef} from 'angular2/angular2'; + +import {IonicDirective} from '../../config/annotations'; +import {IonicConfig} from '../../config/config'; +import {IonInput} from './form'; +import {Ion} from '../ion'; +import {IonicApp} from '../app/app'; +import {Content} from '../content/content'; +import {ClickBlock} from '../../util/click-block'; +import * as dom from '../../util/dom'; +import {Platform} from '../../platform/platform'; + + +@IonicDirective({ + selector: 'ion-input' +}) +export class Input extends Ion { + + constructor( + elementRef: ElementRef, + ionicConfig: IonicConfig + ) { + super(elementRef, ionicConfig); + this.id = ++inputIds; + } + + onInit() { + if (this.input) { + this.input.id = 'input-' + this.id; + } + if (this.label) { + this.label.id = 'label-' + this.id; + this.input.labelledBy = this.label.id; + } + } + + registerInput(directive) { + this.input = directive; + } + + registerLabel(directive) { + this.label = directive; + } + +} + + +@Directive({ + selector: 'textarea,input[type=text],input[type=password],input[type=number],input[type=search],input[type=email],input[type=url]', + property: [ + 'tabIndex' + ], + host: { + '[tabIndex]': 'tabIndex', + '(focus)': 'receivedFocus(true)', + '(blur)': 'receivedFocus(false)', + '(touchstart)': 'pointerStart($event)', + '(touchend)': 'pointerEnd($event)', + '(mousedown)': 'pointerStart($event)', + '(mouseup)': 'pointerEnd($event)', + '[attr.id]': 'id', + '[attr.aria-labelledby]': 'labelledBy', + '[class.disable-focus]': 'disableFocus' + } +}) +export class TextInput extends IonInput { + constructor( + @Optional() @Parent() container: Input, + @Optional() @Ancestor() scrollView: Content, + @Attribute('type') type: string, + elementRef: ElementRef, + app: IonicApp, + config: IonicConfig + ) { + super(elementRef, app, scrollView); + + if (container) { + container.registerInput(this); + this.container = container; + } + + this.type = type; + this.elementRef = elementRef; + this.tabIndex = this.tabIndex || ''; + + this.scrollAssist = config.setting('keyboardScrollAssist'); + } + + pointerStart(ev) { + if (this.scrollAssist) { + this.startCoord = dom.pointerCoord(ev); + this.disableFocus = true; + } + } + + pointerEnd(ev) { + if (this.scrollAssist) { + let endCoord = dom.pointerCoord(ev); + + if (this.startCoord && !dom.hasPointerMoved(20, this.startCoord, endCoord) && !this.hasFocus()) { + ev.preventDefault(); + ev.stopPropagation(); + + this.focus(); + + } else { + this.disableFocus = false; + } + + this.startCoord = null; + } + } + + focus() { + let scrollView = this.scrollView; + + if (scrollView && this.scrollAssist) { + this.disableFocus = true; + + // this input is inside of a scroll view + // scroll the input to the top + let inputY = this.elementRef.nativeElement.offsetTop - 8; + + // do not allow any clicks while it's scrolling + ClickBlock(true, SCROLL_INTO_VIEW_DURATION + 200); + + // used to put a lot of padding on the bottom of the scroll view + scrollView.scrollPadding = true; + + // 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 + this.setFocusHolder(this.type); + + // scroll the input into place + scrollView.scrollTo(0, inputY, SCROLL_INTO_VIEW_DURATION, 8).then(() => { + // the scroll view is in the correct position now + // give the native input the focus + this.setFocus(); + + // all good, allow clicks again + ClickBlock(false); + + this.disableFocus = false; + }); + + } else { + // not inside of a scroll view, just focus it + this.setFocus(); + this.disableFocus = false; + } + + } + + receivedFocus(receivedFocus) { + let self = this; + let scrollView = self.scrollView; + + self.isActiveInput(receivedFocus); + + function touchMove(ev) { + self.setFocusHolder(self.type); + self.deregTouchMove(); + } + + if (scrollView && this.scrollAssist) { + if (receivedFocus) { + // when the input has focus, then the focus holder + // should not be able to be focused + self.deregTouchMove = scrollView && scrollView.addTouchMoveListener(touchMove); + + } else { + // the input no longer has focus + self.deregTouchMove && self.deregTouchMove(); + } + } + + } + +} + + +@Directive({ + selector: 'label', + host: { + '[attr.id]': 'id' + } +}) +export class InputLabel { + constructor(@Optional() @Parent() container: Input) { + if (container) { + container.registerLabel(this); + } + } +} + +const SCROLL_INTO_VIEW_DURATION = 500; + +let inputIds = -1; diff --git a/ionic/components/form/input/input.ts b/ionic/components/form/input/input.ts deleted file mode 100644 index fd9be0b598..0000000000 --- a/ionic/components/form/input/input.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {Component, Directive} from 'angular2/angular2'; - - -@Directive({ - selector: 'ion-input' -}) -export class Input { - constructor() { - //this.config = Button.config.invoke(this) - console.log('INPUT'); - } -} diff --git a/ionic/components/form/label/label.scss b/ionic/components/form/label.scss similarity index 100% rename from ionic/components/form/label/label.scss rename to ionic/components/form/label.scss diff --git a/ionic/components/form/label.ts b/ionic/components/form/label.ts new file mode 100644 index 0000000000..b9ddfb1493 --- /dev/null +++ b/ionic/components/form/label.ts @@ -0,0 +1,7 @@ +import {Directive} from 'angular2/angular2'; + + +@Directive({ + selector: 'ion-label' +}) +export class Label {} diff --git a/ionic/components/form/label/label.ts b/ionic/components/form/label/label.ts deleted file mode 100644 index 2485e60ae0..0000000000 --- a/ionic/components/form/label/label.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {Component, Directive} from 'angular2/angular2'; - - -@Directive({ - selector: 'ion-label' -}) -export class Label { - constructor() { - } -} diff --git a/ionic/components/form/test/input/e2e.ts b/ionic/components/form/test/input/e2e.ts new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/ionic/components/form/test/input/e2e.ts @@ -0,0 +1 @@ + diff --git a/ionic/components/form/test/input/index.ts b/ionic/components/form/test/input/index.ts new file mode 100644 index 0000000000..2dac2b7a35 --- /dev/null +++ b/ionic/components/form/test/input/index.ts @@ -0,0 +1,7 @@ +import {App} from 'ionic/ionic'; + + +@App({ + templateUrl: 'main.html' +}) +class IonicApp {} diff --git a/ionic/components/form/test/input/main.html b/ionic/components/form/test/input/main.html new file mode 100644 index 0000000000..2c17613ef6 --- /dev/null +++ b/ionic/components/form/test/input/main.html @@ -0,0 +1,92 @@ + +Header + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Footer + + + + diff --git a/ionic/config/annotations.ts b/ionic/config/annotations.ts index 0f59b5622c..a1ac5beb69 100644 --- a/ionic/config/annotations.ts +++ b/ionic/config/annotations.ts @@ -11,7 +11,8 @@ import { List, Item, ItemGroup, ItemGroupTitle, Toolbar, Icon, - Checkbox, Switch, Label, Input, + Checkbox, Switch, + Input, TextInput, InputLabel, Segment, SegmentButton, SegmentControlValueAccessor, RadioGroup, RadioButton, SearchBar, Nav, NavbarTemplate, Navbar, NavPush, NavPop, @@ -50,13 +51,18 @@ export const IonicDirectives = [ // Media forwardRef(() => Icon), - // Form elements + // Form forwardRef(() => Segment), forwardRef(() => SegmentButton), forwardRef(() => SegmentControlValueAccessor), - //Checkbox, Switch, Label, Input + //Checkbox, Switch //RadioGroup, RadioButton, SearchBar, + // Input + forwardRef(() => Input), + forwardRef(() => TextInput), + forwardRef(() => InputLabel), + // Nav forwardRef(() => Nav), forwardRef(() => NavbarTemplate), diff --git a/ionic/ionic.scss b/ionic/ionic.scss index f01064f81c..897c3c3deb 100755 --- a/ionic/ionic.scss +++ b/ionic/ionic.scss @@ -33,8 +33,8 @@ "components/content/content", "components/item/item", "components/form/form", - "components/form/label/label", - "components/form/input/input", + "components/form/label", + "components/form/input", "components/layout/layout", "components/list/list", "components/modal/modal", diff --git a/ionic/platform/registry.ts b/ionic/platform/registry.ts index 09375b6578..d0b0851861 100644 --- a/ionic/platform/registry.ts +++ b/ionic/platform/registry.ts @@ -71,7 +71,8 @@ Platform.register({ settings: { mode: 'ios', viewTransition: 'ios', - tapPolyfill: true + tapPolyfill: true, + keyboardScrollAssist: true }, isMatch(p) { return p.isPlatform('ios', 'iphone|ipad|ipod'); diff --git a/ionic/util/click-block.ts b/ionic/util/click-block.ts index b8cd01f9fb..8db77baca7 100644 --- a/ionic/util/click-block.ts +++ b/ionic/util/click-block.ts @@ -3,6 +3,10 @@ const DEFAULT_EXPIRE = 330; let cbEle, fallbackTimerId; let isShowing = false; +function disableInput(ev) { + ev.preventDefault(); + ev.stopPropagation(); +} function show(expire) { clearTimeout(fallbackTimerId); @@ -18,6 +22,7 @@ function show(expire) { cbEle.className = 'click-block ' + CSS_CLICK_BLOCK; document.body.appendChild(cbEle); } + cbEle.addEventListener('touchmove', disableInput); } } @@ -26,6 +31,7 @@ function hide() { if (isShowing) { cbEle.classList.remove(CSS_CLICK_BLOCK); isShowing = false; + cbEle.removeEventListener('touchmove', disableInput); } } diff --git a/ionic/util/dom.ts b/ionic/util/dom.ts index f6a6624476..853cec991e 100644 --- a/ionic/util/dom.ts +++ b/ionic/util/dom.ts @@ -158,3 +158,27 @@ export function windowLoad(callback) { return promise; } + +export function pointerCoord(ev) { + // get coordinates for either a mouse click + // or a touch depending on the given event + let c = { x: 0, y: 0 }; + if (ev) { + const touches = ev.touches && ev.touches.length ? ev.touches : [ev]; + const e = (ev.changedTouches && ev.changedTouches[0]) || touches[0]; + if (e) { + c.x = e.clientX || e.pageX || 0; + c.y = e.clientY || e.pageY || 0; + } + } + return c; +} + +export function hasPointerMoved(tolerance, startCoord, endCoord) { + return Math.abs(startCoord.x - endCoord.x) > tolerance || + Math.abs(startCoord.y - endCoord.y) > tolerance; +} + +export function hasFocus(ele) { + return !!(ele && (document.activeElement === ele.nativeElement || document.activeElement === ele)); +} diff --git a/ionic/util/tap.ts b/ionic/util/tap.ts index 6fb465aff6..a7fce7596a 100644 --- a/ionic/util/tap.ts +++ b/ionic/util/tap.ts @@ -103,8 +103,8 @@ var tapEventListeners = { Platform.ready().then(config => { if (config.setting('tapPolyfill')) { - console.log('Tap.register, tapPolyfill') - Tap.register(document); + // console.log('Tap.register, tapPolyfill') + // Tap.register(document); } });