mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
Bug 386782. save and restore editor state so that it isn't lost when a page goes into the bfcache and then comes back. patch by Chris Pearce, r+sr=peterv,a=beltzner
This commit is contained in:
parent
7f0ad58213
commit
e39f69c653
@ -3961,6 +3961,13 @@ static PRBool HasPresShell(nsPIDOMWindow *aWindow)
|
||||
return presShell != nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLDocument::SetEditingState(EditingState aState)
|
||||
{
|
||||
mEditingState = aState;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLDocument::EditingStateChanged()
|
||||
{
|
||||
|
@ -221,6 +221,8 @@ public:
|
||||
mFragmentParser = aParser;
|
||||
}
|
||||
|
||||
virtual nsresult SetEditingState(EditingState aState);
|
||||
|
||||
protected:
|
||||
nsresult GetBodySize(PRInt32* aWidth,
|
||||
PRInt32* aHeight);
|
||||
|
@ -55,11 +55,11 @@ class nsIDOMHTMLBodyElement;
|
||||
class nsIScriptElement;
|
||||
class nsIEditor;
|
||||
|
||||
// Update htmldocument.gqi when updating this IID!
|
||||
// bfd644d6-92cc-4560-a329-f02ba0c91ca5
|
||||
// 19d63a6c-cc94-499c-892a-955add772e10
|
||||
#define NS_IHTMLDOCUMENT_IID \
|
||||
{ 0xbfd644d6, 0x92cc, 0x4560, \
|
||||
{ 0xa3, 0x29, 0xf0, 0x2b, 0xa0, 0xc9, 0x1c, 0xa5 } }
|
||||
{ 0x19d63a6c, 0xcc94, 0x499c, \
|
||||
{ 0x89, 0x2a, 0x95, 0x5a, 0xdd, 0x77, 0x2e, 0x10 } }
|
||||
|
||||
|
||||
/**
|
||||
* HTML document extensions to nsIDocument.
|
||||
@ -165,6 +165,13 @@ public:
|
||||
*/
|
||||
virtual EditingState GetEditingState() = 0;
|
||||
|
||||
/**
|
||||
* Set the editing state of the document. Don't use this if you want
|
||||
* to enable/disable editing, call EditingStateChanged() or
|
||||
* SetDesignMode().
|
||||
*/
|
||||
virtual nsresult SetEditingState(EditingState aState) = 0;
|
||||
|
||||
/**
|
||||
* Returns the result of document.all[aID] which can either be a node
|
||||
* or a nodelist depending on if there are multiple nodes with the same
|
||||
|
@ -120,6 +120,7 @@
|
||||
#include "nsCDefaultURIFixup.h"
|
||||
#include "nsDocShellEnumerator.h"
|
||||
#include "nsSHistory.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
|
||||
// Helper Classes
|
||||
#include "nsDOMError.h"
|
||||
@ -306,7 +307,6 @@ nsDocShell::nsDocShell():
|
||||
mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto),
|
||||
mPreviousTransIndex(-1),
|
||||
mLoadedTransIndex(-1),
|
||||
mEditorData(nsnull),
|
||||
mTreeOwner(nsnull),
|
||||
mChromeEventHandler(nsnull)
|
||||
#ifdef DEBUG
|
||||
@ -1013,10 +1013,10 @@ nsDocShell::FirePageHideNotification(PRBool aIsUnload)
|
||||
}
|
||||
}
|
||||
|
||||
// Now make sure our editor, if any, is torn down before we go
|
||||
// Now make sure our editor, if any, is detached before we go
|
||||
// any farther.
|
||||
if (mEditorData && aIsUnload) {
|
||||
mEditorData->TearDownEditor();
|
||||
DetachEditorFromWindow();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -3352,6 +3352,12 @@ nsDocShell::Reload(PRUint32 aReloadFlags)
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
|
||||
|
||||
// Need to purge detached editor here, else when we reload a page,
|
||||
// the detached editor state causes SetDesignMode() to fail.
|
||||
if (mOSHE)
|
||||
mOSHE->SetEditorData(nsnull);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -3663,8 +3669,7 @@ nsDocShell::Destroy()
|
||||
// Stop any URLs that are currently being loaded...
|
||||
Stop(nsIWebNavigation::STOP_ALL);
|
||||
|
||||
delete mEditorData;
|
||||
mEditorData = 0;
|
||||
mEditorData = nsnull;
|
||||
|
||||
mTransferableHookData = nsnull;
|
||||
|
||||
@ -5303,6 +5308,67 @@ nsDocShell::CanSavePresentation(PRUint32 aLoadType,
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsDocShell::HasDetachedEditor()
|
||||
{
|
||||
return (mOSHE && mOSHE->HasDetachedEditor()) ||
|
||||
(mLSHE && mLSHE->HasDetachedEditor());
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::ReattachEditorToWindow(nsIDOMWindow *aWindow, nsISHEntry *aSHEntry)
|
||||
{
|
||||
NS_ASSERTION(!mEditorData,
|
||||
"Why reattach an editor when we already have one?");
|
||||
NS_ASSERTION(aWindow,
|
||||
"Need a window to reattach to.");
|
||||
NS_ASSERTION(HasDetachedEditor(),
|
||||
"Reattaching when there's not a detached editor.");
|
||||
|
||||
if (mEditorData || !aWindow || !aSHEntry)
|
||||
return;
|
||||
|
||||
mEditorData = aSHEntry->ForgetEditorData();
|
||||
if (mEditorData) {
|
||||
nsresult res = mEditorData->ReattachToWindow(aWindow);
|
||||
NS_ASSERTION(NS_SUCCEEDED(res), "Failed to reattach editing session");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::DetachEditorFromWindow(nsISHEntry *aSHEntry)
|
||||
{
|
||||
if (!aSHEntry || !mEditorData)
|
||||
return;
|
||||
|
||||
NS_ASSERTION(!aSHEntry->HasDetachedEditor(),
|
||||
"Why detach an editor twice?");
|
||||
|
||||
nsresult res = mEditorData->DetachFromWindow();
|
||||
NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
|
||||
|
||||
if (NS_SUCCEEDED(res)) {
|
||||
// Make aSHEntry hold the owning ref to the editor data.
|
||||
aSHEntry->SetEditorData(mEditorData.forget());
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
PRBool isEditable;
|
||||
GetEditable(&isEditable);
|
||||
NS_ASSERTION(!isEditable,
|
||||
"Window is still editable after detaching editor.");
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::DetachEditorFromWindow()
|
||||
{
|
||||
DetachEditorFromWindow(mOSHE);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocShell::CaptureState()
|
||||
{
|
||||
@ -5920,6 +5986,11 @@ nsDocShell::RestoreFromHistory()
|
||||
}
|
||||
}
|
||||
|
||||
if (HasDetachedEditor()) {
|
||||
nsCOMPtr<nsIDOMWindow> domWin = do_QueryInterface(privWin);
|
||||
ReattachEditorToWindow(domWin, mLSHE);
|
||||
}
|
||||
|
||||
// Simulate the completion of the load.
|
||||
nsDocShell::FinishRestore();
|
||||
|
||||
@ -7045,7 +7116,11 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||
}
|
||||
|
||||
mLoadType = aLoadType;
|
||||
|
||||
|
||||
// Detach the current editor so that it can be restored from the
|
||||
// bfcache later.
|
||||
DetachEditorFromWindow();
|
||||
|
||||
// mLSHE should be assigned to aSHEntry, only after Stop() has
|
||||
// been called. But when loading an error page, do not clear the
|
||||
// mLSHE for the real page.
|
||||
@ -7110,6 +7185,22 @@ nsDocShell::InternalLoad(nsIURI * aURI,
|
||||
DisplayLoadError(rv, aURI, nsnull, chan);
|
||||
}
|
||||
|
||||
if (aSHEntry) {
|
||||
if (aLoadType & LOAD_CMD_HISTORY) {
|
||||
// We've just loaded a page from session history. Reattach
|
||||
// its editing session if it has one.
|
||||
nsCOMPtr<nsIDOMWindow> domWin;
|
||||
CallGetInterface(this, static_cast<nsIDOMWindow**>(getter_AddRefs(domWin)));
|
||||
ReattachEditorToWindow(domWin, aSHEntry);
|
||||
} else {
|
||||
// This is a non-history load from a session history entry. Purge any
|
||||
// previous editing sessions, so that the the editing session will
|
||||
// be recreated. This can happen when we reload something that's
|
||||
// in the bfcache.
|
||||
aSHEntry->SetEditorData(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -8916,10 +9007,10 @@ nsDocShell::EnsureScriptEnvironment()
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::EnsureEditorData()
|
||||
{
|
||||
if (!mEditorData && !mIsBeingDestroyed)
|
||||
{
|
||||
NS_ASSERTION(!HasDetachedEditor(), "EnsureEditorData() called when detached.\n");
|
||||
|
||||
if (!mEditorData && !mIsBeingDestroyed && !HasDetachedEditor()) {
|
||||
mEditorData = new nsDocShellEditorData(this);
|
||||
if (!mEditorData) return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
|
||||
|
@ -525,6 +525,9 @@ protected:
|
||||
// we are it's still OK to load this URI.
|
||||
PRBool IsOKToLoadURI(nsIURI* aURI);
|
||||
|
||||
void ReattachEditorToWindow(nsIDOMWindow *aWindow, nsISHEntry *aSHEntry);
|
||||
void DetachEditorFromWindow(nsISHEntry *aSHEntry);
|
||||
|
||||
protected:
|
||||
// Override the parent setter from nsDocLoader
|
||||
virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader);
|
||||
@ -642,8 +645,8 @@ protected:
|
||||
PRInt32 mPreviousTransIndex;
|
||||
PRInt32 mLoadedTransIndex;
|
||||
|
||||
// Editor stuff
|
||||
nsDocShellEditorData* mEditorData; // editor data, if any
|
||||
// Editor data, if this document is designMode or contentEditable.
|
||||
nsAutoPtr<nsDocShellEditorData> mEditorData;
|
||||
|
||||
// Transferable hooks/callbacks
|
||||
nsCOMPtr<nsIClipboardDragDropHookList> mTransferableHookData;
|
||||
@ -674,6 +677,9 @@ protected:
|
||||
|
||||
static nsIURIFixup *sURIFixup;
|
||||
|
||||
// Returns true when the currently open document has a detached editor
|
||||
// waiting to be reattached.
|
||||
PRBool HasDetachedEditor();
|
||||
|
||||
public:
|
||||
class InterfaceRequestorProxy : public nsIInterfaceRequestor {
|
||||
|
@ -40,13 +40,11 @@
|
||||
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
|
||||
#include "nsIDOMWindow.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
|
||||
nsDocShellEditorData
|
||||
@ -56,6 +54,7 @@
|
||||
nsDocShellEditorData::nsDocShellEditorData(nsIDocShell* inOwningDocShell)
|
||||
: mDocShell(inOwningDocShell)
|
||||
, mMakeEditable(PR_FALSE)
|
||||
, mIsDetached(PR_FALSE)
|
||||
{
|
||||
NS_ASSERTION(mDocShell, "Where is my docShell?");
|
||||
}
|
||||
@ -74,18 +73,12 @@ nsDocShellEditorData::~nsDocShellEditorData()
|
||||
void
|
||||
nsDocShellEditorData::TearDownEditor()
|
||||
{
|
||||
if (mEditingSession)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(mDocShell);
|
||||
// This will eventually call nsDocShellEditorData::SetEditor(nsnull)
|
||||
// which will call mEditorPreDestroy() and delete the editor
|
||||
mEditingSession->TearDownEditorOnWindow(domWindow);
|
||||
}
|
||||
else if (mEditor) // Should never have this w/o nsEditingSession!
|
||||
{
|
||||
NS_ASSERTION(mIsDetached, "We should be detached before tearing down");
|
||||
if (mEditor) {
|
||||
mEditor->PreDestroy();
|
||||
mEditor = nsnull; // explicit clear to make destruction order predictable
|
||||
mEditor = nsnull;
|
||||
}
|
||||
mEditingSession = nsnull;
|
||||
}
|
||||
|
||||
|
||||
@ -95,7 +88,7 @@ nsDocShellEditorData::TearDownEditor()
|
||||
|
||||
----------------------------------------------------------------------------*/
|
||||
nsresult
|
||||
nsDocShellEditorData::MakeEditable(PRBool inWaitForUriLoad /*, PRBool inEditable */)
|
||||
nsDocShellEditorData::MakeEditable(PRBool inWaitForUriLoad)
|
||||
{
|
||||
if (mMakeEditable)
|
||||
return NS_OK;
|
||||
@ -218,6 +211,7 @@ nsresult
|
||||
nsDocShellEditorData::EnsureEditingSession()
|
||||
{
|
||||
NS_ASSERTION(mDocShell, "Should have docShell here");
|
||||
NS_ASSERTION(!mIsDetached, "This will stomp editing session!");
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
@ -230,3 +224,44 @@ nsDocShellEditorData::EnsureEditingSession()
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocShellEditorData::DetachFromWindow()
|
||||
{
|
||||
NS_ASSERTION(mEditingSession,
|
||||
"Can't detach when we don't have a session to detach!");
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(mDocShell);
|
||||
nsresult rv = mEditingSession->DetachFromWindow(domWindow);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mIsDetached = PR_TRUE;
|
||||
mDetachedMakeEditable = mMakeEditable;
|
||||
mMakeEditable = PR_FALSE;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
domWindow->GetDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
|
||||
if (htmlDoc)
|
||||
mDetachedEditingState = htmlDoc->GetEditingState();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsDocShellEditorData::ReattachToWindow(nsIDOMWindow *aWindow)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(mDocShell);
|
||||
nsresult rv = mEditingSession->ReattachToWindow(domWindow);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mIsDetached = PR_FALSE;
|
||||
mMakeEditable = mDetachedMakeEditable;
|
||||
|
||||
nsCOMPtr<nsIDOMDocument> domDoc;
|
||||
domWindow->GetDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
|
||||
if (htmlDoc)
|
||||
htmlDoc->SetEditingState(mDetachedEditingState);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -52,53 +52,54 @@
|
||||
#endif
|
||||
|
||||
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsIEditor.h"
|
||||
|
||||
|
||||
// a non-XPCOM class that is used to store per-docshell editor-related
|
||||
// data.
|
||||
class nsIDOMWindow;
|
||||
|
||||
class nsDocShellEditorData
|
||||
{
|
||||
public:
|
||||
|
||||
nsDocShellEditorData(nsIDocShell* inOwningDocShell);
|
||||
~nsDocShellEditorData();
|
||||
|
||||
nsDocShellEditorData(nsIDocShell* inOwningDocShell);
|
||||
~nsDocShellEditorData();
|
||||
|
||||
// set a flag to say this frame should be editable when the next url loads
|
||||
nsresult MakeEditable(PRBool inWaitForUriLoad);
|
||||
|
||||
PRBool GetEditable();
|
||||
|
||||
// actually create the editor for this docShell
|
||||
nsresult CreateEditor();
|
||||
|
||||
// get the editing session. The editing session always lives on the content
|
||||
// root docShell; this call may crawl up the frame tree to find it.
|
||||
nsresult GetEditingSession(nsIEditingSession **outEditingSession);
|
||||
|
||||
// get the editor for this docShell. May return null but NS_OK
|
||||
nsresult GetEditor(nsIEditor **outEditor);
|
||||
|
||||
// set the editor on this docShell
|
||||
nsresult SetEditor(nsIEditor *inEditor);
|
||||
|
||||
// Tear down the editor on this docshell, if any.
|
||||
void TearDownEditor();
|
||||
|
||||
protected:
|
||||
|
||||
nsresult EnsureEditingSession();
|
||||
nsresult MakeEditable(PRBool inWaitForUriLoad);
|
||||
PRBool GetEditable();
|
||||
nsresult CreateEditor();
|
||||
nsresult GetEditingSession(nsIEditingSession **outEditingSession);
|
||||
nsresult GetEditor(nsIEditor **outEditor);
|
||||
nsresult SetEditor(nsIEditor *inEditor);
|
||||
void TearDownEditor();
|
||||
nsresult DetachFromWindow();
|
||||
nsresult ReattachToWindow(nsIDOMWindow *aWindow);
|
||||
|
||||
protected:
|
||||
|
||||
nsIDocShell* mDocShell; // the doc shell that owns us. Weak ref, since it always outlives us.
|
||||
|
||||
nsCOMPtr<nsIEditingSession> mEditingSession; // only present for the content root docShell. Session is owned here
|
||||
nsresult EnsureEditingSession();
|
||||
|
||||
PRBool mMakeEditable; // indicates whether to make an editor after a url load
|
||||
nsCOMPtr<nsIEditor> mEditor; // if this frame is editable, store editor here. Editor is owned here.
|
||||
// The doc shell that owns us. Weak ref, since it always outlives us.
|
||||
nsIDocShell* mDocShell;
|
||||
|
||||
// Only present for the content root docShell. Session is owned here.
|
||||
nsCOMPtr<nsIEditingSession> mEditingSession;
|
||||
|
||||
// Indicates whether to make an editor after a url load.
|
||||
PRBool mMakeEditable;
|
||||
|
||||
// If this frame is editable, store editor here. Editor is owned here.
|
||||
nsCOMPtr<nsIEditor> mEditor;
|
||||
|
||||
// Denotes if the editor is detached from its window. The editor is detached
|
||||
// while it's stored in the session history bfcache.
|
||||
PRBool mIsDetached;
|
||||
|
||||
// Backup for mMakeEditable while the editor is detached.
|
||||
PRBool mDetachedMakeEditable;
|
||||
|
||||
// Backup for the corresponding nsIHTMLDocument's editing state while
|
||||
// the editor is detached.
|
||||
nsIHTMLDocument::EditingState mDetachedEditingState;
|
||||
|
||||
};
|
||||
|
||||
|
@ -457,5 +457,11 @@ interface nsIDocShell : nsISupports
|
||||
* known JAR type).
|
||||
*/
|
||||
readonly attribute boolean channelIsUnsafe;
|
||||
|
||||
/**
|
||||
* Disconnects this docshell's editor from its window, and stores the
|
||||
* editor data in the open document's session history entry.
|
||||
*/
|
||||
[noscript, notxpcom] void DetachEditorFromWindow();
|
||||
};
|
||||
|
||||
|
@ -52,8 +52,11 @@ interface nsIDocShellTreeItem;
|
||||
interface nsISupportsArray;
|
||||
%{C++
|
||||
struct nsRect;
|
||||
class nsDocShellEditorData;
|
||||
%}
|
||||
[ref] native nsRect(nsRect);
|
||||
[ptr] native nsDocShellEditorDataPtr(nsDocShellEditorData);
|
||||
|
||||
|
||||
[scriptable, uuid(abe54136-49e5-44ca-a749-290038c6b85d)]
|
||||
interface nsISHEntry : nsIHistoryEntry
|
||||
@ -188,6 +191,23 @@ interface nsISHEntry : nsIHistoryEntry
|
||||
* came from.
|
||||
*/
|
||||
attribute nsISupports owner;
|
||||
|
||||
/**
|
||||
* Gets the owning pointer to the editor data assosicated with
|
||||
* this shistory entry. This forgets its pointer, so free it when
|
||||
* you're done.
|
||||
*/
|
||||
[noscript, notxpcom] nsDocShellEditorDataPtr forgetEditorData();
|
||||
|
||||
/**
|
||||
* Sets the owning pointer to the editor data assosicated with
|
||||
* this shistory entry. Unless forgetEditorData() is called, this
|
||||
* shentry will destroy the editor data when it's destroyed.
|
||||
*/
|
||||
[noscript, notxpcom] void setEditorData(in nsDocShellEditorDataPtr aData);
|
||||
|
||||
/** Returns true if this shistory entry is storing a detached editor. */
|
||||
[noscript, notxpcom] boolean hasDetachedEditor();
|
||||
};
|
||||
|
||||
|
||||
|
@ -59,6 +59,8 @@ REQUIRES = xpcom \
|
||||
content \
|
||||
widget \
|
||||
nkcache \
|
||||
editor \
|
||||
composer \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = nsSHEntry.cpp \
|
||||
@ -72,3 +74,4 @@ EXTRA_DSO_LDOPTS = \
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
LOCAL_INCLUDES += -I$(srcdir)/../../base
|
||||
|
@ -54,6 +54,8 @@
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "nsISHistory.h"
|
||||
#include "nsISHistoryInternal.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
#include "nsIDocShell.h"
|
||||
|
||||
// Hardcode this to time out unused content viewers after 30 minutes
|
||||
#define CONTENT_VIEWER_TIMEOUT_SECONDS 30*60
|
||||
@ -161,6 +163,8 @@ nsSHEntry::~nsSHEntry()
|
||||
viewer->Destroy();
|
||||
}
|
||||
|
||||
mEditorData = nsnull;
|
||||
|
||||
#ifdef DEBUG
|
||||
// This is not happening as far as I can tell from breakpad as of early November 2007
|
||||
nsExpirationTracker<nsSHEntry,3>::Iterator iterator(gHistoryTracker);
|
||||
@ -833,3 +837,25 @@ nsSHEntry::DocumentMutated()
|
||||
// Warning! The call to DropPresentationState could have dropped the last
|
||||
// reference to this nsSHEntry, so no accessing members beyond here.
|
||||
}
|
||||
|
||||
nsDocShellEditorData*
|
||||
nsSHEntry::ForgetEditorData()
|
||||
{
|
||||
return mEditorData.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsSHEntry::SetEditorData(nsDocShellEditorData* aData)
|
||||
{
|
||||
NS_ASSERTION(!(aData && mEditorData),
|
||||
"We're going to overwrite an owning ref!");
|
||||
if (mEditorData != aData)
|
||||
mEditorData = aData;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsSHEntry::HasDetachedEditor()
|
||||
{
|
||||
return mEditorData != nsnull;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
// Interfaces needed
|
||||
#include "nsIContentViewer.h"
|
||||
@ -59,6 +60,7 @@
|
||||
#include "nsSupportsArray.h"
|
||||
#include "nsIMutationObserver.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsDocShellEditorData.h"
|
||||
|
||||
class nsSHEntry : public nsISHEntry,
|
||||
public nsISHContainer,
|
||||
@ -113,6 +115,7 @@ private:
|
||||
nsCOMPtr<nsISupportsArray> mRefreshURIList;
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsExpirationState mExpirationState;
|
||||
nsAutoPtr<nsDocShellEditorData> mEditorData;
|
||||
};
|
||||
|
||||
#endif /* nsSHEntry_h */
|
||||
|
@ -49,6 +49,7 @@ _TEST_FILES = \
|
||||
test_bug270414.html \
|
||||
test_bug278916.html \
|
||||
test_bug279495.html \
|
||||
test_bug386782.html \
|
||||
test_child.html \
|
||||
test_grandchild.html \
|
||||
test_sibling-off-domain.html \
|
||||
|
136
docshell/test/navigation/test_bug386782.html
Normal file
136
docshell/test/navigation/test_bug386782.html
Normal file
@ -0,0 +1,136 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=386782
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 386782</title>
|
||||
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script>
|
||||
|
||||
// This tests if we can load a document whose root is in designMode,
|
||||
// edit it, navigate to a new page, navigate back, still edit, and still
|
||||
// undo/redo. Note that this is different from the case where the
|
||||
// designMode document is in a frame inside the window, as this means
|
||||
// the editable region is not in the root docshell (a less complicated case).
|
||||
|
||||
|
||||
//var test.window = null;
|
||||
var testInterval = 2000;
|
||||
|
||||
var gTests = [
|
||||
{
|
||||
// <html><body onload="document.designMode='on'"><p>designModeDocument</p></body></html>
|
||||
url: 'data:text/html;charset=utf-8;base64,PGh0bWw%2BPGJvZHkgb25sb2FkPSJkb2N1bWVudC5kZXNpZ25Nb2RlPSdvbiciPjxwPmRlc2lnbk1vZGVEb2N1bWVudDwvcD48L2JvZHk%2BPC9odG1sPg0K',
|
||||
name: 'designModeNavigate',
|
||||
expectedBodyBeforeEdit: '<p>designModeDocument</p>',
|
||||
expectedBodyAfterEdit: '<p>EDITED designModeDocument</p>',
|
||||
expectedBodyAfterSecondEdit: '<p>EDITED TWICE designModeDocument</p>',
|
||||
},
|
||||
{
|
||||
// <html><body contentEditable="true"><p>contentEditable</p></body></html>
|
||||
url: 'data:text/html;charset=utf-8;base64,PGh0bWw%2BPGJvZHkgY29udGVudEVkaXRhYmxlPSJ0cnVlIj48cD5jb250ZW50RWRpdGFibGU8L3A%2BPC9ib2R5PjwvaHRtbD4NCg0KDQo%3D',
|
||||
name: 'contentEditableNavigate',
|
||||
expectedBodyBeforeEdit: '<br><p>contentEditable</p>',
|
||||
expectedBodyAfterEdit: 'EDITED <br><p>contentEditable</p>',
|
||||
expectedBodyAfterSecondEdit: 'EDITED TWICE <br><p>contentEditable</p>',
|
||||
}
|
||||
];
|
||||
|
||||
var gTestNum = -1;
|
||||
var gTest = null;
|
||||
|
||||
window.onload = goNext();
|
||||
|
||||
function goNext() {
|
||||
gTestNum++;
|
||||
if (gTestNum >= gTests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
gTest = gTests[gTestNum];
|
||||
gTest.window = window.open(gTest.url, gTest.name);
|
||||
setTimeout(beginTest, testInterval);
|
||||
}
|
||||
|
||||
function beginTest() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
gTest.window.document.body.focus();
|
||||
|
||||
// WARNING: If the following test fails, give the setTimeout() in the onload()
|
||||
// a bit longer; the doc hasn't had enough time to setup its editor.
|
||||
is(gTest.window.document.body.innerHTML, gTest.expectedBodyBeforeEdit, "Is doc setup yet");
|
||||
|
||||
sendChar('E', gTest.window.document.body);
|
||||
sendChar('D', gTest.window.document.body);
|
||||
sendChar('I', gTest.window.document.body);
|
||||
sendChar('T', gTest.window.document.body);
|
||||
sendChar('E', gTest.window.document.body);
|
||||
sendChar('D', gTest.window.document.body);
|
||||
sendChar(' ', gTest.window.document.body);
|
||||
is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Editing failed.");
|
||||
|
||||
gTest.window.location = 'data:text/html;charset=utf-8,SomeOtherDocument';
|
||||
setTimeout(goBack, testInterval);
|
||||
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
gTest.window.history.back();
|
||||
setTimeout(checkStillEditable, testInterval);
|
||||
}
|
||||
|
||||
function checkStillEditable() {
|
||||
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
|
||||
|
||||
// Check that the contents are correct.
|
||||
is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Edited contents still correct?");
|
||||
|
||||
// Check that we can undo/redo and the contents are correct.
|
||||
gTest.window.document.execCommand("undo", false, null);
|
||||
is(gTest.window.document.body.innerHTML, gTest.expectedBodyBeforeEdit, "Can we undo?");
|
||||
|
||||
gTest.window.document.execCommand("redo", false, null);
|
||||
is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Can we redo?");
|
||||
|
||||
// Check that we can still edit the page.
|
||||
gTest.window.document.body.focus();
|
||||
sendChar('T', gTest.window.document.body);
|
||||
sendChar('W', gTest.window.document.body);
|
||||
sendChar('I', gTest.window.document.body);
|
||||
sendChar('C', gTest.window.document.body);
|
||||
sendChar('E', gTest.window.document.body);
|
||||
sendChar(' ', gTest.window.document.body);
|
||||
is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterSecondEdit, "Can we still edit?");
|
||||
|
||||
gTest.window.close();
|
||||
goNext();
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=386782">Mozilla Bug 386782</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
/** Test for Bug 386782 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -116,5 +116,17 @@ interface nsIEditingSession : nsISupports
|
||||
* were before the last call to disableJSAndPlugins.
|
||||
*/
|
||||
void restoreJSAndPlugins(in nsIDOMWindow aWindow);
|
||||
|
||||
/**
|
||||
* Removes all the editor's controllers/listeners etc and makes the window
|
||||
* uneditable.
|
||||
*/
|
||||
void detachFromWindow(in nsIDOMWindow aWindow);
|
||||
|
||||
/**
|
||||
* Undos detachFromWindow(), reattaches this editing session/editor
|
||||
* to the window.
|
||||
*/
|
||||
void reattachToWindow(in nsIDOMWindow aWindow);
|
||||
};
|
||||
|
||||
|
@ -248,6 +248,9 @@ nsEditingSession::DisableJSAndPlugins(nsIDOMWindow *aWindow)
|
||||
NS_IMETHODIMP
|
||||
nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow)
|
||||
{
|
||||
if (!mDisabledJSAndPlugins)
|
||||
return NS_OK;
|
||||
|
||||
mDisabledJSAndPlugins = PR_FALSE;
|
||||
|
||||
nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
|
||||
@ -410,26 +413,17 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
}
|
||||
|
||||
// make the UI state maintainer
|
||||
nsComposerCommandsUpdater *stateMaintainer;
|
||||
NS_NEWXPCOM(stateMaintainer, nsComposerCommandsUpdater);
|
||||
mStateMaintainer = static_cast<nsISelectionListener*>(stateMaintainer);
|
||||
|
||||
if (!mStateMaintainer) return NS_ERROR_OUT_OF_MEMORY;
|
||||
mStateMaintainer = new nsComposerCommandsUpdater();
|
||||
|
||||
// now init the state maintainer
|
||||
// This allows notification of error state
|
||||
// even if we don't create an editor
|
||||
rv = stateMaintainer->Init(aWindow);
|
||||
rv = mStateMaintainer->Init(aWindow);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mEditorStatus != eEditorCreationInProgress)
|
||||
{
|
||||
// We had an earlier error -- force notification of document creation
|
||||
nsCOMPtr<nsIDocumentStateListener> docListener =
|
||||
do_QueryInterface(mStateMaintainer);
|
||||
if (docListener)
|
||||
docListener->NotifyDocumentCreated();
|
||||
|
||||
mStateMaintainer->NotifyDocumentCreated();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
@ -484,8 +478,7 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
|
||||
// Set up as a doc state listener
|
||||
// Important! We must have this to broadcast the "obs_documentCreated" message
|
||||
rv = editor->AddDocumentStateListener(
|
||||
static_cast<nsIDocumentStateListener*>(stateMaintainer));
|
||||
rv = editor->AddDocumentStateListener(mStateMaintainer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// XXXbz we really shouldn't need a presShell here!
|
||||
@ -504,15 +497,14 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
|
||||
if (!selPriv) return NS_ERROR_FAILURE;
|
||||
|
||||
rv = selPriv->AddSelectionListener(stateMaintainer);
|
||||
rv = selPriv->AddSelectionListener(mStateMaintainer);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// and as a transaction listener
|
||||
nsCOMPtr<nsITransactionManager> txnMgr;
|
||||
editor->GetTransactionManager(getter_AddRefs(txnMgr));
|
||||
if (txnMgr)
|
||||
txnMgr->AddListener(static_cast<nsITransactionListener*>
|
||||
(stateMaintainer));
|
||||
txnMgr->AddListener(mStateMaintainer);
|
||||
|
||||
// Set context on all controllers to be the editor
|
||||
rv = SetEditorOnControllers(aWindow, editor);
|
||||
@ -521,11 +513,37 @@ nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
// Everything went fine!
|
||||
mEditorStatus = eEditorOK;
|
||||
|
||||
|
||||
// This will trigger documentCreation notification
|
||||
return editor->PostCreate();
|
||||
}
|
||||
|
||||
// Removes all listeners and controllers from aWindow and aEditor.
|
||||
void
|
||||
nsEditingSession::RemoveListenersAndControllers(nsIDOMWindow *aWindow,
|
||||
nsIEditor *aEditor)
|
||||
{
|
||||
if (!mStateMaintainer || !aEditor)
|
||||
return;
|
||||
|
||||
// Remove all the listeners
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
aEditor->GetSelection(getter_AddRefs(selection));
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
|
||||
if (selPriv)
|
||||
selPriv->RemoveSelectionListener(mStateMaintainer);
|
||||
|
||||
aEditor->RemoveDocumentStateListener(mStateMaintainer);
|
||||
|
||||
nsCOMPtr<nsITransactionManager> txnMgr;
|
||||
aEditor->GetTransactionManager(getter_AddRefs(txnMgr));
|
||||
if (txnMgr)
|
||||
txnMgr->RemoveListener(mStateMaintainer);
|
||||
|
||||
// Remove editor controllers from the window now that we're not
|
||||
// editing in that window any more.
|
||||
RemoveEditorControllers(aWindow);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
|
||||
TearDownEditorOnWindow
|
||||
@ -538,6 +556,9 @@ nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
if (!mDoneSetup)
|
||||
return NS_OK;
|
||||
|
||||
if (!aWindow)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Kill any existing reload timer
|
||||
@ -547,8 +568,6 @@ nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
mLoadBlankDocTimer = nsnull;
|
||||
}
|
||||
|
||||
nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
|
||||
|
||||
mDoneSetup = PR_FALSE;
|
||||
|
||||
// Check if we're turning off editing (from contentEditable or designMode).
|
||||
@ -556,14 +575,8 @@ nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
aWindow->GetDocument(getter_AddRefs(domDoc));
|
||||
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(domDoc);
|
||||
PRBool stopEditing = htmlDoc && htmlDoc->IsEditingOn();
|
||||
if (stopEditing) {
|
||||
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
|
||||
if (webProgress) {
|
||||
webProgress->RemoveProgressListener(this);
|
||||
|
||||
mProgressListenerRegistered = PR_FALSE;
|
||||
}
|
||||
}
|
||||
if (stopEditing)
|
||||
RemoveWebProgressListener(aWindow);
|
||||
|
||||
nsCOMPtr<nsIEditorDocShell> editorDocShell;
|
||||
rv = GetEditorDocShellFromWindow(aWindow, getter_AddRefs(editorDocShell));
|
||||
@ -576,107 +589,27 @@ nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow)
|
||||
if (stopEditing)
|
||||
htmlDoc->TearingDownEditor(editor);
|
||||
|
||||
// null out the editor on the controllers first to prevent their weak
|
||||
// references from pointing to a destroyed editor
|
||||
if (mStateMaintainer && editor)
|
||||
{
|
||||
// null out the editor on the controllers
|
||||
// Null out the editor on the controllers first to prevent their weak
|
||||
// references from pointing to a destroyed editor.
|
||||
SetEditorOnControllers(aWindow, nsnull);
|
||||
}
|
||||
|
||||
// null out the editor on the docShell to trigger PreDestroy which
|
||||
// needs to happen before document state listeners are removed below
|
||||
// Null out the editor on the docShell to trigger PreDestroy which
|
||||
// needs to happen before document state listeners are removed below.
|
||||
editorDocShell->SetEditor(nsnull);
|
||||
|
||||
if (mStateMaintainer)
|
||||
RemoveListenersAndControllers(aWindow, editor);
|
||||
|
||||
if (stopEditing)
|
||||
{
|
||||
if (editor)
|
||||
// Make things the way they were before we started editing.
|
||||
RestoreJSAndPlugins(aWindow);
|
||||
RestoreAnimationMode(aWindow);
|
||||
|
||||
if (mMakeWholeDocumentEditable)
|
||||
{
|
||||
// If we had an editor -- we are loading a new URL into existing window
|
||||
|
||||
// Remove all the listeners
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
editor->GetSelection(getter_AddRefs(selection));
|
||||
nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection);
|
||||
if (selPriv)
|
||||
{
|
||||
nsCOMPtr<nsISelectionListener> listener =
|
||||
do_QueryInterface(mStateMaintainer);
|
||||
selPriv->RemoveSelectionListener(listener);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocumentStateListener> docListener =
|
||||
do_QueryInterface(mStateMaintainer);
|
||||
editor->RemoveDocumentStateListener(docListener);
|
||||
|
||||
nsCOMPtr<nsITransactionManager> txnMgr;
|
||||
editor->GetTransactionManager(getter_AddRefs(txnMgr));
|
||||
if (txnMgr)
|
||||
{
|
||||
nsCOMPtr<nsITransactionListener> transactionListener =
|
||||
do_QueryInterface(mStateMaintainer);
|
||||
txnMgr->RemoveListener(transactionListener);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove editor controllers from the window now that we're not
|
||||
// editing in that window any more.
|
||||
|
||||
nsCOMPtr<nsIDOMWindowInternal> domWindowInt(do_QueryInterface(aWindow));
|
||||
|
||||
nsCOMPtr<nsIControllers> controllers;
|
||||
domWindowInt->GetControllers(getter_AddRefs(controllers));
|
||||
|
||||
if (controllers) {
|
||||
nsCOMPtr<nsIController> controller;
|
||||
|
||||
if (mBaseCommandControllerId) {
|
||||
controllers->GetControllerById(mBaseCommandControllerId,
|
||||
getter_AddRefs(controller));
|
||||
|
||||
if (controller) {
|
||||
controllers->RemoveController(controller);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDocStateControllerId) {
|
||||
controllers->GetControllerById(mDocStateControllerId,
|
||||
getter_AddRefs(controller));
|
||||
|
||||
if (controller) {
|
||||
controllers->RemoveController(controller);
|
||||
}
|
||||
}
|
||||
|
||||
if (mHTMLCommandControllerId) {
|
||||
controllers->GetControllerById(mHTMLCommandControllerId,
|
||||
getter_AddRefs(controller));
|
||||
|
||||
if (controller) {
|
||||
controllers->RemoveController(controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear IDs to trigger creation of new controllers
|
||||
mBaseCommandControllerId = 0;
|
||||
mDocStateControllerId = 0;
|
||||
mHTMLCommandControllerId = 0;
|
||||
}
|
||||
|
||||
if (stopEditing) {
|
||||
if (mDisabledJSAndPlugins) {
|
||||
// Make things the way they were before we started editing.
|
||||
RestoreJSAndPlugins(aWindow);
|
||||
}
|
||||
|
||||
if (!mInteractive) {
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
|
||||
if (utils)
|
||||
utils->SetImageAnimationMode(mImageAnimationMode);
|
||||
}
|
||||
|
||||
if (mMakeWholeDocumentEditable) {
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -1020,7 +953,9 @@ nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress,
|
||||
aWebProgress->GetDOMWindow(getter_AddRefs(domWindow));
|
||||
if (domWindow)
|
||||
{
|
||||
TearDownEditorOnWindow(domWindow);
|
||||
nsIDocShell *docShell = GetDocShellFromWindow(domWindow);
|
||||
if (!docShell) return NS_ERROR_FAILURE;
|
||||
docShell->DetachEditorFromWindow();
|
||||
}
|
||||
|
||||
if (aIsToBeMadeEditable)
|
||||
@ -1387,3 +1322,179 @@ nsEditingSession::SetContextOnControllerById(nsIControllers* aControllers,
|
||||
|
||||
return editorController->SetCommandContext(aContext);
|
||||
}
|
||||
|
||||
void
|
||||
nsEditingSession::RemoveEditorControllers(nsIDOMWindow *aWindow)
|
||||
{
|
||||
// Remove editor controllers from the aWindow, call when we're
|
||||
// tearing down/detaching editor.
|
||||
nsCOMPtr<nsIDOMWindowInternal> domWindowInt(do_QueryInterface(aWindow));
|
||||
|
||||
nsCOMPtr<nsIControllers> controllers;
|
||||
if (domWindowInt)
|
||||
domWindowInt->GetControllers(getter_AddRefs(controllers));
|
||||
|
||||
if (controllers)
|
||||
{
|
||||
nsCOMPtr<nsIController> controller;
|
||||
if (mBaseCommandControllerId)
|
||||
{
|
||||
controllers->GetControllerById(mBaseCommandControllerId,
|
||||
getter_AddRefs(controller));
|
||||
if (controller)
|
||||
controllers->RemoveController(controller);
|
||||
}
|
||||
|
||||
if (mDocStateControllerId)
|
||||
{
|
||||
controllers->GetControllerById(mDocStateControllerId,
|
||||
getter_AddRefs(controller));
|
||||
if (controller)
|
||||
controllers->RemoveController(controller);
|
||||
}
|
||||
|
||||
if (mHTMLCommandControllerId)
|
||||
{
|
||||
controllers->GetControllerById(mHTMLCommandControllerId,
|
||||
getter_AddRefs(controller));
|
||||
if (controller)
|
||||
controllers->RemoveController(controller);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear IDs to trigger creation of new controllers.
|
||||
mBaseCommandControllerId = 0;
|
||||
mDocStateControllerId = 0;
|
||||
mHTMLCommandControllerId = 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsEditingSession::RemoveWebProgressListener(nsIDOMWindow *aWindow)
|
||||
{
|
||||
nsIDocShell *docShell = GetDocShellFromWindow(aWindow);
|
||||
nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
|
||||
if (webProgress)
|
||||
{
|
||||
webProgress->RemoveProgressListener(this);
|
||||
mProgressListenerRegistered = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsEditingSession::RestoreAnimationMode(nsIDOMWindow *aWindow)
|
||||
{
|
||||
if (!mInteractive)
|
||||
{
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
|
||||
if (utils)
|
||||
utils->SetImageAnimationMode(mImageAnimationMode);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditingSession::DetachFromWindow(nsIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(mEditorFlags != 0, "mEditorFlags should not be 0");
|
||||
NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist.");
|
||||
|
||||
// Kill any existing reload timer
|
||||
if (mLoadBlankDocTimer)
|
||||
{
|
||||
mLoadBlankDocTimer->Cancel();
|
||||
mLoadBlankDocTimer = nsnull;
|
||||
}
|
||||
|
||||
// Remove controllers, webprogress listener, and otherwise
|
||||
// make things the way they were before we started editing.
|
||||
RemoveEditorControllers(aWindow);
|
||||
RemoveWebProgressListener(aWindow);
|
||||
RestoreJSAndPlugins(aWindow);
|
||||
RestoreAnimationMode(aWindow);
|
||||
|
||||
// Kill our weak reference to our original window, in case
|
||||
// it changes on restore, or otherwise dies.
|
||||
mWindowToBeEdited = nsnull;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsEditingSession::ReattachToWindow(nsIDOMWindow* aWindow)
|
||||
{
|
||||
NS_ASSERTION(mEditorFlags != 0, "mEditorFlags should still be valid...");
|
||||
NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist.");
|
||||
|
||||
// Imitate nsEditorDocShell::MakeEditable() to reattach the
|
||||
// old editor ot the window.
|
||||
nsresult rv;
|
||||
|
||||
mWindowToBeEdited = do_GetWeakReference(aWindow);
|
||||
|
||||
// Disable plugins.
|
||||
if (!mInteractive)
|
||||
{
|
||||
rv = DisableJSAndPlugins(aWindow);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Tells embedder that startup is in progress.
|
||||
mEditorStatus = eEditorCreationInProgress;
|
||||
|
||||
// Adds back web progress listener.
|
||||
rv = PrepareForEditing(aWindow);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Setup the command controllers again.
|
||||
rv = SetupEditorCommandController("@mozilla.org/editor/editorcontroller;1",
|
||||
aWindow,
|
||||
static_cast<nsIEditingSession*>(this),
|
||||
&mBaseCommandControllerId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1",
|
||||
aWindow,
|
||||
static_cast<nsIEditingSession*>(this),
|
||||
&mDocStateControllerId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mStateMaintainer)
|
||||
mStateMaintainer->Init(aWindow);
|
||||
|
||||
// Get editor
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
rv = GetEditorForWindow(aWindow, getter_AddRefs(editor));
|
||||
if (!editor)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mInteractive)
|
||||
{
|
||||
// Disable animation of images in this document:
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow));
|
||||
if (!utils) return NS_ERROR_FAILURE;
|
||||
|
||||
rv = utils->GetImageAnimationMode(&mImageAnimationMode);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
utils->SetImageAnimationMode(imgIContainer::kDontAnimMode);
|
||||
}
|
||||
|
||||
// The third controller takes an nsIEditor as the context
|
||||
rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1",
|
||||
aWindow, editor,
|
||||
&mHTMLCommandControllerId);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Set context on all controllers to be the editor
|
||||
rv = SetEditorOnControllers(aWindow, editor);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
PRBool isEditable;
|
||||
rv = WindowIsEditable(aWindow, &isEditable);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(isEditable, "Window is not editable after reattaching editor.");
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
#endif
|
||||
|
||||
#include "nsITimer.h"
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#ifndef __gen_nsIWebProgressListener_h__
|
||||
#include "nsIWebProgressListener.h"
|
||||
@ -119,6 +120,12 @@ protected:
|
||||
|
||||
PRBool IsProgressForTargetDocument(nsIWebProgress *aWebProgress);
|
||||
|
||||
void RemoveEditorControllers(nsIDOMWindow *aWindow);
|
||||
void RemoveWebProgressListener(nsIDOMWindow *aWindow);
|
||||
void RestoreAnimationMode(nsIDOMWindow *aWindow);
|
||||
void RemoveListenersAndControllers(nsIDOMWindow *aWindow,
|
||||
nsIEditor *aEditor);
|
||||
|
||||
protected:
|
||||
|
||||
PRPackedBool mDoneSetup; // have we prepared for editing yet?
|
||||
@ -149,7 +156,7 @@ protected:
|
||||
|
||||
// THE REMAINING MEMBER VARIABLES WILL BECOME A SET WHEN WE EDIT
|
||||
// MORE THAN ONE EDITOR PER EDITING SESSION
|
||||
nsCOMPtr<nsISupports> mStateMaintainer; // we hold the owning ref to this
|
||||
nsRefPtr<nsComposerCommandsUpdater> mStateMaintainer;
|
||||
|
||||
nsWeakPtr mWindowToBeEdited;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user