зеркало из https://github.com/mozilla/gecko-dev.git
Bug 719459 - Add onmozbrowsertitlechange event. r=smaug
--HG-- extra : rebase_source : b5e8ee64c85e0090a38a849bf077a68055ff56b9
This commit is contained in:
Родитель
6b2098fe3a
Коммит
da0cb52496
|
@ -11,6 +11,7 @@
|
|||
#include "nsIDOMCustomEvent.h"
|
||||
#include "nsIVariant.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsWeakPtr.h"
|
||||
#include "nsVariant.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMMemoryReporter.h"
|
||||
|
@ -37,10 +38,13 @@ NS_INTERFACE_TABLE_HEAD(nsGenericHTMLFrameElement)
|
|||
NS_INTERFACE_MAP_END_INHERITING(nsGenericHTMLElement)
|
||||
|
||||
NS_IMPL_INT_ATTR(nsGenericHTMLFrameElement, TabIndex, tabindex)
|
||||
NS_IMPL_BOOL_ATTR(nsGenericHTMLFrameElement, Mozbrowser, mozbrowser)
|
||||
|
||||
nsGenericHTMLFrameElement::~nsGenericHTMLFrameElement()
|
||||
{
|
||||
if (mTitleChangedListener) {
|
||||
mTitleChangedListener->Unregister();
|
||||
}
|
||||
|
||||
if (mFrameLoader) {
|
||||
mFrameLoader->Destroy();
|
||||
}
|
||||
|
@ -112,17 +116,7 @@ nsGenericHTMLFrameElement::EnsureFrameLoader()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Register ourselves as a web progress listener on the frameloader's
|
||||
// docshell.
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
mFrameLoader->GetDocShell(getter_AddRefs(docShell));
|
||||
nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
|
||||
NS_ENSURE_TRUE(webProgress, NS_OK);
|
||||
|
||||
// This adds a weak ref, so we don't have to worry about unregistering.
|
||||
webProgress->AddProgressListener(this,
|
||||
nsIWebProgress::NOTIFY_LOCATION |
|
||||
nsIWebProgress::NOTIFY_STATE_WINDOW);
|
||||
MaybeEnsureBrowserFrameListenersRegistered();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -285,6 +279,84 @@ nsGenericHTMLFrameElement::SizeOf() const
|
|||
return size;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::GetMozbrowser(bool *aValue)
|
||||
{
|
||||
return GetBoolAttr(nsGkAtoms::mozbrowser, aValue);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::SetMozbrowser(bool aValue)
|
||||
{
|
||||
nsresult rv = SetBoolAttr(nsGkAtoms::mozbrowser, aValue);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MaybeEnsureBrowserFrameListenersRegistered();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this frame element is allowed to be a browser frame (because it passes
|
||||
* BrowserFrameSecurityCheck()), then make sure that it has the appropriate
|
||||
* event listeners enabled.
|
||||
*/
|
||||
void
|
||||
nsGenericHTMLFrameElement::MaybeEnsureBrowserFrameListenersRegistered()
|
||||
{
|
||||
if (mBrowserFrameListenersRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If this frame passes the browser frame security check, ensure that its
|
||||
// listeners are active.
|
||||
if (!BrowserFrameSecurityCheck()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Not much we can do without a frameLoader. But EnsureFrameLoader will call
|
||||
// this function, so we'll get a chance to pass this test.
|
||||
if (!mFrameLoader) {
|
||||
return;
|
||||
}
|
||||
|
||||
mBrowserFrameListenersRegistered = true;
|
||||
|
||||
// Register ourselves as a web progress listener on the frameloader's
|
||||
// docshell.
|
||||
nsCOMPtr<nsIDocShell> docShell;
|
||||
mFrameLoader->GetDocShell(getter_AddRefs(docShell));
|
||||
nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(docShell);
|
||||
|
||||
// This adds a weak ref, so we don't have to worry about unregistering.
|
||||
if (webProgress) {
|
||||
webProgress->AddProgressListener(this,
|
||||
nsIWebProgress::NOTIFY_LOCATION |
|
||||
nsIWebProgress::NOTIFY_STATE_WINDOW);
|
||||
}
|
||||
|
||||
// Register a listener for DOMTitleChanged on the window's chrome event
|
||||
// handler. The chrome event handler outlives this iframe, so we'll have to
|
||||
// unregister when the iframe is destroyed.
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(docShell);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(window->IsOuterWindow());
|
||||
|
||||
nsIDOMEventTarget *chromeHandler = window->GetChromeEventHandler();
|
||||
if (!chromeHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mTitleChangedListener);
|
||||
mTitleChangedListener = new TitleChangedListener(this, chromeHandler);
|
||||
chromeHandler->AddSystemEventListener(NS_LITERAL_STRING("DOMTitleChanged"),
|
||||
mTitleChangedListener,
|
||||
/* useCapture = */ false,
|
||||
/* wantsUntrusted = */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this frame element has permission to send mozbrowser
|
||||
* events, and false otherwise.
|
||||
|
@ -449,3 +521,77 @@ nsGenericHTMLFrameElement::OnSecurityChange(nsIWebProgress *aWebProgress,
|
|||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsGenericHTMLFrameElement::TitleChangedListener,
|
||||
nsIDOMEventListener)
|
||||
|
||||
nsGenericHTMLFrameElement::TitleChangedListener::TitleChangedListener(
|
||||
nsGenericHTMLFrameElement *aElement,
|
||||
nsIDOMEventTarget *aChromeHandler)
|
||||
{
|
||||
mElement =
|
||||
do_GetWeakReference(NS_ISUPPORTS_CAST(nsIDOMMozBrowserFrame*, aElement));
|
||||
mChromeHandler = do_GetWeakReference(aChromeHandler);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGenericHTMLFrameElement::TitleChangedListener::HandleEvent(nsIDOMEvent *aEvent)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsString eventType;
|
||||
aEvent->GetType(eventType);
|
||||
MOZ_ASSERT(eventType.EqualsLiteral("DOMTitleChanged"));
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIDOMMozBrowserFrame> element = do_QueryReferent(mElement);
|
||||
if (!element) {
|
||||
// Hm, our element is gone, but somehow we weren't unregistered?
|
||||
Unregister();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsGenericHTMLFrameElement* frameElement =
|
||||
static_cast<nsGenericHTMLFrameElement*>(element.get());
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> frameDocument;
|
||||
frameElement->GetContentDocument(getter_AddRefs(frameDocument));
|
||||
NS_ENSURE_STATE(frameDocument);
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target;
|
||||
aEvent->GetTarget(getter_AddRefs(target));
|
||||
nsCOMPtr<nsIDOMDocument> targetDocument = do_QueryInterface(target);
|
||||
NS_ENSURE_STATE(targetDocument);
|
||||
|
||||
if (frameDocument != targetDocument) {
|
||||
// This is a titlechange event for the wrong document!
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsString newTitle;
|
||||
nsresult rv = targetDocument->GetTitle(newTitle);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
frameElement->MaybeFireBrowserEvent(
|
||||
NS_LITERAL_STRING("titlechange"),
|
||||
NS_LITERAL_STRING("customevent"),
|
||||
newTitle);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsGenericHTMLFrameElement::TitleChangedListener::Unregister()
|
||||
{
|
||||
nsCOMPtr<nsIDOMEventTarget> chromeHandler = do_QueryReferent(mChromeHandler);
|
||||
if (!chromeHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
chromeHandler->RemoveSystemEventListener(NS_LITERAL_STRING("DOMTitleChanged"),
|
||||
this, /* useCapture = */ false);
|
||||
|
||||
// Careful; the call above may have removed the last strong reference to this
|
||||
// class, so don't dereference |this| here.
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsIDOMHTMLFrameElement.h"
|
||||
#include "nsIDOMMozBrowserFrame.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIWebProgressListener.h"
|
||||
|
||||
/**
|
||||
|
@ -22,9 +23,11 @@ public:
|
|||
nsGenericHTMLFrameElement(already_AddRefed<nsINodeInfo> aNodeInfo,
|
||||
mozilla::dom::FromParser aFromParser)
|
||||
: nsGenericHTMLElement(aNodeInfo)
|
||||
, mNetworkCreated(aFromParser == mozilla::dom::FROM_PARSER_NETWORK)
|
||||
, mBrowserFrameListenersRegistered(false)
|
||||
{
|
||||
mNetworkCreated = aFromParser == mozilla::dom::FROM_PARSER_NETWORK;
|
||||
}
|
||||
|
||||
virtual ~nsGenericHTMLFrameElement();
|
||||
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
@ -60,6 +63,28 @@ public:
|
|||
nsGenericHTMLElement)
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Listens to titlechanged events from the document inside the iframe and
|
||||
* forwards them along to the iframe so it can fire a mozbrowsertitlechange
|
||||
* event if appropriate.
|
||||
*/
|
||||
class TitleChangedListener : public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
TitleChangedListener(nsGenericHTMLFrameElement *aElement,
|
||||
nsIDOMEventTarget *aChromeHandler);
|
||||
|
||||
/* Unregister this listener. */
|
||||
void Unregister();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
private:
|
||||
nsWeakPtr mElement; /* nsGenericHTMLFrameElement */
|
||||
nsWeakPtr mChromeHandler; /* nsIDOMEventTarget */
|
||||
};
|
||||
|
||||
// This doesn't really ensure a frame loade in all cases, only when
|
||||
// it makes sense.
|
||||
nsresult EnsureFrameLoader();
|
||||
|
@ -67,14 +92,19 @@ protected:
|
|||
nsresult GetContentDocument(nsIDOMDocument** aContentDocument);
|
||||
nsresult GetContentWindow(nsIDOMWindow** aContentWindow);
|
||||
|
||||
void MaybeEnsureBrowserFrameListenersRegistered();
|
||||
bool BrowserFrameSecurityCheck();
|
||||
nsresult MaybeFireBrowserEvent(const nsAString &aEventName,
|
||||
const nsAString &aEventType,
|
||||
const nsAString &aValue = EmptyString());
|
||||
|
||||
nsRefPtr<nsFrameLoader> mFrameLoader;
|
||||
nsRefPtr<TitleChangedListener> mTitleChangedListener;
|
||||
|
||||
// True when the element is created by the parser
|
||||
// using NS_FROM_PARSER_NETWORK flag.
|
||||
// If the element is modified, it may lose the flag.
|
||||
bool mNetworkCreated;
|
||||
|
||||
bool mBrowserFrameListenersRegistered;
|
||||
};
|
||||
|
|
|
@ -80,6 +80,7 @@ _TEST_FILES = \
|
|||
test_browserFrame3.html \
|
||||
test_browserFrame4.html \
|
||||
test_browserFrame5.html \
|
||||
test_browserFrame6.html \
|
||||
$(NULL)
|
||||
|
||||
_CHROME_FILES = \
|
||||
|
|
|
@ -25,7 +25,10 @@ SimpleTest.waitForExplicitFinish();
|
|||
function runTest() {
|
||||
browserFrameHelpers.setEnabledPref(false);
|
||||
|
||||
var iframe = document.getElementById('iframe');
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.mozbrowser = true;
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
iframe.addEventListener('mozbrowserloadstart', function() {
|
||||
ok(false, 'Should not send mozbrowserloadstart event.');
|
||||
});
|
||||
|
@ -42,7 +45,5 @@ addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
|
|||
|
||||
</script>
|
||||
|
||||
<iframe id='iframe' mozbrowser></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -26,7 +26,10 @@ function runTest() {
|
|||
browserFrameHelpers.setEnabledPref(true);
|
||||
browserFrameHelpers.setWhitelistPref(' http://foobar.com');
|
||||
|
||||
var iframe = document.getElementById('iframe');
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.mozbrowser = true;
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
iframe.addEventListener('mozbrowserloadstart', function() {
|
||||
ok(false, 'Should not send mozbrowserloadstart event.');
|
||||
});
|
||||
|
@ -43,7 +46,5 @@ addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
|
|||
|
||||
</script>
|
||||
|
||||
<iframe id='iframe' mozbrowser></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -18,7 +18,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=710231
|
|||
-->
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
@ -31,8 +30,24 @@ function runTest() {
|
|||
browserFrameHelpers.setEnabledPref(true);
|
||||
browserFrameHelpers.addToWhitelist();
|
||||
|
||||
var iframe = document.getElementById('iframe');
|
||||
// Load example.org into the iframe, wait for that to load, then call
|
||||
// runTest2. This would *almost* work if we just had a <iframe mozbrowser>
|
||||
// in the HTML, except that we have to set the prefs before we create the
|
||||
// iframe!
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.id = 'iframe';
|
||||
document.body.appendChild(iframe);
|
||||
iframe.src = 'data:text/html,1';
|
||||
iframe.addEventListener('load', function() {
|
||||
iframe.removeEventListener('load', arguments.callee);
|
||||
SimpleTest.executeSoon(runTest2);
|
||||
});
|
||||
}
|
||||
|
||||
function runTest2() {
|
||||
var iframe = document.getElementById('iframe');
|
||||
iframe.mozbrowser = true;
|
||||
iframe.addEventListener('mozbrowserloadstart', function() {
|
||||
ok(!seenLoadStart, 'Just one loadstart event.');
|
||||
seenLoadStart = true;
|
||||
|
@ -82,7 +97,5 @@ addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
|
|||
|
||||
</script>
|
||||
|
||||
<iframe id='iframe' mozbrowser></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -17,7 +17,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=720157
|
|||
-->
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
@ -25,32 +24,62 @@ function runTest() {
|
|||
browserFrameHelpers.setEnabledPref(true);
|
||||
browserFrameHelpers.addToWhitelist();
|
||||
|
||||
var iframe = document.getElementById('iframe');
|
||||
var iframe1 = document.createElement('iframe');
|
||||
document.body.appendChild(iframe1);
|
||||
iframe1.id = 'iframe1';
|
||||
iframe1.addEventListener('load', function() {
|
||||
iframe1.removeEventListener('load', arguments.callee);
|
||||
SimpleTest.executeSoon(runTest2);
|
||||
});
|
||||
iframe1.src = 'http://example.org';
|
||||
}
|
||||
|
||||
function runTest2() {
|
||||
var iframe1 = document.getElementById('iframe1');
|
||||
iframe1.mozbrowser = true;
|
||||
|
||||
var iframe2 = document.getElementById('iframe2');
|
||||
|
||||
var sawLoad = false;
|
||||
var sawLocationChange = false;
|
||||
|
||||
iframe.addEventListener('mozbrowserlocationchange', function(e) {
|
||||
iframe1.addEventListener('mozbrowserlocationchange', function(e) {
|
||||
ok(!sawLocationChange, 'Just one locationchange event.');
|
||||
ok(!sawLoad, 'locationchange before load.');
|
||||
is(e.detail, 'data:text/html,1', "event's reported location");
|
||||
sawLocationChange = true;
|
||||
});
|
||||
|
||||
iframe.addEventListener('load', function() {
|
||||
iframe1.addEventListener('load', function() {
|
||||
ok(sawLocationChange, 'Load after locationchange.');
|
||||
ok(!sawLoad, 'Just one load event.');
|
||||
sawLoad = true;
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
iframe.src = 'data:text/html,1';
|
||||
function iframe2Load() {
|
||||
if (!sawLoad || !sawLocationChange) {
|
||||
// Spin if iframe1 hasn't loaded yet.
|
||||
SimpleTest.executeSoon(iframe2Load);
|
||||
return;
|
||||
}
|
||||
ok(true, 'Got iframe2 load.');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
iframe2.addEventListener('load', iframe2Load);
|
||||
|
||||
|
||||
iframe1.src = 'data:text/html,1';
|
||||
|
||||
// Load something into iframe2 to check that it doesn't trigger a
|
||||
// locationchange for our iframe1 listener.
|
||||
iframe2.src = 'http://example.com';
|
||||
}
|
||||
|
||||
addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
|
||||
|
||||
</script>
|
||||
|
||||
<iframe id='iframe' mozbrowser></iframe>
|
||||
<iframe id='iframe2'></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=720157
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 720157</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="browserFrameHelpers.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=720157">Mozilla Bug 720157</a>
|
||||
|
||||
<!--
|
||||
Test that the onmozbrowsertitlechange event works.
|
||||
-->
|
||||
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function runTest() {
|
||||
browserFrameHelpers.setEnabledPref(true);
|
||||
browserFrameHelpers.addToWhitelist();
|
||||
|
||||
var iframe1 = document.createElement('iframe');
|
||||
iframe1.mozbrowser = true;
|
||||
document.body.appendChild(iframe1);
|
||||
|
||||
// iframe2 is a red herring; we modify its title but don't listen for
|
||||
// titlechanges; we want to make sure that its titlechange events aren't
|
||||
// picked up by the listener on iframe1.
|
||||
var iframe2 = document.createElement('iframe');
|
||||
iframe2.mozbrowser = true;
|
||||
document.body.appendChild(iframe2);
|
||||
|
||||
var numTitleChanges = 0;
|
||||
|
||||
iframe1.addEventListener('mozbrowsertitlechange', function(e) {
|
||||
numTitleChanges++;
|
||||
|
||||
if (numTitleChanges == 1) {
|
||||
is(e.detail, 'Title');
|
||||
iframe1.contentDocument.title = 'New title';
|
||||
iframe2.contentDocument.title = 'BAD TITLE 2';
|
||||
}
|
||||
else if (numTitleChanges == 2) {
|
||||
is(e.detail, 'New title');
|
||||
iframe1.src = 'data:text/html,<html><head><title>Title 3</title></head><body></body></html>';
|
||||
}
|
||||
else if (numTitleChanges == 3) {
|
||||
is(e.detail, 'Title 3');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
else {
|
||||
ok(false, 'Too many titlechange events.');
|
||||
}
|
||||
});
|
||||
|
||||
iframe1.src = 'data:text/html,<html><head><title>Title</title></head><body></body></html>';
|
||||
iframe2.src = 'data:text/html,<html><head><title>BAD TITLE</title></head><body></body></html>';
|
||||
}
|
||||
|
||||
addEventListener('load', function() { SimpleTest.executeSoon(runTest); });
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
Загрузка…
Ссылка в новой задаче