зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1005818 - Part 1: Load a widget as an app if the |src| is in the |widgetPages|. r=fabrice, sr=sicking
1. Add permission |embed-widgets| and Element attribute |mozwidget| 2. Add |hasWidgetPage| in /mozIApplication.idl 3. Check permission |embed-widgets| and the |src| is in the |widgetPages| when |GetAppManifest| 4. Add test case 5. Should enable preference |dom.enable_widgets|
This commit is contained in:
Родитель
ebe0ceedb6
Коммит
2df665e34c
|
@ -288,6 +288,7 @@ interface nsIFrameLoader : nsISupports
|
|||
|
||||
/**
|
||||
* Find out whether the owner content really is a browser or app frame
|
||||
* Especially, a widget frame is regarded as an app frame.
|
||||
*/
|
||||
readonly attribute boolean ownerIsBrowserOrAppFrame;
|
||||
};
|
||||
|
|
|
@ -91,6 +91,7 @@ GK_ATOM(_and, "and")
|
|||
GK_ATOM(anonid, "anonid")
|
||||
GK_ATOM(any, "any")
|
||||
GK_ATOM(mozapp, "mozapp")
|
||||
GK_ATOM(mozwidget, "mozwidget")
|
||||
GK_ATOM(applet, "applet")
|
||||
GK_ATOM(applyImports, "apply-imports")
|
||||
GK_ATOM(applyTemplates, "apply-templates")
|
||||
|
|
|
@ -332,6 +332,63 @@ nsGenericHTMLFrameElement::GetIsExpectingSystemMessage(bool *aOut)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/** Get manifest url of app or widget
|
||||
* @param AppType: nsGkAtoms::mozapp or nsGkAtoms::mozwidget
|
||||
*/
|
||||
void nsGenericHTMLFrameElement::GetManifestURLByType(nsIAtom *aAppType,
|
||||
nsAString& aManifestURL)
|
||||
{
|
||||
aManifestURL.Truncate();
|
||||
|
||||
if (aAppType != nsGkAtoms::mozapp && aAppType != nsGkAtoms::mozwidget) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString manifestURL;
|
||||
GetAttr(kNameSpaceID_None, aAppType, manifestURL);
|
||||
if (manifestURL.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check permission.
|
||||
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
||||
NS_ENSURE_TRUE_VOID(permMgr);
|
||||
nsIPrincipal *principal = NodePrincipal();
|
||||
const char* aPermissionType = (aAppType == nsGkAtoms::mozapp) ? "embed-apps"
|
||||
: "embed-widgets";
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
|
||||
aPermissionType,
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE_VOID(appsService);
|
||||
|
||||
nsCOMPtr<mozIApplication> app;
|
||||
appsService->GetAppByManifestURL(manifestURL, getter_AddRefs(app));
|
||||
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasWidgetPage = false;
|
||||
nsAutoString src;
|
||||
if (aAppType == nsGkAtoms::mozwidget) {
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
|
||||
nsresult rv = app->HasWidgetPage(src, &hasWidgetPage);
|
||||
|
||||
if (!NS_SUCCEEDED(rv) || !hasWidgetPage) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aManifestURL.Assign(manifestURL);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
|
||||
{
|
||||
|
@ -342,35 +399,36 @@ nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Check permission.
|
||||
nsIPrincipal *principal = NodePrincipal();
|
||||
nsCOMPtr<nsIPermissionManager> permMgr =
|
||||
services::GetPermissionManager();
|
||||
NS_ENSURE_TRUE(permMgr, NS_OK);
|
||||
nsAutoString appManifestURL;
|
||||
nsAutoString widgetManifestURL;
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
nsresult rv = permMgr->TestPermissionFromPrincipal(principal,
|
||||
"embed-apps",
|
||||
&permission);
|
||||
NS_ENSURE_SUCCESS(rv, NS_OK);
|
||||
if (permission != nsIPermissionManager::ALLOW_ACTION) {
|
||||
GetManifestURLByType(nsGkAtoms::mozapp, appManifestURL);
|
||||
|
||||
if (Preferences::GetBool("dom.enable_widgets")) {
|
||||
GetManifestURLByType(nsGkAtoms::mozwidget, widgetManifestURL);
|
||||
}
|
||||
|
||||
bool isApp = !appManifestURL.IsEmpty();
|
||||
bool isWidget = !widgetManifestURL.IsEmpty();
|
||||
|
||||
if (!isApp && !isWidget) {
|
||||
// No valid case to get manifest
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (isApp && isWidget) {
|
||||
NS_WARNING("Can not simultaneously be mozapp and mozwidget");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString manifestURL;
|
||||
GetAttr(kNameSpaceID_None, nsGkAtoms::mozapp, manifestURL);
|
||||
if (manifestURL.IsEmpty()) {
|
||||
return NS_OK;
|
||||
if (isApp) {
|
||||
manifestURL.Assign(appManifestURL);
|
||||
} else if (isWidget) {
|
||||
manifestURL.Assign(widgetManifestURL);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
NS_ENSURE_TRUE(appsService, NS_OK);
|
||||
|
||||
nsCOMPtr<mozIApplication> app;
|
||||
appsService->GetAppByManifestURL(manifestURL, getter_AddRefs(app));
|
||||
if (app) {
|
||||
aOut.Assign(manifestURL);
|
||||
}
|
||||
aOut.Assign(manifestURL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@ protected:
|
|||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
private:
|
||||
void GetManifestURLByType(nsIAtom *aAppType, nsAString& aOut);
|
||||
};
|
||||
|
||||
#endif // nsGenericHTMLFrameElement_h
|
||||
|
|
|
@ -57,6 +57,10 @@ mozIApplication.prototype = {
|
|||
return (perm === Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
},
|
||||
|
||||
hasWidgetPage: function(aPageURL) {
|
||||
return this.widgetPages.indexOf(aPageURL) != -1;
|
||||
},
|
||||
|
||||
QueryInterface: function(aIID) {
|
||||
if (aIID.equals(Ci.mozIApplication) ||
|
||||
aIID.equals(Ci.nsISupports))
|
||||
|
@ -100,6 +104,7 @@ function _setAppProperties(aObj, aApp) {
|
|||
aObj.storeVersion = aApp.storeVersion || 0;
|
||||
aObj.role = aApp.role || "";
|
||||
aObj.redirects = aApp.redirects;
|
||||
aObj.widgetPages = aApp.widgetPages || [];
|
||||
aObj.kind = aApp.kind;
|
||||
}
|
||||
|
||||
|
@ -678,6 +683,10 @@ ManifestHelper.prototype = {
|
|||
return this._localeProp("package_path");
|
||||
},
|
||||
|
||||
get widgetPages() {
|
||||
return this._localeProp("widgetPages");
|
||||
},
|
||||
|
||||
get size() {
|
||||
return this._manifest["size"] || 0;
|
||||
},
|
||||
|
|
|
@ -232,6 +232,11 @@ this.PermissionsTable = { geolocation: {
|
|||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"embed-widgets": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"storage": {
|
||||
app: ALLOW_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
|
|
|
@ -262,6 +262,10 @@ this.DOMApplicationRegistry = {
|
|||
app.role = "";
|
||||
}
|
||||
|
||||
if (app.widgetPages === undefined) {
|
||||
app.widgetPages = [];
|
||||
}
|
||||
|
||||
// At startup we can't be downloading, and the $TMP directory
|
||||
// will be empty so we can't just apply a staged update.
|
||||
app.downloading = false;
|
||||
|
@ -321,6 +325,15 @@ this.DOMApplicationRegistry = {
|
|||
return res.length > 0 ? res : null;
|
||||
},
|
||||
|
||||
_saveWidgetsFullPath: function(aManifest, aDestApp) {
|
||||
if (aManifest.widgetPages) {
|
||||
aDestApp.widgetPages = aManifest.widgetPages.map(aManifest.resolveURL,
|
||||
aManifest/* thisArg */);
|
||||
} else {
|
||||
aDestApp.widgetPages = [];
|
||||
}
|
||||
},
|
||||
|
||||
// Registers all the activities and system messages.
|
||||
registerAppsHandlers: Task.async(function*(aRunUpdate) {
|
||||
this.notifyAppsRegistryStart();
|
||||
|
@ -345,6 +358,10 @@ this.DOMApplicationRegistry = {
|
|||
let app = this.webapps[aResult.id];
|
||||
app.csp = aResult.manifest.csp || "";
|
||||
app.role = aResult.manifest.role || "";
|
||||
|
||||
let localeManifest = new ManifestHelper(aResult.manifest, app.origin, app.manifestURL);
|
||||
this._saveWidgetsFullPath(localeManifest, app);
|
||||
|
||||
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
|
||||
app.redirects = this.sanitizeRedirects(aResult.redirects);
|
||||
}
|
||||
|
@ -984,6 +1001,8 @@ this.DOMApplicationRegistry = {
|
|||
app.name = manifest.name;
|
||||
app.csp = manifest.csp || "";
|
||||
app.role = localeManifest.role;
|
||||
this._saveWidgetsFullPath(localeManifest, app);
|
||||
|
||||
if (app.appStatus >= Ci.nsIPrincipal.APP_STATUS_PRIVILEGED) {
|
||||
app.redirects = this.sanitizeRedirects(manifest.redirects);
|
||||
}
|
||||
|
@ -2014,6 +2033,8 @@ this.DOMApplicationRegistry = {
|
|||
aApp.downloadAvailable = true;
|
||||
aApp.downloadSize = manifest.size;
|
||||
aApp.updateManifest = aNewManifest;
|
||||
this._saveWidgetsFullPath(manifest, aApp);
|
||||
|
||||
yield this._saveApps();
|
||||
|
||||
this.broadcastMessage("Webapps:UpdateState", {
|
||||
|
@ -2072,6 +2093,7 @@ this.DOMApplicationRegistry = {
|
|||
aApp.name = aNewManifest.name;
|
||||
aApp.csp = manifest.csp || "";
|
||||
aApp.role = manifest.role || "";
|
||||
this._saveWidgetsFullPath(manifest, aApp);
|
||||
aApp.updateTime = Date.now();
|
||||
} else {
|
||||
manifest =
|
||||
|
@ -2471,6 +2493,7 @@ this.DOMApplicationRegistry = {
|
|||
appObject.name = aManifest.name;
|
||||
appObject.csp = aLocaleManifest.csp || "";
|
||||
appObject.role = aLocaleManifest.role;
|
||||
this._saveWidgetsFullPath(aLocaleManifest, appObject);
|
||||
appObject.installerAppId = aData.appId;
|
||||
appObject.installerIsBrowser = aData.isBrowser;
|
||||
|
||||
|
@ -2506,6 +2529,9 @@ this.DOMApplicationRegistry = {
|
|||
|
||||
app.csp = aManifest.csp || "";
|
||||
|
||||
let aLocaleManifest = new ManifestHelper(aManifest, app.origin, app.manifestURL);
|
||||
this._saveWidgetsFullPath(aLocaleManifest, app);
|
||||
|
||||
app.appStatus = AppsUtils.getAppManifestStatus(aManifest);
|
||||
|
||||
app.removable = true;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
var gBasePath = "tests/dom/apps/tests/";
|
||||
var gAppTemplatePath = "tests/dom/apps/tests/file_app.template.html";
|
||||
var gAppcacheTemplatePath = "tests/dom/apps/tests/file_cached_app.template.appcache";
|
||||
var gWidgetTemplatePath = "tests/dom/apps/tests/file_widget_app.template.html";
|
||||
var gDefaultIcon = "default_icon";
|
||||
|
||||
function makeResource(templatePath, version, apptype) {
|
||||
|
@ -14,7 +15,6 @@ function makeResource(templatePath, version, apptype) {
|
|||
if (templatePath == gAppTemplatePath && apptype == 'cached') {
|
||||
res = res.replace('<html>', '<html manifest="file_app.sjs?apptype=cached&getappcache=true">');
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ function handleRequest(request, response) {
|
|||
|
||||
// Get the app type.
|
||||
var apptype = query.apptype;
|
||||
if (apptype != 'hosted' && apptype != 'cached')
|
||||
if (apptype != 'hosted' && apptype != 'cached' && apptype != 'widget')
|
||||
throw "Invalid app type: " + apptype;
|
||||
|
||||
// Get the version from server state and handle the etag.
|
||||
|
@ -83,7 +83,12 @@ function handleRequest(request, response) {
|
|||
response.write(makeResource(gAppcacheTemplatePath, version, apptype));
|
||||
return;
|
||||
}
|
||||
|
||||
else if (apptype == 'widget')
|
||||
{
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(makeResource(gWidgetTemplatePath, version, apptype));
|
||||
return;
|
||||
}
|
||||
// Generate the app.
|
||||
response.setHeader("Content-Type", "text/html", false);
|
||||
response.write(makeResource(gAppTemplatePath, version, apptype));
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function sendMessage(msg) {
|
||||
alert(msg);
|
||||
}
|
||||
|
||||
function ok(p, msg) {
|
||||
if (p)
|
||||
sendMessage("OK: " + msg);
|
||||
else
|
||||
sendMessage("KO: " + msg);
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
if (a == b)
|
||||
sendMessage("OK: " + a + " == " + b + " - " + msg);
|
||||
else
|
||||
sendMessage("KO: " + a + " != " + b + " - " + msg);
|
||||
}
|
||||
|
||||
function installed(p) {
|
||||
if (p)
|
||||
sendMessage("IS_INSTALLED");
|
||||
else
|
||||
sendMessage("NOT_INSTALLED");
|
||||
}
|
||||
|
||||
function finish() {
|
||||
sendMessage("VERSION: MyWebApp vVERSIONTOKEN");
|
||||
sendMessage("DONE");
|
||||
}
|
||||
|
||||
function cbError() {
|
||||
ok(false, "Error callback invoked");
|
||||
finish();
|
||||
}
|
||||
|
||||
function go() {
|
||||
ok(true, "Launched app");
|
||||
var request = window.navigator.mozApps.getSelf();
|
||||
request.onsuccess = function() {
|
||||
var widget = request.result;
|
||||
ok(widget,"Should be a widget");
|
||||
checkWidget(widget);
|
||||
}
|
||||
request.onerror = cbError;
|
||||
}
|
||||
|
||||
function checkWidget(widget) {
|
||||
// If the widget is installed, |widget| will be non-null. If it is, verify its state.
|
||||
installed(!!widget);
|
||||
if (widget) {
|
||||
var widgetName = "Really Rapid Release (APPTYPETOKEN)";
|
||||
var manifest = SpecialPowers.wrap(widget.manifest);
|
||||
is(manifest.name, widgetName, "Manifest name should be correct");
|
||||
is(widget.origin, "http://test", "Widget origin should be correct");
|
||||
is(widget.installOrigin, "http://mochi.test:8888", "Install origin should be correct");
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="go();">
|
||||
App Body. Version: VERSIONTOKEN
|
||||
</body></html>
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "Really Rapid Release (widget)",
|
||||
"description": "Updated even faster than <a href='http://mozilla.org'>Firefox</a>, just to annoy slashdotters.",
|
||||
"launch_path": "/tests/dom/apps/tests/file_app.sjs?apptype=widget",
|
||||
"icons": {
|
||||
"128": "ICONTOKEN"
|
||||
},
|
||||
"widgetPages": [
|
||||
"/tests/dom/apps/tests/file_app.sjs?apptype=widget"
|
||||
]
|
||||
}
|
|
@ -10,6 +10,8 @@ support-files =
|
|||
file_packaged_app.sjs
|
||||
file_packaged_app.template.html
|
||||
file_packaged_app.template.webapp
|
||||
file_widget_app.template.webapp
|
||||
file_widget_app.template.html
|
||||
signed_app.sjs
|
||||
signed_app_template.webapp
|
||||
signed/*
|
||||
|
@ -28,3 +30,4 @@ skip-if = buildapp == "b2g" || toolkit == "android" # see bug 989806
|
|||
[test_receipt_operations.html]
|
||||
[test_signed_pkg_install.html]
|
||||
[test_uninstall_errors.html]
|
||||
[test_widget.html]
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for DataStore - basic operation on a readonly db</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
<script type="application/javascript;version=1.7">
|
||||
|
||||
var gWidgetManifestURL = 'http://test/tests/dom/apps/tests/file_app.sjs?apptype=widget&getmanifest=true';
|
||||
var gApp;
|
||||
|
||||
function cbError() {
|
||||
ok(false, "Error callback invoked");
|
||||
finish();
|
||||
}
|
||||
|
||||
function installApp() {
|
||||
var request = navigator.mozApps.install(gWidgetManifestURL);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = function() {
|
||||
gApp = request.result;
|
||||
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
function uninstallApp() {
|
||||
// Uninstall the app.
|
||||
var request = navigator.mozApps.mgmt.uninstall(gApp);
|
||||
request.onerror = cbError;
|
||||
request.onsuccess = function() {
|
||||
// All done.
|
||||
info("All done");
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
function testApp() {
|
||||
var ifr = document.createElement('iframe');
|
||||
ifr.setAttribute('mozbrowser', 'true');
|
||||
ifr.setAttribute('mozwidget', gApp.manifestURL);
|
||||
ifr.setAttribute('src', gApp.origin+gApp.manifest.launch_path);
|
||||
|
||||
var domParent = document.getElementById('container');
|
||||
|
||||
// Set us up to listen for messages from the app.
|
||||
var listener = function(e) {
|
||||
var message = e.detail.message;
|
||||
if (/^OK/.exec(message)) {
|
||||
ok(true, "Message from widget: " + message);
|
||||
} else if (/KO/.exec(message)) {
|
||||
ok(false, "Message from widget: " + message);
|
||||
} else if (/DONE/.exec(message)) {
|
||||
ok(true, "Message from widget complete");
|
||||
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
|
||||
domParent.removeChild(ifr);
|
||||
runTest();
|
||||
}
|
||||
}
|
||||
|
||||
// This event is triggered when the app calls "alert".
|
||||
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
|
||||
domParent.appendChild(ifr);
|
||||
}
|
||||
|
||||
var tests = [
|
||||
// Permissions
|
||||
function() {
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "browser", "allow": 1, "context": document },
|
||||
{ "type": "embed-widgets", "allow": 1, "context": document },
|
||||
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest);
|
||||
},
|
||||
|
||||
// Preferences
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.mozBrowserFramesEnabled", true],
|
||||
["dom.enable_widgets", true]]}, runTest);
|
||||
},
|
||||
|
||||
function() {
|
||||
SpecialPowers.setAllAppsLaunchable(true);
|
||||
runTest();
|
||||
},
|
||||
|
||||
// No confirmation needed when an app is installed
|
||||
function() {
|
||||
SpecialPowers.autoConfirmAppInstall(runTest);
|
||||
},
|
||||
|
||||
// Installing the app
|
||||
installApp,
|
||||
|
||||
// Run tests in app
|
||||
testApp,
|
||||
|
||||
// Uninstall the app
|
||||
uninstallApp
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
if (SpecialPowers.isMainProcess()) {
|
||||
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -11,12 +11,18 @@
|
|||
* We expose Gecko-internal helpers related to "web apps" through this
|
||||
* sub-interface.
|
||||
*/
|
||||
[scriptable, uuid(7bd62430-c374-49eb-be1b-ce821a180360)]
|
||||
[scriptable, uuid(1d856b11-ac29-47d3-bd52-a86e3d45fcf4)]
|
||||
interface mozIApplication: nsISupports
|
||||
{
|
||||
/* Return true if this app has |permission|. */
|
||||
boolean hasPermission(in string permission);
|
||||
|
||||
/**
|
||||
* Return true if this app can be a widget and
|
||||
* its |widgetPages| contains |page|
|
||||
*/
|
||||
boolean hasWidgetPage(in DOMString pageURL);
|
||||
|
||||
/* Application status as defined in nsIPrincipal. */
|
||||
readonly attribute unsigned short appStatus;
|
||||
|
||||
|
|
|
@ -25,8 +25,11 @@ interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
|
|||
* Gets whether this frame really is an app frame.
|
||||
*
|
||||
* In order to really be an app frame, this frame must really be a browser
|
||||
* frame (this requirement will go away eventually), and the frame's mozapp
|
||||
* attribute must point to the manifest of a valid app.
|
||||
* frame (this requirement will go away eventually), and must satisfy one
|
||||
* and only one of the following conditions:
|
||||
* 1. the frame's mozapp attribute must point to the manifest of a valid app
|
||||
* 2. the frame's mozwidget attribute must point to the manifest of a valid
|
||||
* app, and the src should be in the |widgetPages| specified by the manifest.
|
||||
*/
|
||||
[infallible] readonly attribute boolean reallyIsApp;
|
||||
|
||||
|
@ -41,7 +44,8 @@ interface nsIMozBrowserFrame : nsIDOMMozBrowserFrame
|
|||
[infallible] readonly attribute boolean isExpectingSystemMessage;
|
||||
|
||||
/**
|
||||
* Gets this frame's app manifest URL, if the frame really is an app frame.
|
||||
* Gets this frame's app manifest URL or widget manifest URL, if the frame
|
||||
* really is an app frame.
|
||||
* Otherwise, returns the empty string.
|
||||
*
|
||||
* This method is guaranteed not to fail.
|
||||
|
|
Загрузка…
Ссылка в новой задаче