This repository has been archived by the owner on Nov 3, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
app_window_factory.js
205 lines (185 loc) · 6.46 KB
/
app_window_factory.js
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
'use strict';
/* global applications, BrowserConfigHelper, AppWindowManager,
homescreenLauncher, AppWindow */
/* jshint nonew: false */
(function(exports) {
/**
* AppWindowFactory handle the launch request from gecko and
* wrap the config with properer parameters.
*
* If gecko is asking us to open a webapp,
* AppWindowFactory would do the instantiation and let
* AppWindowManager to do the following app opening control via
* event <code>launchapp</code>.
*
* If gecko is asking us to open an inline activity page,
* AppWindowFactory would wrap the configuration and sent it to
* AppWindowFactory for it to do instantiation via event
* <code>launchactivity</code>.
*
* ![app and activity launch flow](http://i.imgur.com/ZyMcgft.png)
*
* @class AppWindowFactory
*/
function AppWindowFactory() {
this.preHandleEvent = this.preHandleEvent.bind(this);
}
AppWindowFactory.prototype = {
/**
* Indicate whether this class is started or not.
* @access private
* @type {Boolean}
* @memberof AppWindowFactory.prototype
*/
_started: false,
/**
* Register all event handlers.
* @memberof AppWindowFactory.prototype
*/
start: function awf_start() {
if (this._started) {
return;
}
this._started = true;
window.addEventListener('webapps-launch', this.preHandleEvent);
window.addEventListener('webapps-close', this.preHandleEvent);
window.addEventListener('open-app', this.preHandleEvent);
window.addEventListener('applicationready', (function appReady(e) {
window.removeEventListener('applicationready', appReady);
this._handlePendingEvents();
}).bind(this));
},
/**
* Unregister all event handlers.
* @memberof AppWindowFactory.prototype
*/
stop: function awf_stop() {
if (!this._started) {
return;
}
this._started = false;
window.removeEventListener('webapps-launch', this.preHandleEvent);
window.removeEventListener('webapps-close', this.preHandleEvent);
window.removeEventListener('open-app', this.preHandleEvent);
},
/**
* Queue events until AppWindowFactory is ready to handle them.
*/
_queueEvents: [],
_queuePendingEvent: function(evt) {
this._queueEvents.push(evt);
},
_handlePendingEvents: function() {
this._queueEvents.forEach((function(evt) {
this.handleEvent(evt);
}).bind(this));
this._queueEvents = [];
},
preHandleEvent: function(evt) {
if (applications.ready) {
this.handleEvent(evt);
} else {
this._queuePendingEvent(evt);
}
},
handleEvent: function awf_handleEvent(evt) {
var detail = evt.detail;
var manifestURL = detail.manifestURL;
if (!manifestURL) {
return;
}
var config = new BrowserConfigHelper(detail.url, detail.manifestURL);
if (!config.manifest) {
return;
}
switch (evt.type) {
case 'webapps-launch':
// TODO: Look up current opened window list,
// and then create a new instance here.
this.launch(config);
break;
case 'open-app':
// System Message Handler API is asking us to open the specific URL
// that handles the pending system message.
// We will launch it in background if it's not handling an activity.
config.isSystemMessage = true;
if (detail.isActivity) {
config.isActivity = true;
if (detail.target.disposition &&
detail.target.disposition == 'inline') {
config.inline = true;
}
}
config.changeURL = !detail.onlyShowApp;
config.stayBackground = !detail.showApp;
if (detail.extra && detail.extra.manifestURL) {
config.parentApp = detail.extra.manifestURL;
}
// TODO: Create activity window instance
// or background app window instance for system message here.
this.launch(config);
break;
case 'webapps-close':
this.publish('killapp', config);
break;
}
},
/**
* Browser Configuration
* @typedef {Object} BrowserConfig
* @property {String} origin the same as appURL.
* @property {String} manifestURL the same as manifestURL.
* @property {Object} manifest the parsed manifest object.
* If the app is not an entry point app,
* the manifest would be the reference of application
* manifest stored in Applications module. But if the app
* is an entry point app, we will do deep clone to
* generate a new object and replace the properties of
* entry point to proper position.
* @property {String} name the name of the app, retrieved from manifest.
* @property {Boolean} oop Indicate it's running out of process or in
* process.
*/
/**
* Launch an app window.
* @param {BrowserConfig} config Generated by BrowserConfigHelper.
* @memberof AppWindowFactory.prototype
*/
launch: function awf_launch(config) {
if (config.url === window.location.href) {
return;
}
if (config.isActivity && config.inline) {
this.publish('launchactivity', config, document.body);
return;
}
// The rocketbar currently handles the management of
// the search app
if (config.manifest.role === 'search') {
return;
}
var app = AppWindowManager.getApp(config.origin, config.manifestURL);
if (app) {
app.reviveBrowser();
} else if (config.origin !== homescreenLauncher.origin) {
new AppWindow(config);
} else if (config.origin == homescreenLauncher.origin) {
homescreenLauncher.getHomescreen(true);
}
this.publish('launchapp', config);
},
/**
* Publish a CustomEvent.
* @param {String} event The name of the event.
* @param {Object} detail The data passed when initializing the event.
* @memberof AppWindowFactory.prototype
*/
publish: function awf_publish(event, detail, scope) {
scope = scope || window;
var evt = document.createEvent('CustomEvent');
evt.initCustomEvent(event, true, false, detail);
scope.dispatchEvent(evt);
}
};
exports.AppWindowFactory = AppWindowFactory;
}(window));