fix(clickblock): add NavOptions.minClickBlockDuration

* feat(clickblock): ability to set a minimum duration for click block

* fix(clickblock): add NavOptions.minClickBlockDuration
This commit is contained in:
Adam Bradley
2017-01-09 16:44:37 -06:00
committed by Justin Willis
parent 3f164237ae
commit 8ca9797c0f
12 changed files with 50 additions and 10 deletions

View File

@ -6,6 +6,7 @@ import { Config } from '../../config/config';
import { Key } from '../../platform/key'; import { Key } from '../../platform/key';
import { Platform } from '../../platform/platform'; import { Platform } from '../../platform/platform';
import { NavParams } from '../../navigation/nav-params'; import { NavParams } from '../../navigation/nav-params';
import { NavOptions } from '../../navigation/nav-util';
import { ViewController } from '../../navigation/view-controller'; import { ViewController } from '../../navigation/view-controller';
/** /**
@ -174,7 +175,10 @@ export class ActionSheetCmp {
} }
dismiss(role: any): Promise<any> { dismiss(role: any): Promise<any> {
return this._viewCtrl.dismiss(null, role); const opts: NavOptions = {
minClickBlockDuration: 400
};
return this._viewCtrl.dismiss(null, role, opts);
} }
ngOnDestroy() { ngOnDestroy() {

View File

@ -58,6 +58,7 @@ export class ActionSheet extends ViewController {
* @returns {Promise} Returns a promise which is resolved when the transition has completed. * @returns {Promise} Returns a promise which is resolved when the transition has completed.
*/ */
present(navOptions: NavOptions = {}) { present(navOptions: NavOptions = {}) {
navOptions.minClickBlockDuration = navOptions.minClickBlockDuration || 400;
return this._app.present(this, navOptions); return this._app.present(this, navOptions);
} }

View File

@ -6,6 +6,7 @@ import { GestureController, BlockerDelegate, BLOCK_ALL } from '../../gestures/ge
import { isPresent, assert } from '../../util/util'; import { isPresent, assert } from '../../util/util';
import { Key } from '../../platform/key'; import { Key } from '../../platform/key';
import { NavParams } from '../../navigation/nav-params'; import { NavParams } from '../../navigation/nav-params';
import { NavOptions } from '../../navigation/nav-util';
import { Platform } from '../../platform/platform'; import { Platform } from '../../platform/platform';
import { ViewController } from '../../navigation/view-controller'; import { ViewController } from '../../navigation/view-controller';
@ -298,7 +299,10 @@ export class AlertCmp {
} }
dismiss(role: any): Promise<any> { dismiss(role: any): Promise<any> {
return this._viewCtrl.dismiss(this.getValues(), role); const opts: NavOptions = {
minClickBlockDuration: 400
};
return this._viewCtrl.dismiss(this.getValues(), role, opts);
} }
getValues(): any { getValues(): any {

View File

@ -81,6 +81,7 @@ export class Alert extends ViewController {
* @returns {Promise} Returns a promise which is resolved when the transition has completed. * @returns {Promise} Returns a promise which is resolved when the transition has completed.
*/ */
present(navOptions: NavOptions = {}) { present(navOptions: NavOptions = {}) {
navOptions.minClickBlockDuration = navOptions.minClickBlockDuration || 400;
return this._app.present(this, navOptions); return this._app.present(this, navOptions);
} }

View File

@ -119,17 +119,17 @@ export class App {
* it will automatically enable the app again. It's basically a fallback incase * it will automatically enable the app again. It's basically a fallback incase
* something goes wrong during a transition and the app wasn't re-enabled correctly. * something goes wrong during a transition and the app wasn't re-enabled correctly.
*/ */
setEnabled(isEnabled: boolean, duration: number = 700) { setEnabled(isEnabled: boolean, duration: number = 700, minDuration: number = 0) {
this._disTime = (isEnabled ? 0 : Date.now() + duration); this._disTime = (isEnabled ? 0 : Date.now() + duration);
if (this._clickBlock) { if (this._clickBlock) {
if (isEnabled) { if (isEnabled) {
// disable the click block if it's enabled, or the duration is tiny // disable the click block if it's enabled, or the duration is tiny
this._clickBlock.activate(false, CLICK_BLOCK_BUFFER_IN_MILLIS); this._clickBlock.activate(false, CLICK_BLOCK_BUFFER_IN_MILLIS, minDuration);
} else { } else {
// show the click block for duration + some number // show the click block for duration + some number
this._clickBlock.activate(true, duration + CLICK_BLOCK_BUFFER_IN_MILLIS); this._clickBlock.activate(true, duration + CLICK_BLOCK_BUFFER_IN_MILLIS, minDuration);
} }
} }
} }

View File

@ -2,6 +2,7 @@ import { Component, ComponentFactoryResolver, HostListener, Renderer, ViewChild,
import { Key } from '../../platform/key'; import { Key } from '../../platform/key';
import { NavParams } from '../../navigation/nav-params'; import { NavParams } from '../../navigation/nav-params';
import { NavOptions } from '../../navigation/nav-util';
import { ViewController } from '../../navigation/view-controller'; import { ViewController } from '../../navigation/view-controller';
import { GestureController, BlockerDelegate, GESTURE_MENU_SWIPE, GESTURE_GO_BACK_SWIPE } from '../../gestures/gesture-controller'; import { GestureController, BlockerDelegate, GESTURE_MENU_SWIPE, GESTURE_GO_BACK_SWIPE } from '../../gestures/gesture-controller';
import { assert } from '../../util/util'; import { assert } from '../../util/util';
@ -78,7 +79,10 @@ export class ModalCmp {
_bdClick() { _bdClick() {
if (this._enabled && this._bdDismiss) { if (this._enabled && this._bdDismiss) {
return this._viewCtrl.dismiss(null, 'backdrop').catch(() => { const opts: NavOptions = {
minClickBlockDuration: 400
};
return this._viewCtrl.dismiss(null, 'backdrop', opts).catch(() => {
console.debug('Dismiss modal by clicking backdrop was cancelled'); console.debug('Dismiss modal by clicking backdrop was cancelled');
}); });
} }

View File

@ -58,6 +58,7 @@ export class Modal extends ViewController {
* @returns {Promise} Returns a promise which is resolved when the transition has completed. * @returns {Promise} Returns a promise which is resolved when the transition has completed.
*/ */
present(navOptions: NavOptions = {}) { present(navOptions: NavOptions = {}) {
navOptions.minClickBlockDuration = navOptions.minClickBlockDuration || 400;
return this._app.present(this, navOptions, AppPortal.MODAL); return this._app.present(this, navOptions, AppPortal.MODAL);
} }

View File

@ -663,7 +663,7 @@ export class NavControllerBase extends Ion implements NavController {
if (duration > DISABLE_APP_MINIMUM_DURATION && opts.disableApp !== false) { if (duration > DISABLE_APP_MINIMUM_DURATION && opts.disableApp !== false) {
// if this transition has a duration and this is the root transition // if this transition has a duration and this is the root transition
// then set that the app is actively disabled // then set that the app is actively disabled
this._app.setEnabled(false, duration + ACTIVE_TRANSITION_OFFSET); this._app.setEnabled(false, duration + ACTIVE_TRANSITION_OFFSET, opts.minClickBlockDuration);
} else { } else {
console.debug('transition is running but app has not been disabled'); console.debug('transition is running but app has not been disabled');
} }

View File

@ -162,6 +162,7 @@ export interface NavOptions {
keyboardClose?: boolean; keyboardClose?: boolean;
progressAnimation?: boolean; progressAnimation?: boolean;
disableApp?: boolean; disableApp?: boolean;
minClickBlockDuration?: number;
ev?: any; ev?: any;
updateUrl?: boolean; updateUrl?: boolean;
isNavRoot?: boolean; isNavRoot?: boolean;

View File

@ -167,6 +167,12 @@ export class ViewController {
if (!this._nav) { if (!this._nav) {
return Promise.resolve(false); return Promise.resolve(false);
} }
if (this.isOverlay && !navOptions.minClickBlockDuration) {
// This is a Modal being dismissed so we need
// to add the minClickBlockDuration option
// for UIWebView
navOptions.minClickBlockDuration = 400;
}
this._dismissData = data; this._dismissData = data;
this._dismissRole = role; this._dismissRole = role;

View File

@ -63,8 +63,8 @@ ion-input :focus {
opacity: 0; opacity: 0;
transform: translate3d(0, -100%, 0) translateY(1px); transform: translate3d(0, -100%, 0) translateY(1px);
// background: red; background: red;
// opacity: .3; opacity: .3;
contain: strict; contain: strict;
} }

View File

@ -14,6 +14,8 @@ import { Platform } from '../platform/platform';
export class ClickBlock { export class ClickBlock {
private _tmr: number; private _tmr: number;
private _showing: boolean = false; private _showing: boolean = false;
private _start: number;
private _minEnd: number;
isEnabled: boolean; isEnabled: boolean;
constructor( constructor(
@ -31,10 +33,15 @@ export class ClickBlock {
} }
} }
activate(shouldShow: boolean, expire: number = 100) { activate(shouldShow: boolean, expire: number = 100, minDuration: number = 0) {
if (this.isEnabled) { if (this.isEnabled) {
this.plt.cancelTimeout(this._tmr); this.plt.cancelTimeout(this._tmr);
if (shouldShow) { if (shouldShow) {
// remember when we started the click block
this._start = Date.now();
// figure out the minimum time it should be showing until
// this is useful for transitions that are less than 300ms
this._minEnd = this._start + (minDuration || 0);
this._activate(true); this._activate(true);
} }
this._tmr = this.plt.timeout(this._activate.bind(this, false), expire); this._tmr = this.plt.timeout(this._activate.bind(this, false), expire);
@ -44,6 +51,17 @@ export class ClickBlock {
/** @internal */ /** @internal */
_activate(shouldShow: boolean) { _activate(shouldShow: boolean) {
if (this._showing !== shouldShow) { if (this._showing !== shouldShow) {
if (!shouldShow) {
// check if it was enabled before the minimum duration
// this is useful for transitions that are less than 300ms
var now = Date.now();
if (now < this._minEnd) {
this._tmr = this.plt.timeout(this._activate.bind(this, false), this._minEnd - now);
return;
}
}
this._setElementClass('click-block-active', shouldShow); this._setElementClass('click-block-active', shouldShow);
this._showing = shouldShow; this._showing = shouldShow;
} }