forked from ionic-team/ionic-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.ts
More file actions
276 lines (233 loc) · 7.12 KB
/
app.ts
File metadata and controls
276 lines (233 loc) · 7.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
import { EventEmitter, Injectable } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { AppPortal, IonicApp } from './app-root';
import { ClickBlock } from '../../util/click-block';
import { Config } from '../../config/config';
import { isNav, isTabs, NavOptions, DIRECTION_FORWARD, DIRECTION_BACK } from '../../navigation/nav-util';
import { NavController } from '../../navigation/nav-controller';
import { Platform } from '../../platform/platform';
import { ViewController } from '../../navigation/view-controller';
/**
* Ionic App
*/
@Injectable()
export class App {
private _disTime: number = 0;
private _scrollTime: number = 0;
private _title: string = '';
private _titleSrv: Title = new Title();
private _rootNav: NavController = null;
/**
* @private
*/
_clickBlock: ClickBlock;
/**
* @private
*/
_appRoot: IonicApp;
/**
* @private
*/
viewDidLoad: EventEmitter<any> = new EventEmitter();
/**
* @private
*/
viewWillEnter: EventEmitter<any> = new EventEmitter();
/**
* @private
*/
viewDidEnter: EventEmitter<any> = new EventEmitter();
/**
* @private
*/
viewWillLeave: EventEmitter<any> = new EventEmitter();
/**
* @private
*/
viewDidLeave: EventEmitter<any> = new EventEmitter();
/**
* @private
*/
viewWillUnload: EventEmitter<any> = new EventEmitter();
constructor(
private _config: Config,
private _platform: Platform
) {
// listen for hardware back button events
// register this back button action with a default priority
_platform.registerBackButtonAction(this.navPop.bind(this));
}
/**
* Sets the document title.
* @param {string} val Value to set the document title to.
*/
setTitle(val: string) {
if (val !== this._title) {
this._title = val;
this._titleSrv.setTitle(val);
}
}
/**
* @private
*/
setElementClass(className: string, isAdd: boolean) {
this._appRoot.setElementClass(className, isAdd);
}
/**
* Sets if the app is currently enabled or not, meaning if it's
* available to accept new user commands. For example, this is set to `false`
* while views transition, a modal slides up, an action-sheet
* slides up, etc. After the transition completes it is set back to `true`.
* @param {boolean} isEnabled `true` for enabled, `false` for disabled
* @param {number} duration When `isEnabled` is set to `false`, this argument
* is used to set the maximum number of milliseconds that app will wait until
* 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.
*/
setEnabled(isEnabled: boolean, duration: number = 700) {
this._disTime = (isEnabled ? 0 : Date.now() + duration);
if (this._clickBlock) {
if (isEnabled || duration <= 32) {
// disable the click block if it's enabled, or the duration is tiny
this._clickBlock.activate(false, 0);
} else {
// show the click block for duration + some number
this._clickBlock.activate(true, duration + CLICK_BLOCK_BUFFER_IN_MILLIS);
}
}
}
/**
* Toggles whether an application can be scrolled
* @param {boolean} disableScroll when set to `false`, the application's
* scrolling is enabled. When set to `true`, scrolling is disabled.
*/
setScrollDisabled(disableScroll: boolean) {
if (this._config.get('canDisableScroll', true)) {
this._appRoot._disableScroll(disableScroll);
}
}
/**
* @private
* Boolean if the app is actively enabled or not.
* @return {boolean}
*/
isEnabled(): boolean {
return (this._disTime < Date.now());
}
/**
* @private
*/
setScrolling() {
this._scrollTime = Date.now();
}
/**
* Boolean if the app is actively scrolling or not.
* @return {boolean}
*/
isScrolling(): boolean {
return (this._scrollTime + 48 > Date.now());
}
/**
* @private
*/
getActiveNav(): NavController {
var nav = this._rootNav || null;
var activeChildNav: any;
while (nav) {
activeChildNav = nav.getActiveChildNav();
if (!activeChildNav) {
break;
}
nav = activeChildNav;
}
return nav;
}
/**
* retuns the root NavController
*/
getRootNav(): NavController {
return this._rootNav;
}
/**
* @private
*/
_setRootNav(nav: any) {
this._rootNav = nav;
}
/**
* @private
*/
present(enteringView: ViewController, opts: NavOptions, appPortal?: AppPortal): Promise<any> {
const portal = this._appRoot._getPortal(appPortal);
enteringView._setNav(portal);
opts.keyboardClose = false;
opts.direction = DIRECTION_FORWARD;
if (!opts.animation) {
opts.animation = enteringView.getTransitionName(DIRECTION_FORWARD);
}
enteringView.setLeavingOpts({
keyboardClose: false,
direction: DIRECTION_BACK,
animation: enteringView.getTransitionName(DIRECTION_BACK),
ev: opts.ev
});
return portal.insertPages(-1, [enteringView], opts);
}
/**
* @private
*/
navPop(): Promise<any> {
// function used to climb up all parent nav controllers
function navPop(nav: any): Promise<any> {
if (nav) {
if (isTabs(nav)) {
// FYI, using "nav instanceof Tabs" throws a Promise runtime error for whatever reason, idk
// this is a Tabs container
// see if there is a valid previous tab to go to
let prevTab = nav.previousTab(true);
if (prevTab) {
console.debug('app, goBack previous tab');
nav.select(prevTab);
return Promise.resolve();
}
} else if (isNav(nav) && nav.length() > 1) {
// this nav controller has more than one view
// pop the current view on this nav and we're done here
console.debug('app, goBack pop nav');
return nav.pop();
}
// try again using the parent nav (if there is one)
return navPop(nav.parent);
}
// nerp, never found nav that could pop off a view
return null;
}
// app must be enabled and there must be a
// root nav controller for go back to work
if (this._rootNav && this.isEnabled()) {
const portal = this._appRoot._getPortal();
// first check if the root navigation has any overlays
// opened in it's portal, like alert/actionsheet/popup
if (portal.length() > 0) {
// there is an overlay view in the portal
// let's pop this one off to go back
console.debug('app, goBack pop overlay');
return portal.pop();
}
// next get the active nav, check itself and climb up all
// of its parent navs until it finds a nav that can pop
let navPromise = navPop(this.getActiveNav());
if (navPromise === null) {
// no views to go back to
// let's exit the app
if (this._config.getBoolean('navExitApp', true)) {
console.debug('app, goBack exitApp');
this._platform.exitApp();
}
}
return navPromise;
}
return Promise.resolve();
}
}
const CLICK_BLOCK_BUFFER_IN_MILLIS = 64;