VulpesOS/gaia/tv_apps/smart-system/js/wrapper_factory.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

198 lines
5.9 KiB
JavaScript
Executable file

'use strict';
/*global applications, AppWindowManager, AppWindow, AppInstallManager */
(function(window) {
/**
* WrapperFactory deals with opening a window for bookmarked web page.
* Usually the request is coming from homescreen app.
* @module WrapperFactory
*/
var WrapperFactory = {
init: function wf_init() {
window.addEventListener('mozbrowseropenwindow', this, true);
},
handleEvent: function wf_handleEvent(evt) {
// Prevent Gecko's default handler from opening the window.
evt.preventDefault();
var detail = evt.detail;
// If it's a normal window.open request, ignore.
if (typeof detail.features !== 'string') {
return;
}
// Turn ',' separated 'key=value' string into object for easy access
var features = detail.features
.split(',')
.reduce(function(acc, feature) {
feature = feature
.split('=')
.map(function(featureElem) { return featureElem.trim(); });
if (feature.length !== 2) {
return acc;
}
acc[decodeURIComponent(feature[0])] = decodeURIComponent(feature[1]);
return acc;
}, {});
if ('preview' in features && features.preview === 'true' &&
AppInstallManager.isMarketplaceAppActive()) {
var marketplaceApp = AppWindowManager.getActiveApp();
marketplaceApp.publish('launchpreviewapp', {
url: detail.url,
origin: detail.url,
features: {
name: features.name,
iconUrl: features.iconUrl
}
});
evt.stopImmediatePropagation();
return;
}
// Handles only call to window.open with `remote=true` feature.
if (!('remote' in features) || features.remote !== 'true') {
return;
}
var callerOrigin;
// Examine permission
// XXX: Ask app window about this.
// We can skip the permission check for events against the system window.
if (evt.target !== window) {
var callerIframe = evt.target;
var manifestURL = callerIframe.getAttribute('mozapp');
var callerApp = applications.getByManifestURL(manifestURL);
if (!this.hasPermission(callerApp, 'open-remote-window')) {
return;
}
callerOrigin = callerApp.origin;
} else {
callerOrigin = location.origin;
}
// So, we are going to open a remote window.
evt.stopImmediatePropagation();
var name = detail.name;
var url = detail.url;
var isAppLike = (features.applike === 'true');
var app;
// Use fake origin for named windows in order to be able to reuse them,
// otherwise always open a new window for '_blank'.
var origin = null;
if (name == '_blank') {
if (!isAppLike) {
// If we already have a browser and we receive an open request,
// display it in the current browser frame.
var activeApp = AppWindowManager.getActiveApp();
if (activeApp && activeApp.isBrowser()) {
activeApp.navigate(url);
return;
}
}
origin = url;
app = AppWindowManager.getApp(origin);
// Just bring on top if a wrapper window is
// already running with this url.
if (app && app.windowName == '_blank') {
this.publish('launchapp', { origin: origin });
}
} else {
origin = 'window:' + name + ',source:' + callerOrigin;
app = AppWindowManager.getApp(origin);
if (app && app.windowName === name) {
if (app.iframe.src === url) {
// If the url is already loaded, just display the app
this.publish('launchapp', { origin: origin });
return;
} else {
// Wrapper context shouldn't be shared between two apps -> killing
this.publish('killapp', { origin: origin });
}
}
}
// TODO: Put this into browser_config_helper.
var browser_config = this.generateBrowserConfig(features);
// If we don't reuse an existing app, open a brand new one
browser_config.url = url;
browser_config.origin = origin;
browser_config.windowName = name;
if (!browser_config.title) {
browser_config.title = url;
}
if (isAppLike) {
browser_config.isAppLike = true;
browser_config.identity = origin;
}
this.launchWrapper(browser_config);
},
launchWrapper: function wf_launchWrapper(config) {
var app = AppWindowManager.getApp(config.origin);
if (!app) {
config.chrome = {
scrollable: !config.isAppLike
};
app = new AppWindow(config);
} else {
app.updateName(config.title);
}
this.publish('launchapp', { origin: config.origin });
},
hasPermission: function wf_hasPermission(app, permission) {
var mozPerms = navigator.mozPermissionSettings;
if (!mozPerms) {
return false;
}
var value = mozPerms.get(permission, app.manifestURL, app.origin, false);
return (value === 'allow');
},
generateBrowserConfig: function wf_generateBrowserConfig(features) {
var config = {};
config.title = features.name;
config.icon = features.icon || '';
if ('originName' in features) {
config.originName = features.originName;
config.originURL = features.originUrl;
}
if ('searchName' in features) {
config.searchName = features.searchName;
config.searchURL = features.searchUrl;
}
if ('remote' in features) {
config.oop = true;
}
return config;
},
publish: function wf_publish(event, detail) {
var evt = new CustomEvent(event, { detail: detail });
window.dispatchEvent(evt);
}
};
window.WrapperFactory = WrapperFactory;
WrapperFactory.init();
}(window));