mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-31 21:21:08 +00:00
Bug 462856 - offline app notification code doesn't handle subframes. r=mconnor, r=bz
This commit is contained in:
parent
19961382d3
commit
19435fea38
@ -1155,6 +1155,10 @@ function prepareForStartup() {
|
|||||||
// setup our common DOMLinkAdded listener
|
// setup our common DOMLinkAdded listener
|
||||||
gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
|
gBrowser.addEventListener("DOMLinkAdded", DOMLinkHandler, false);
|
||||||
|
|
||||||
|
// setup our MozApplicationManifest listener
|
||||||
|
gBrowser.addEventListener("MozApplicationManifest",
|
||||||
|
OfflineApps, false);
|
||||||
|
|
||||||
// setup simple gestures support
|
// setup simple gestures support
|
||||||
gGestureSupport.init(true);
|
gGestureSupport.init(true);
|
||||||
}
|
}
|
||||||
@ -3875,10 +3879,6 @@ var XULBrowserWindow = {
|
|||||||
this.endDocumentLoad(aRequest, aStatus);
|
this.endDocumentLoad(aRequest, aStatus);
|
||||||
if (!gBrowser.mTabbedMode && !gBrowser.mCurrentBrowser.mIconURL)
|
if (!gBrowser.mTabbedMode && !gBrowser.mCurrentBrowser.mIconURL)
|
||||||
gBrowser.useDefaultIcon(gBrowser.mCurrentTab);
|
gBrowser.useDefaultIcon(gBrowser.mCurrentTab);
|
||||||
|
|
||||||
if (Components.isSuccessCode(aStatus) &&
|
|
||||||
content.document.documentElement.getAttribute("manifest"))
|
|
||||||
OfflineApps.offlineAppRequested(content);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5334,6 +5334,12 @@ var OfflineApps = {
|
|||||||
obs.removeObserver(this, "offline-cache-update-completed");
|
obs.removeObserver(this, "offline-cache-update-completed");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleEvent: function(event) {
|
||||||
|
if (event.type == "MozApplicationManifest") {
|
||||||
|
this.offlineAppRequested(event.originalTarget.defaultView);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
// OfflineApps Implementation Methods
|
// OfflineApps Implementation Methods
|
||||||
|
|
||||||
@ -5360,6 +5366,7 @@ var OfflineApps = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
_getManifestURI: function(aWindow) {
|
_getManifestURI: function(aWindow) {
|
||||||
|
if (!aWindow.document.documentElement) return null;
|
||||||
var attr = aWindow.document.documentElement.getAttribute("manifest");
|
var attr = aWindow.document.documentElement.getAttribute("manifest");
|
||||||
if (!attr) return null;
|
if (!attr) return null;
|
||||||
|
|
||||||
@ -5481,7 +5488,7 @@ var OfflineApps = {
|
|||||||
var browser = this._getBrowserForContentWindow(browserWindow,
|
var browser = this._getBrowserForContentWindow(browserWindow,
|
||||||
aContentWindow);
|
aContentWindow);
|
||||||
|
|
||||||
var currentURI = browser.webNavigation.currentURI;
|
var currentURI = aContentWindow.document.documentURIObject;
|
||||||
var pm = Cc["@mozilla.org/permissionmanager;1"].
|
var pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||||
getService(Ci.nsIPermissionManager);
|
getService(Ci.nsIPermissionManager);
|
||||||
|
|
||||||
@ -5499,19 +5506,32 @@ var OfflineApps = {
|
|||||||
// this pref isn't set by default, ignore failures
|
// this pref isn't set by default, ignore failures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var host = currentURI.asciiHost;
|
||||||
var notificationBox = gBrowser.getNotificationBox(browser);
|
var notificationBox = gBrowser.getNotificationBox(browser);
|
||||||
var notification = notificationBox.getNotificationWithValue("offline-app-requested");
|
var notificationID = "offline-app-requested-" + host;
|
||||||
if (!notification) {
|
var notification = notificationBox.getNotificationWithValue(notificationID);
|
||||||
|
|
||||||
|
if (notification) {
|
||||||
|
notification.documents.push(aContentWindow.document);
|
||||||
|
} else {
|
||||||
var bundle_browser = document.getElementById("bundle_browser");
|
var bundle_browser = document.getElementById("bundle_browser");
|
||||||
|
|
||||||
var buttons = [{
|
var buttons = [{
|
||||||
label: bundle_browser.getString("offlineApps.allow"),
|
label: bundle_browser.getString("offlineApps.allow"),
|
||||||
accessKey: bundle_browser.getString("offlineApps.allowAccessKey"),
|
accessKey: bundle_browser.getString("offlineApps.allowAccessKey"),
|
||||||
callback: function() { OfflineApps.allowSite(); }
|
callback: function() {
|
||||||
|
for (var i = 0; i < notification.documents.length; i++) {
|
||||||
|
OfflineApps.allowSite(notification.documents[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
},{
|
},{
|
||||||
label: bundle_browser.getString("offlineApps.never"),
|
label: bundle_browser.getString("offlineApps.never"),
|
||||||
accessKey: bundle_browser.getString("offlineApps.neverAccessKey"),
|
accessKey: bundle_browser.getString("offlineApps.neverAccessKey"),
|
||||||
callback: function() { OfflineApps.disallowSite(); }
|
callback: function() {
|
||||||
|
for (var i = 0; i < notification.documents.length; i++) {
|
||||||
|
OfflineApps.disallowSite(notification.documents[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
},{
|
},{
|
||||||
label: bundle_browser.getString("offlineApps.notNow"),
|
label: bundle_browser.getString("offlineApps.notNow"),
|
||||||
accessKey: bundle_browser.getString("offlineApps.notNowAccessKey"),
|
accessKey: bundle_browser.getString("offlineApps.notNowAccessKey"),
|
||||||
@ -5520,51 +5540,55 @@ var OfflineApps = {
|
|||||||
|
|
||||||
const priority = notificationBox.PRIORITY_INFO_LOW;
|
const priority = notificationBox.PRIORITY_INFO_LOW;
|
||||||
var message = bundle_browser.getFormattedString("offlineApps.available",
|
var message = bundle_browser.getFormattedString("offlineApps.available",
|
||||||
[ currentURI.host ]);
|
[ host ]);
|
||||||
notificationBox.appendNotification(message, "offline-app-requested",
|
notification =
|
||||||
"chrome://browser/skin/Info.png",
|
notificationBox.appendNotification(message, notificationID,
|
||||||
priority, buttons);
|
"chrome://browser/skin/Info.png",
|
||||||
|
priority, buttons);
|
||||||
|
notification.documents = [ aContentWindow.document ];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
allowSite: function() {
|
allowSite: function(aDocument) {
|
||||||
var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
|
|
||||||
var pm = Cc["@mozilla.org/permissionmanager;1"].
|
var pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||||
getService(Ci.nsIPermissionManager);
|
getService(Ci.nsIPermissionManager);
|
||||||
pm.add(currentURI, "offline-app", Ci.nsIPermissionManager.ALLOW_ACTION);
|
pm.add(aDocument.documentURIObject, "offline-app",
|
||||||
|
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||||
|
|
||||||
// When a site is enabled while loading, <link rel="offline-resource">
|
// When a site is enabled while loading, manifest resources will
|
||||||
// resources will start fetching immediately. This one time we need to
|
// start fetching immediately. This one time we need to do it
|
||||||
// do it ourselves.
|
// ourselves.
|
||||||
this._startFetching();
|
this._startFetching(aDocument);
|
||||||
},
|
},
|
||||||
|
|
||||||
disallowSite: function() {
|
disallowSite: function(aDocument) {
|
||||||
var currentURI = gBrowser.selectedBrowser.webNavigation.currentURI;
|
|
||||||
var pm = Cc["@mozilla.org/permissionmanager;1"].
|
var pm = Cc["@mozilla.org/permissionmanager;1"].
|
||||||
getService(Ci.nsIPermissionManager);
|
getService(Ci.nsIPermissionManager);
|
||||||
pm.add(currentURI, "offline-app", Ci.nsIPermissionManager.DENY_ACTION);
|
pm.add(aDocument.documentURIObject, "offline-app",
|
||||||
|
Ci.nsIPermissionManager.DENY_ACTION);
|
||||||
},
|
},
|
||||||
|
|
||||||
manage: function() {
|
manage: function() {
|
||||||
openAdvancedPreferences("networkTab");
|
openAdvancedPreferences("networkTab");
|
||||||
},
|
},
|
||||||
|
|
||||||
_startFetching: function() {
|
_startFetching: function(aDocument) {
|
||||||
var manifest = content.document.documentElement.getAttribute("manifest");
|
if (!aDocument.documentElement)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var manifest = aDocument.documentElement.getAttribute("manifest");
|
||||||
if (!manifest)
|
if (!manifest)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||||
getService(Ci.nsIIOService);
|
getService(Ci.nsIIOService);
|
||||||
|
|
||||||
var contentURI = ios.newURI(content.location.href, null, null);
|
var manifestURI = ios.newURI(manifest, aDocument.characterSet,
|
||||||
var manifestURI = ios.newURI(manifest, content.document.characterSet,
|
aDocument.documentURIObject);
|
||||||
contentURI);
|
|
||||||
|
|
||||||
var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
var updateService = Cc["@mozilla.org/offlinecacheupdate-service;1"].
|
||||||
getService(Ci.nsIOfflineCacheUpdateService);
|
getService(Ci.nsIOfflineCacheUpdateService);
|
||||||
updateService.scheduleUpdate(manifestURI, contentURI);
|
updateService.scheduleUpdate(manifestURI, aDocument.documentURIObject);
|
||||||
},
|
},
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -50,6 +50,13 @@ _TEST_FILES = test_feed_discovery.html \
|
|||||||
test_contextmenu.html \
|
test_contextmenu.html \
|
||||||
subtst_contextmenu.html \
|
subtst_contextmenu.html \
|
||||||
ctxmenu-image.png \
|
ctxmenu-image.png \
|
||||||
|
test_offlineNotification.html \
|
||||||
|
offlineChild.html \
|
||||||
|
offlineChild.cacheManifest \
|
||||||
|
offlineChild.cacheManifest^headers^ \
|
||||||
|
offlineChild2.html \
|
||||||
|
offlineChild2.cacheManifest \
|
||||||
|
offlineChild2.cacheManifest^headers^ \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
# browser_bug423833.js disabled temporarily since it's unreliable: bug 428712
|
# browser_bug423833.js disabled temporarily since it's unreliable: bug 428712
|
||||||
|
2
browser/base/content/test/offlineChild.cacheManifest
Normal file
2
browser/base/content/test/offlineChild.cacheManifest
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
CACHE MANIFEST
|
||||||
|
offlineChild.html
|
@ -0,0 +1 @@
|
|||||||
|
Content-Type: text/cache-manifest
|
20
browser/base/content/test/offlineChild.html
Normal file
20
browser/base/content/test/offlineChild.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<html manifest="offlineChild.cacheManifest">
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function finish(success) {
|
||||||
|
window.parent.postMessage(success ? "success" : "failure", "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationCache.oncached = function() { finish(true); }
|
||||||
|
applicationCache.onnoupdate = function() { finish(true); }
|
||||||
|
applicationCache.onerror = function() { finish(false); }
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Child</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
2
browser/base/content/test/offlineChild2.cacheManifest
Normal file
2
browser/base/content/test/offlineChild2.cacheManifest
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
CACHE MANIFEST
|
||||||
|
offlineChild2.html
|
@ -0,0 +1 @@
|
|||||||
|
Content-Type: text/cache-manifest
|
20
browser/base/content/test/offlineChild2.html
Normal file
20
browser/base/content/test/offlineChild2.html
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<html manifest="offlineChild2.cacheManifest">
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function finish(success) {
|
||||||
|
window.parent.postMessage(success ? "success" : "failure", "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationCache.oncached = function() { finish(true); }
|
||||||
|
applicationCache.onnoupdate = function() { finish(true); }
|
||||||
|
applicationCache.onerror = function() { finish(false); }
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Child</h1>
|
||||||
|
</body>
|
||||||
|
</html>
|
68
browser/base/content/test/test_offlineNotification.html
Normal file
68
browser/base/content/test/test_offlineNotification.html
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=462856
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<title>Test offline app notification</title>
|
||||||
|
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body onload="loaded()">
|
||||||
|
<p id="display">
|
||||||
|
<!-- Load the test frame twice from the same domain,
|
||||||
|
to make sure we get notifications for both -->
|
||||||
|
<iframe name="testFrame" src="offlineChild.html"></iframe>
|
||||||
|
<iframe name="testFrame2" src="offlineChild2.html"></iframe>
|
||||||
|
<!-- Load from another domain to make sure we get a second allow/deny
|
||||||
|
notification -->
|
||||||
|
<iframe name="testFrame3" src="http://example.com/tests/browser/base/content/test/offlineChild.html"></iframe>
|
||||||
|
|
||||||
|
<div id="content" style="display: none">
|
||||||
|
</div>
|
||||||
|
<pre id="test">
|
||||||
|
<script class="testbody" type="text/javascript">
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
|
||||||
|
var numFinished = 0;
|
||||||
|
|
||||||
|
window.addEventListener("message", function(event) {
|
||||||
|
is(event.data, "success", "Child was successfully cached.");
|
||||||
|
|
||||||
|
if (++numFinished == 3) {
|
||||||
|
// Clean up after ourself
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
var pm = Components.classes["@mozilla.org/permissionmanager;1"].
|
||||||
|
getService(Components.interfaces.nsIPermissionManager);
|
||||||
|
|
||||||
|
pm.remove(frames.testFrame.document.documentURIObject.host, "offline-app");
|
||||||
|
pm.remove(frames.testFrame3.document.documentURIObject.host, "offline-app");
|
||||||
|
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
function loaded() {
|
||||||
|
// Click the notification bar's "Allow" button. This should kick
|
||||||
|
// off updates, which will eventually lead to getting messages from
|
||||||
|
// the children.
|
||||||
|
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||||
|
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].
|
||||||
|
getService(Components.interfaces.nsIWindowMediator);
|
||||||
|
var win = wm.getMostRecentWindow("navigator:browser");
|
||||||
|
var notificationBox = win.gBrowser.getNotificationBox();
|
||||||
|
|
||||||
|
var notification = notificationBox.getNotificationWithValue("offline-app-requested-localhost");
|
||||||
|
notification.childNodes[0].click();
|
||||||
|
|
||||||
|
notification = notificationBox.getNotificationWithValue("offline-app-requested-example.com");
|
||||||
|
notification.childNodes[0].click();
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -883,6 +883,28 @@ public:
|
|||||||
PRBool aCancelable,
|
PRBool aCancelable,
|
||||||
PRBool *aDefaultAction = nsnull);
|
PRBool *aDefaultAction = nsnull);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method creates and dispatches a trusted event to the chrome
|
||||||
|
* event handler.
|
||||||
|
* Works only with events which can be created by calling
|
||||||
|
* nsIDOMDocumentEvent::CreateEvent() with parameter "Events".
|
||||||
|
* @param aDocument The document which will be used to create the event,
|
||||||
|
* and whose window's chrome handler will be used to
|
||||||
|
* dispatch the event.
|
||||||
|
* @param aTarget The target of the event, used for event->SetTarget()
|
||||||
|
* @param aEventName The name of the event.
|
||||||
|
* @param aCanBubble Whether the event can bubble.
|
||||||
|
* @param aCancelable Is the event cancelable.
|
||||||
|
* @param aDefaultAction Set to true if default action should be taken,
|
||||||
|
* see nsIDOMEventTarget::DispatchEvent.
|
||||||
|
*/
|
||||||
|
static nsresult DispatchChromeEvent(nsIDocument* aDoc,
|
||||||
|
nsISupports* aTarget,
|
||||||
|
const nsAString& aEventName,
|
||||||
|
PRBool aCanBubble,
|
||||||
|
PRBool aCancelable,
|
||||||
|
PRBool *aDefaultAction = nsnull);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if an event attribute name (such as onclick) is valid for
|
* Determines if an event attribute name (such as onclick) is valid for
|
||||||
* a given element type. Types are from the EventNameType enumeration
|
* a given element type. Types are from the EventNameType enumeration
|
||||||
|
@ -3124,6 +3124,51 @@ nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
|
|||||||
return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
|
return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsContentUtils::DispatchChromeEvent(nsIDocument *aDoc,
|
||||||
|
nsISupports *aTarget,
|
||||||
|
const nsAString& aEventName,
|
||||||
|
PRBool aCanBubble, PRBool aCancelable,
|
||||||
|
PRBool *aDefaultAction)
|
||||||
|
{
|
||||||
|
|
||||||
|
NS_ENSURE_ARG_POINTER(aDoc);
|
||||||
|
NS_ENSURE_ARG_POINTER(aDoc->GetWindow());
|
||||||
|
NS_ENSURE_ARG_POINTER(aDoc->GetWindow()->GetChromeEventHandler());
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMDocumentEvent> docEvent = do_QueryInterface(aDoc);
|
||||||
|
nsCOMPtr<nsIDOMEventTarget> originalTarget =
|
||||||
|
do_QueryInterface(aTarget);
|
||||||
|
NS_ENSURE_TRUE(docEvent && originalTarget, NS_ERROR_INVALID_ARG);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIDOMEvent> event;
|
||||||
|
nsresult rv =
|
||||||
|
docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent = do_QueryInterface(event);
|
||||||
|
NS_ENSURE_TRUE(privateEvent, NS_ERROR_FAILURE);
|
||||||
|
|
||||||
|
rv = event->InitEvent(aEventName, aCanBubble, aCancelable);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = privateEvent->SetTarget(originalTarget);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
rv = privateEvent->SetTrusted(PR_TRUE);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsEventStatus status = nsEventStatus_eIgnore;
|
||||||
|
rv = aDoc->GetWindow()->GetChromeEventHandler()->DispatchDOMEvent(nsnull,
|
||||||
|
event,
|
||||||
|
nsnull,
|
||||||
|
&status);
|
||||||
|
if (aDefaultAction) {
|
||||||
|
*aDefaultAction = (status != nsEventStatus_eConsumeNoDefault);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
nsIContent*
|
nsIContent*
|
||||||
nsContentUtils::MatchElementId(nsIContent *aContent, nsIAtom* aId)
|
nsContentUtils::MatchElementId(nsIContent *aContent, nsIAtom* aId)
|
||||||
|
@ -3980,6 +3980,15 @@ nsDocument::DispatchContentLoadedEvents()
|
|||||||
} while (parent);
|
} while (parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the document has a manifest attribute, fire a MozApplicationManifest
|
||||||
|
// event.
|
||||||
|
nsIContent* root = GetRootContent();
|
||||||
|
if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
|
||||||
|
nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
|
||||||
|
NS_LITERAL_STRING("MozApplicationManifest"),
|
||||||
|
PR_TRUE, PR_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
UnblockOnload(PR_TRUE);
|
UnblockOnload(PR_TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user