Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 sw=2 et tw=78: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include <string.h> // for nullptr, strcmp |
michael@0 | 8 | |
michael@0 | 9 | #include "imgIContainer.h" // for imgIContainer, etc |
michael@0 | 10 | #include "mozFlushType.h" // for mozFlushType::Flush_Frames |
michael@0 | 11 | #include "mozilla/mozalloc.h" // for operator new |
michael@0 | 12 | #include "nsAString.h" |
michael@0 | 13 | #include "nsComponentManagerUtils.h" // for do_CreateInstance |
michael@0 | 14 | #include "nsComposerCommandsUpdater.h" // for nsComposerCommandsUpdater |
michael@0 | 15 | #include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc |
michael@0 | 16 | #include "nsEditingSession.h" |
michael@0 | 17 | #include "nsError.h" // for NS_ERROR_FAILURE, NS_OK, etc |
michael@0 | 18 | #include "nsIChannel.h" // for nsIChannel |
michael@0 | 19 | #include "nsICommandManager.h" // for nsICommandManager |
michael@0 | 20 | #include "nsIContentViewer.h" // for nsIContentViewer |
michael@0 | 21 | #include "nsIController.h" // for nsIController |
michael@0 | 22 | #include "nsIControllerContext.h" // for nsIControllerContext |
michael@0 | 23 | #include "nsIControllers.h" // for nsIControllers |
michael@0 | 24 | #include "nsID.h" // for NS_GET_IID, etc |
michael@0 | 25 | #include "nsIDOMDocument.h" // for nsIDOMDocument |
michael@0 | 26 | #include "nsIDOMHTMLDocument.h" // for nsIDOMHTMLDocument |
michael@0 | 27 | #include "nsIDOMWindow.h" // for nsIDOMWindow |
michael@0 | 28 | #include "nsIDOMWindowUtils.h" // for nsIDOMWindowUtils |
michael@0 | 29 | #include "nsIDocShell.h" // for nsIDocShell |
michael@0 | 30 | #include "nsIDocument.h" // for nsIDocument |
michael@0 | 31 | #include "nsIDocumentStateListener.h" |
michael@0 | 32 | #include "nsIEditor.h" // for nsIEditor |
michael@0 | 33 | #include "nsIHTMLDocument.h" // for nsIHTMLDocument, etc |
michael@0 | 34 | #include "nsIInterfaceRequestorUtils.h" // for do_GetInterface |
michael@0 | 35 | #include "nsIPlaintextEditor.h" // for nsIPlaintextEditor, etc |
michael@0 | 36 | #include "nsIRefreshURI.h" // for nsIRefreshURI |
michael@0 | 37 | #include "nsIRequest.h" // for nsIRequest |
michael@0 | 38 | #include "nsISelection.h" // for nsISelection |
michael@0 | 39 | #include "nsISelectionPrivate.h" // for nsISelectionPrivate |
michael@0 | 40 | #include "nsITimer.h" // for nsITimer, etc |
michael@0 | 41 | #include "nsITransactionManager.h" // for nsITransactionManager |
michael@0 | 42 | #include "nsIWeakReference.h" // for nsISupportsWeakReference, etc |
michael@0 | 43 | #include "nsIWebNavigation.h" // for nsIWebNavigation |
michael@0 | 44 | #include "nsIWebProgress.h" // for nsIWebProgress, etc |
michael@0 | 45 | #include "nsLiteralString.h" // for NS_LITERAL_STRING |
michael@0 | 46 | #include "nsPICommandUpdater.h" // for nsPICommandUpdater |
michael@0 | 47 | #include "nsPIDOMWindow.h" // for nsPIDOMWindow |
michael@0 | 48 | #include "nsReadableUtils.h" // for AppendUTF16toUTF8 |
michael@0 | 49 | #include "nsStringFwd.h" // for nsAFlatString |
michael@0 | 50 | |
michael@0 | 51 | class nsISupports; |
michael@0 | 52 | class nsIURI; |
michael@0 | 53 | |
michael@0 | 54 | /*--------------------------------------------------------------------------- |
michael@0 | 55 | |
michael@0 | 56 | nsEditingSession |
michael@0 | 57 | |
michael@0 | 58 | ----------------------------------------------------------------------------*/ |
michael@0 | 59 | nsEditingSession::nsEditingSession() |
michael@0 | 60 | : mDoneSetup(false) |
michael@0 | 61 | , mCanCreateEditor(false) |
michael@0 | 62 | , mInteractive(false) |
michael@0 | 63 | , mMakeWholeDocumentEditable(true) |
michael@0 | 64 | , mDisabledJSAndPlugins(false) |
michael@0 | 65 | , mScriptsEnabled(true) |
michael@0 | 66 | , mPluginsEnabled(true) |
michael@0 | 67 | , mProgressListenerRegistered(false) |
michael@0 | 68 | , mImageAnimationMode(0) |
michael@0 | 69 | , mEditorFlags(0) |
michael@0 | 70 | , mEditorStatus(eEditorOK) |
michael@0 | 71 | , mBaseCommandControllerId(0) |
michael@0 | 72 | , mDocStateControllerId(0) |
michael@0 | 73 | , mHTMLCommandControllerId(0) |
michael@0 | 74 | { |
michael@0 | 75 | } |
michael@0 | 76 | |
michael@0 | 77 | /*--------------------------------------------------------------------------- |
michael@0 | 78 | |
michael@0 | 79 | ~nsEditingSession |
michael@0 | 80 | |
michael@0 | 81 | ----------------------------------------------------------------------------*/ |
michael@0 | 82 | nsEditingSession::~nsEditingSession() |
michael@0 | 83 | { |
michael@0 | 84 | // Must cancel previous timer? |
michael@0 | 85 | if (mLoadBlankDocTimer) |
michael@0 | 86 | mLoadBlankDocTimer->Cancel(); |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | NS_IMPL_ISUPPORTS(nsEditingSession, nsIEditingSession, nsIWebProgressListener, |
michael@0 | 90 | nsISupportsWeakReference) |
michael@0 | 91 | |
michael@0 | 92 | /*--------------------------------------------------------------------------- |
michael@0 | 93 | |
michael@0 | 94 | MakeWindowEditable |
michael@0 | 95 | |
michael@0 | 96 | aEditorType string, "html" "htmlsimple" "text" "textsimple" |
michael@0 | 97 | void makeWindowEditable(in nsIDOMWindow aWindow, in string aEditorType, |
michael@0 | 98 | in boolean aDoAfterUriLoad, |
michael@0 | 99 | in boolean aMakeWholeDocumentEditable, |
michael@0 | 100 | in boolean aInteractive); |
michael@0 | 101 | ----------------------------------------------------------------------------*/ |
michael@0 | 102 | #define DEFAULT_EDITOR_TYPE "html" |
michael@0 | 103 | |
michael@0 | 104 | NS_IMETHODIMP |
michael@0 | 105 | nsEditingSession::MakeWindowEditable(nsIDOMWindow *aWindow, |
michael@0 | 106 | const char *aEditorType, |
michael@0 | 107 | bool aDoAfterUriLoad, |
michael@0 | 108 | bool aMakeWholeDocumentEditable, |
michael@0 | 109 | bool aInteractive) |
michael@0 | 110 | { |
michael@0 | 111 | mEditorType.Truncate(); |
michael@0 | 112 | mEditorFlags = 0; |
michael@0 | 113 | |
michael@0 | 114 | // disable plugins |
michael@0 | 115 | nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 116 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 117 | |
michael@0 | 118 | mDocShell = do_GetWeakReference(docShell); |
michael@0 | 119 | mInteractive = aInteractive; |
michael@0 | 120 | mMakeWholeDocumentEditable = aMakeWholeDocumentEditable; |
michael@0 | 121 | |
michael@0 | 122 | nsresult rv; |
michael@0 | 123 | if (!mInteractive) { |
michael@0 | 124 | rv = DisableJSAndPlugins(aWindow); |
michael@0 | 125 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 126 | } |
michael@0 | 127 | |
michael@0 | 128 | // Always remove existing editor |
michael@0 | 129 | TearDownEditorOnWindow(aWindow); |
michael@0 | 130 | |
michael@0 | 131 | // Tells embedder that startup is in progress |
michael@0 | 132 | mEditorStatus = eEditorCreationInProgress; |
michael@0 | 133 | |
michael@0 | 134 | //temporary to set editor type here. we will need different classes soon. |
michael@0 | 135 | if (!aEditorType) |
michael@0 | 136 | aEditorType = DEFAULT_EDITOR_TYPE; |
michael@0 | 137 | mEditorType = aEditorType; |
michael@0 | 138 | |
michael@0 | 139 | // if all this does is setup listeners and I don't need listeners, |
michael@0 | 140 | // can't this step be ignored?? (based on aDoAfterURILoad) |
michael@0 | 141 | rv = PrepareForEditing(aWindow); |
michael@0 | 142 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 143 | |
michael@0 | 144 | // set the flag on the docShell to say that it's editable |
michael@0 | 145 | rv = docShell->MakeEditable(aDoAfterUriLoad); |
michael@0 | 146 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 147 | |
michael@0 | 148 | // Setup commands common to plaintext and html editors, |
michael@0 | 149 | // including the document creation observers |
michael@0 | 150 | // the first is an editing controller |
michael@0 | 151 | rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1", |
michael@0 | 152 | aWindow, |
michael@0 | 153 | static_cast<nsIEditingSession*>(this), |
michael@0 | 154 | &mBaseCommandControllerId); |
michael@0 | 155 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 156 | |
michael@0 | 157 | // The second is a controller to monitor doc state, |
michael@0 | 158 | // such as creation and "dirty flag" |
michael@0 | 159 | rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1", |
michael@0 | 160 | aWindow, |
michael@0 | 161 | static_cast<nsIEditingSession*>(this), |
michael@0 | 162 | &mDocStateControllerId); |
michael@0 | 163 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 164 | |
michael@0 | 165 | // aDoAfterUriLoad can be false only when making an existing window editable |
michael@0 | 166 | if (!aDoAfterUriLoad) |
michael@0 | 167 | { |
michael@0 | 168 | rv = SetupEditorOnWindow(aWindow); |
michael@0 | 169 | |
michael@0 | 170 | // mEditorStatus is set to the error reason |
michael@0 | 171 | // Since this is used only when editing an existing page, |
michael@0 | 172 | // it IS ok to destroy current editor |
michael@0 | 173 | if (NS_FAILED(rv)) |
michael@0 | 174 | TearDownEditorOnWindow(aWindow); |
michael@0 | 175 | } |
michael@0 | 176 | return rv; |
michael@0 | 177 | } |
michael@0 | 178 | |
michael@0 | 179 | NS_IMETHODIMP |
michael@0 | 180 | nsEditingSession::DisableJSAndPlugins(nsIDOMWindow *aWindow) |
michael@0 | 181 | { |
michael@0 | 182 | nsIDocShell *docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 183 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 184 | |
michael@0 | 185 | bool tmp; |
michael@0 | 186 | nsresult rv = docShell->GetAllowJavascript(&tmp); |
michael@0 | 187 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 188 | |
michael@0 | 189 | mScriptsEnabled = tmp; |
michael@0 | 190 | |
michael@0 | 191 | rv = docShell->SetAllowJavascript(false); |
michael@0 | 192 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 193 | |
michael@0 | 194 | // Disable plugins in this document: |
michael@0 | 195 | mPluginsEnabled = docShell->PluginsAllowedInCurrentDoc(); |
michael@0 | 196 | |
michael@0 | 197 | rv = docShell->SetAllowPlugins(false); |
michael@0 | 198 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 199 | |
michael@0 | 200 | mDisabledJSAndPlugins = true; |
michael@0 | 201 | |
michael@0 | 202 | return NS_OK; |
michael@0 | 203 | } |
michael@0 | 204 | |
michael@0 | 205 | NS_IMETHODIMP |
michael@0 | 206 | nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow) |
michael@0 | 207 | { |
michael@0 | 208 | NS_ENSURE_TRUE(mDisabledJSAndPlugins, NS_OK); |
michael@0 | 209 | |
michael@0 | 210 | mDisabledJSAndPlugins = false; |
michael@0 | 211 | |
michael@0 | 212 | nsIDocShell *docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 213 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 214 | |
michael@0 | 215 | nsresult rv = docShell->SetAllowJavascript(mScriptsEnabled); |
michael@0 | 216 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 217 | |
michael@0 | 218 | // Disable plugins in this document: |
michael@0 | 219 | return docShell->SetAllowPlugins(mPluginsEnabled); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | NS_IMETHODIMP |
michael@0 | 223 | nsEditingSession::GetJsAndPluginsDisabled(bool *aResult) |
michael@0 | 224 | { |
michael@0 | 225 | NS_ENSURE_ARG_POINTER(aResult); |
michael@0 | 226 | *aResult = mDisabledJSAndPlugins; |
michael@0 | 227 | return NS_OK; |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | /*--------------------------------------------------------------------------- |
michael@0 | 231 | |
michael@0 | 232 | WindowIsEditable |
michael@0 | 233 | |
michael@0 | 234 | boolean windowIsEditable (in nsIDOMWindow aWindow); |
michael@0 | 235 | ----------------------------------------------------------------------------*/ |
michael@0 | 236 | NS_IMETHODIMP |
michael@0 | 237 | nsEditingSession::WindowIsEditable(nsIDOMWindow *aWindow, bool *outIsEditable) |
michael@0 | 238 | { |
michael@0 | 239 | nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 240 | NS_ENSURE_STATE(docShell); |
michael@0 | 241 | |
michael@0 | 242 | return docShell->GetEditable(outIsEditable); |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | |
michael@0 | 246 | // These are MIME types that are automatically parsed as "text/plain" |
michael@0 | 247 | // and thus we can edit them as plaintext |
michael@0 | 248 | // Note: in older versions, we attempted to convert the mimetype of |
michael@0 | 249 | // the network channel for these and "text/xml" to "text/plain", |
michael@0 | 250 | // but further investigation reveals that strategy doesn't work |
michael@0 | 251 | const char* const gSupportedTextTypes[] = { |
michael@0 | 252 | "text/plain", |
michael@0 | 253 | "text/css", |
michael@0 | 254 | "text/rdf", |
michael@0 | 255 | "text/xsl", |
michael@0 | 256 | "text/javascript", // obsolete type |
michael@0 | 257 | "text/ecmascript", // obsolete type |
michael@0 | 258 | "application/javascript", |
michael@0 | 259 | "application/ecmascript", |
michael@0 | 260 | "application/x-javascript", // obsolete type |
michael@0 | 261 | "text/xul", // obsolete type |
michael@0 | 262 | "application/vnd.mozilla.xul+xml", |
michael@0 | 263 | nullptr // IMPORTANT! Null must be at end |
michael@0 | 264 | }; |
michael@0 | 265 | |
michael@0 | 266 | bool |
michael@0 | 267 | IsSupportedTextType(const char* aMIMEType) |
michael@0 | 268 | { |
michael@0 | 269 | NS_ENSURE_TRUE(aMIMEType, false); |
michael@0 | 270 | |
michael@0 | 271 | int32_t i = 0; |
michael@0 | 272 | while (gSupportedTextTypes[i]) |
michael@0 | 273 | { |
michael@0 | 274 | if (strcmp(gSupportedTextTypes[i], aMIMEType) == 0) |
michael@0 | 275 | { |
michael@0 | 276 | return true; |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | i ++; |
michael@0 | 280 | } |
michael@0 | 281 | |
michael@0 | 282 | return false; |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | /*--------------------------------------------------------------------------- |
michael@0 | 286 | |
michael@0 | 287 | SetupEditorOnWindow |
michael@0 | 288 | |
michael@0 | 289 | nsIEditor setupEditorOnWindow (in nsIDOMWindow aWindow); |
michael@0 | 290 | ----------------------------------------------------------------------------*/ |
michael@0 | 291 | NS_IMETHODIMP |
michael@0 | 292 | nsEditingSession::SetupEditorOnWindow(nsIDOMWindow *aWindow) |
michael@0 | 293 | { |
michael@0 | 294 | mDoneSetup = true; |
michael@0 | 295 | |
michael@0 | 296 | nsresult rv; |
michael@0 | 297 | |
michael@0 | 298 | //MIME CHECKING |
michael@0 | 299 | //must get the content type |
michael@0 | 300 | // Note: the doc gets this from the network channel during StartPageLoad, |
michael@0 | 301 | // so we don't have to get it from there ourselves |
michael@0 | 302 | nsCOMPtr<nsIDOMDocument> doc; |
michael@0 | 303 | nsAutoCString mimeCType; |
michael@0 | 304 | |
michael@0 | 305 | //then lets check the mime type |
michael@0 | 306 | if (NS_SUCCEEDED(aWindow->GetDocument(getter_AddRefs(doc))) && doc) |
michael@0 | 307 | { |
michael@0 | 308 | nsAutoString mimeType; |
michael@0 | 309 | if (NS_SUCCEEDED(doc->GetContentType(mimeType))) |
michael@0 | 310 | AppendUTF16toUTF8(mimeType, mimeCType); |
michael@0 | 311 | |
michael@0 | 312 | if (IsSupportedTextType(mimeCType.get())) |
michael@0 | 313 | { |
michael@0 | 314 | mEditorType.AssignLiteral("text"); |
michael@0 | 315 | mimeCType = "text/plain"; |
michael@0 | 316 | } |
michael@0 | 317 | else if (!mimeCType.EqualsLiteral("text/html") && |
michael@0 | 318 | !mimeCType.EqualsLiteral("application/xhtml+xml")) |
michael@0 | 319 | { |
michael@0 | 320 | // Neither an acceptable text or html type. |
michael@0 | 321 | mEditorStatus = eEditorErrorCantEditMimeType; |
michael@0 | 322 | |
michael@0 | 323 | // Turn editor into HTML -- we will load blank page later |
michael@0 | 324 | mEditorType.AssignLiteral("html"); |
michael@0 | 325 | mimeCType.AssignLiteral("text/html"); |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | // Flush out frame construction to make sure that the subframe's |
michael@0 | 329 | // presshell is set up if it needs to be. |
michael@0 | 330 | nsCOMPtr<nsIDocument> document = do_QueryInterface(doc); |
michael@0 | 331 | if (document) { |
michael@0 | 332 | document->FlushPendingNotifications(Flush_Frames); |
michael@0 | 333 | if (mMakeWholeDocumentEditable) { |
michael@0 | 334 | document->SetEditableFlag(true); |
michael@0 | 335 | nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(document); |
michael@0 | 336 | if (htmlDocument) { |
michael@0 | 337 | // Enable usage of the execCommand API |
michael@0 | 338 | htmlDocument->SetEditingState(nsIHTMLDocument::eDesignMode); |
michael@0 | 339 | } |
michael@0 | 340 | } |
michael@0 | 341 | } |
michael@0 | 342 | } |
michael@0 | 343 | bool needHTMLController = false; |
michael@0 | 344 | |
michael@0 | 345 | const char *classString = "@mozilla.org/editor/htmleditor;1"; |
michael@0 | 346 | if (mEditorType.EqualsLiteral("textmail")) |
michael@0 | 347 | { |
michael@0 | 348 | mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | |
michael@0 | 349 | nsIPlaintextEditor::eEditorEnableWrapHackMask | |
michael@0 | 350 | nsIPlaintextEditor::eEditorMailMask; |
michael@0 | 351 | } |
michael@0 | 352 | else if (mEditorType.EqualsLiteral("text")) |
michael@0 | 353 | { |
michael@0 | 354 | mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | |
michael@0 | 355 | nsIPlaintextEditor::eEditorEnableWrapHackMask; |
michael@0 | 356 | } |
michael@0 | 357 | else if (mEditorType.EqualsLiteral("htmlmail")) |
michael@0 | 358 | { |
michael@0 | 359 | if (mimeCType.EqualsLiteral("text/html")) |
michael@0 | 360 | { |
michael@0 | 361 | needHTMLController = true; |
michael@0 | 362 | mEditorFlags = nsIPlaintextEditor::eEditorMailMask; |
michael@0 | 363 | } |
michael@0 | 364 | else //set the flags back to textplain. |
michael@0 | 365 | mEditorFlags = nsIPlaintextEditor::eEditorPlaintextMask | |
michael@0 | 366 | nsIPlaintextEditor::eEditorEnableWrapHackMask; |
michael@0 | 367 | } |
michael@0 | 368 | else // Defaulted to html |
michael@0 | 369 | { |
michael@0 | 370 | needHTMLController = true; |
michael@0 | 371 | } |
michael@0 | 372 | |
michael@0 | 373 | if (mInteractive) { |
michael@0 | 374 | mEditorFlags |= nsIPlaintextEditor::eEditorAllowInteraction; |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | // make the UI state maintainer |
michael@0 | 378 | mStateMaintainer = new nsComposerCommandsUpdater(); |
michael@0 | 379 | |
michael@0 | 380 | // now init the state maintainer |
michael@0 | 381 | // This allows notification of error state |
michael@0 | 382 | // even if we don't create an editor |
michael@0 | 383 | rv = mStateMaintainer->Init(aWindow); |
michael@0 | 384 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 385 | |
michael@0 | 386 | if (mEditorStatus != eEditorCreationInProgress) |
michael@0 | 387 | { |
michael@0 | 388 | mStateMaintainer->NotifyDocumentCreated(); |
michael@0 | 389 | return NS_ERROR_FAILURE; |
michael@0 | 390 | } |
michael@0 | 391 | |
michael@0 | 392 | // Create editor and do other things |
michael@0 | 393 | // only if we haven't found some error above, |
michael@0 | 394 | nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 395 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 396 | |
michael@0 | 397 | if (!mInteractive) { |
michael@0 | 398 | // Disable animation of images in this document: |
michael@0 | 399 | nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow)); |
michael@0 | 400 | NS_ENSURE_TRUE(utils, NS_ERROR_FAILURE); |
michael@0 | 401 | |
michael@0 | 402 | rv = utils->GetImageAnimationMode(&mImageAnimationMode); |
michael@0 | 403 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 404 | utils->SetImageAnimationMode(imgIContainer::kDontAnimMode); |
michael@0 | 405 | } |
michael@0 | 406 | |
michael@0 | 407 | // create and set editor |
michael@0 | 408 | // Try to reuse an existing editor |
michael@0 | 409 | nsCOMPtr<nsIEditor> editor = do_QueryReferent(mExistingEditor); |
michael@0 | 410 | if (editor) { |
michael@0 | 411 | editor->PreDestroy(false); |
michael@0 | 412 | } else { |
michael@0 | 413 | editor = do_CreateInstance(classString, &rv); |
michael@0 | 414 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 415 | mExistingEditor = do_GetWeakReference(editor); |
michael@0 | 416 | } |
michael@0 | 417 | // set the editor on the docShell. The docShell now owns it. |
michael@0 | 418 | rv = docShell->SetEditor(editor); |
michael@0 | 419 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 420 | |
michael@0 | 421 | // setup the HTML editor command controller |
michael@0 | 422 | if (needHTMLController) |
michael@0 | 423 | { |
michael@0 | 424 | // The third controller takes an nsIEditor as the context |
michael@0 | 425 | rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1", |
michael@0 | 426 | aWindow, editor, |
michael@0 | 427 | &mHTMLCommandControllerId); |
michael@0 | 428 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 429 | } |
michael@0 | 430 | |
michael@0 | 431 | // Set mimetype on editor |
michael@0 | 432 | rv = editor->SetContentsMIMEType(mimeCType.get()); |
michael@0 | 433 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 434 | |
michael@0 | 435 | nsCOMPtr<nsIContentViewer> contentViewer; |
michael@0 | 436 | rv = docShell->GetContentViewer(getter_AddRefs(contentViewer)); |
michael@0 | 437 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 438 | NS_ENSURE_TRUE(contentViewer, NS_ERROR_FAILURE); |
michael@0 | 439 | |
michael@0 | 440 | nsCOMPtr<nsIDOMDocument> domDoc; |
michael@0 | 441 | rv = contentViewer->GetDOMDocument(getter_AddRefs(domDoc)); |
michael@0 | 442 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 443 | NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE); |
michael@0 | 444 | |
michael@0 | 445 | // Set up as a doc state listener |
michael@0 | 446 | // Important! We must have this to broadcast the "obs_documentCreated" message |
michael@0 | 447 | rv = editor->AddDocumentStateListener(mStateMaintainer); |
michael@0 | 448 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 449 | |
michael@0 | 450 | rv = editor->Init(domDoc, nullptr /* root content */, |
michael@0 | 451 | nullptr, mEditorFlags, EmptyString()); |
michael@0 | 452 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 453 | |
michael@0 | 454 | nsCOMPtr<nsISelection> selection; |
michael@0 | 455 | editor->GetSelection(getter_AddRefs(selection)); |
michael@0 | 456 | nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection); |
michael@0 | 457 | NS_ENSURE_TRUE(selPriv, NS_ERROR_FAILURE); |
michael@0 | 458 | |
michael@0 | 459 | rv = selPriv->AddSelectionListener(mStateMaintainer); |
michael@0 | 460 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 461 | |
michael@0 | 462 | // and as a transaction listener |
michael@0 | 463 | nsCOMPtr<nsITransactionManager> txnMgr; |
michael@0 | 464 | editor->GetTransactionManager(getter_AddRefs(txnMgr)); |
michael@0 | 465 | if (txnMgr) |
michael@0 | 466 | txnMgr->AddListener(mStateMaintainer); |
michael@0 | 467 | |
michael@0 | 468 | // Set context on all controllers to be the editor |
michael@0 | 469 | rv = SetEditorOnControllers(aWindow, editor); |
michael@0 | 470 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 471 | |
michael@0 | 472 | // Everything went fine! |
michael@0 | 473 | mEditorStatus = eEditorOK; |
michael@0 | 474 | |
michael@0 | 475 | // This will trigger documentCreation notification |
michael@0 | 476 | return editor->PostCreate(); |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | // Removes all listeners and controllers from aWindow and aEditor. |
michael@0 | 480 | void |
michael@0 | 481 | nsEditingSession::RemoveListenersAndControllers(nsIDOMWindow *aWindow, |
michael@0 | 482 | nsIEditor *aEditor) |
michael@0 | 483 | { |
michael@0 | 484 | if (!mStateMaintainer || !aEditor) |
michael@0 | 485 | return; |
michael@0 | 486 | |
michael@0 | 487 | // Remove all the listeners |
michael@0 | 488 | nsCOMPtr<nsISelection> selection; |
michael@0 | 489 | aEditor->GetSelection(getter_AddRefs(selection)); |
michael@0 | 490 | nsCOMPtr<nsISelectionPrivate> selPriv = do_QueryInterface(selection); |
michael@0 | 491 | if (selPriv) |
michael@0 | 492 | selPriv->RemoveSelectionListener(mStateMaintainer); |
michael@0 | 493 | |
michael@0 | 494 | aEditor->RemoveDocumentStateListener(mStateMaintainer); |
michael@0 | 495 | |
michael@0 | 496 | nsCOMPtr<nsITransactionManager> txnMgr; |
michael@0 | 497 | aEditor->GetTransactionManager(getter_AddRefs(txnMgr)); |
michael@0 | 498 | if (txnMgr) |
michael@0 | 499 | txnMgr->RemoveListener(mStateMaintainer); |
michael@0 | 500 | |
michael@0 | 501 | // Remove editor controllers from the window now that we're not |
michael@0 | 502 | // editing in that window any more. |
michael@0 | 503 | RemoveEditorControllers(aWindow); |
michael@0 | 504 | } |
michael@0 | 505 | |
michael@0 | 506 | /*--------------------------------------------------------------------------- |
michael@0 | 507 | |
michael@0 | 508 | TearDownEditorOnWindow |
michael@0 | 509 | |
michael@0 | 510 | void tearDownEditorOnWindow (in nsIDOMWindow aWindow); |
michael@0 | 511 | ----------------------------------------------------------------------------*/ |
michael@0 | 512 | NS_IMETHODIMP |
michael@0 | 513 | nsEditingSession::TearDownEditorOnWindow(nsIDOMWindow *aWindow) |
michael@0 | 514 | { |
michael@0 | 515 | if (!mDoneSetup) { |
michael@0 | 516 | return NS_OK; |
michael@0 | 517 | } |
michael@0 | 518 | |
michael@0 | 519 | NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER); |
michael@0 | 520 | |
michael@0 | 521 | nsresult rv; |
michael@0 | 522 | |
michael@0 | 523 | // Kill any existing reload timer |
michael@0 | 524 | if (mLoadBlankDocTimer) |
michael@0 | 525 | { |
michael@0 | 526 | mLoadBlankDocTimer->Cancel(); |
michael@0 | 527 | mLoadBlankDocTimer = nullptr; |
michael@0 | 528 | } |
michael@0 | 529 | |
michael@0 | 530 | mDoneSetup = false; |
michael@0 | 531 | |
michael@0 | 532 | // Check if we're turning off editing (from contentEditable or designMode). |
michael@0 | 533 | nsCOMPtr<nsIDOMDocument> domDoc; |
michael@0 | 534 | aWindow->GetDocument(getter_AddRefs(domDoc)); |
michael@0 | 535 | nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(domDoc); |
michael@0 | 536 | bool stopEditing = htmlDoc && htmlDoc->IsEditingOn(); |
michael@0 | 537 | if (stopEditing) |
michael@0 | 538 | RemoveWebProgressListener(aWindow); |
michael@0 | 539 | |
michael@0 | 540 | nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 541 | NS_ENSURE_STATE(docShell); |
michael@0 | 542 | |
michael@0 | 543 | nsCOMPtr<nsIEditor> editor; |
michael@0 | 544 | rv = docShell->GetEditor(getter_AddRefs(editor)); |
michael@0 | 545 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 546 | |
michael@0 | 547 | if (stopEditing) |
michael@0 | 548 | htmlDoc->TearingDownEditor(editor); |
michael@0 | 549 | |
michael@0 | 550 | if (mStateMaintainer && editor) |
michael@0 | 551 | { |
michael@0 | 552 | // Null out the editor on the controllers first to prevent their weak |
michael@0 | 553 | // references from pointing to a destroyed editor. |
michael@0 | 554 | SetEditorOnControllers(aWindow, nullptr); |
michael@0 | 555 | } |
michael@0 | 556 | |
michael@0 | 557 | // Null out the editor on the docShell to trigger PreDestroy which |
michael@0 | 558 | // needs to happen before document state listeners are removed below. |
michael@0 | 559 | docShell->SetEditor(nullptr); |
michael@0 | 560 | |
michael@0 | 561 | RemoveListenersAndControllers(aWindow, editor); |
michael@0 | 562 | |
michael@0 | 563 | if (stopEditing) |
michael@0 | 564 | { |
michael@0 | 565 | // Make things the way they were before we started editing. |
michael@0 | 566 | RestoreJSAndPlugins(aWindow); |
michael@0 | 567 | RestoreAnimationMode(aWindow); |
michael@0 | 568 | |
michael@0 | 569 | if (mMakeWholeDocumentEditable) |
michael@0 | 570 | { |
michael@0 | 571 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc, &rv); |
michael@0 | 572 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 573 | |
michael@0 | 574 | doc->SetEditableFlag(false); |
michael@0 | 575 | nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(doc); |
michael@0 | 576 | if (htmlDocument) { |
michael@0 | 577 | htmlDocument->SetEditingState(nsIHTMLDocument::eOff); |
michael@0 | 578 | } |
michael@0 | 579 | } |
michael@0 | 580 | } |
michael@0 | 581 | |
michael@0 | 582 | return rv; |
michael@0 | 583 | } |
michael@0 | 584 | |
michael@0 | 585 | /*--------------------------------------------------------------------------- |
michael@0 | 586 | |
michael@0 | 587 | GetEditorForFrame |
michael@0 | 588 | |
michael@0 | 589 | nsIEditor getEditorForFrame (in nsIDOMWindow aWindow); |
michael@0 | 590 | ----------------------------------------------------------------------------*/ |
michael@0 | 591 | NS_IMETHODIMP |
michael@0 | 592 | nsEditingSession::GetEditorForWindow(nsIDOMWindow *aWindow, |
michael@0 | 593 | nsIEditor **outEditor) |
michael@0 | 594 | { |
michael@0 | 595 | nsCOMPtr<nsIDocShell> docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 596 | NS_ENSURE_STATE(aWindow); |
michael@0 | 597 | |
michael@0 | 598 | return docShell->GetEditor(outEditor); |
michael@0 | 599 | } |
michael@0 | 600 | |
michael@0 | 601 | /*--------------------------------------------------------------------------- |
michael@0 | 602 | |
michael@0 | 603 | OnStateChange |
michael@0 | 604 | |
michael@0 | 605 | ----------------------------------------------------------------------------*/ |
michael@0 | 606 | NS_IMETHODIMP |
michael@0 | 607 | nsEditingSession::OnStateChange(nsIWebProgress *aWebProgress, |
michael@0 | 608 | nsIRequest *aRequest, |
michael@0 | 609 | uint32_t aStateFlags, nsresult aStatus) |
michael@0 | 610 | { |
michael@0 | 611 | |
michael@0 | 612 | #ifdef NOISY_DOC_LOADING |
michael@0 | 613 | nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
michael@0 | 614 | if (channel) |
michael@0 | 615 | { |
michael@0 | 616 | nsAutoCString contentType; |
michael@0 | 617 | channel->GetContentType(contentType); |
michael@0 | 618 | if (!contentType.IsEmpty()) |
michael@0 | 619 | printf(" ++++++ MIMETYPE = %s\n", contentType.get()); |
michael@0 | 620 | } |
michael@0 | 621 | #endif |
michael@0 | 622 | |
michael@0 | 623 | // |
michael@0 | 624 | // A Request has started... |
michael@0 | 625 | // |
michael@0 | 626 | if (aStateFlags & nsIWebProgressListener::STATE_START) |
michael@0 | 627 | { |
michael@0 | 628 | #ifdef NOISY_DOC_LOADING |
michael@0 | 629 | { |
michael@0 | 630 | nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
michael@0 | 631 | if (channel) |
michael@0 | 632 | { |
michael@0 | 633 | nsCOMPtr<nsIURI> uri; |
michael@0 | 634 | channel->GetURI(getter_AddRefs(uri)); |
michael@0 | 635 | if (uri) |
michael@0 | 636 | { |
michael@0 | 637 | nsXPIDLCString spec; |
michael@0 | 638 | uri->GetSpec(spec); |
michael@0 | 639 | printf(" **** STATE_START: CHANNEL URI=%s, flags=%x\n", |
michael@0 | 640 | spec.get(), aStateFlags); |
michael@0 | 641 | } |
michael@0 | 642 | } |
michael@0 | 643 | else |
michael@0 | 644 | printf(" STATE_START: NO CHANNEL flags=%x\n", aStateFlags); |
michael@0 | 645 | } |
michael@0 | 646 | #endif |
michael@0 | 647 | // Page level notification... |
michael@0 | 648 | if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) |
michael@0 | 649 | { |
michael@0 | 650 | nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
michael@0 | 651 | StartPageLoad(channel); |
michael@0 | 652 | #ifdef NOISY_DOC_LOADING |
michael@0 | 653 | printf("STATE_START & STATE_IS_NETWORK flags=%x\n", aStateFlags); |
michael@0 | 654 | #endif |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | // Document level notification... |
michael@0 | 658 | if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT && |
michael@0 | 659 | !(aStateFlags & nsIWebProgressListener::STATE_RESTORING)) { |
michael@0 | 660 | #ifdef NOISY_DOC_LOADING |
michael@0 | 661 | printf("STATE_START & STATE_IS_DOCUMENT flags=%x\n", aStateFlags); |
michael@0 | 662 | #endif |
michael@0 | 663 | |
michael@0 | 664 | bool progressIsForTargetDocument = |
michael@0 | 665 | IsProgressForTargetDocument(aWebProgress); |
michael@0 | 666 | |
michael@0 | 667 | if (progressIsForTargetDocument) |
michael@0 | 668 | { |
michael@0 | 669 | nsCOMPtr<nsIDOMWindow> window; |
michael@0 | 670 | aWebProgress->GetDOMWindow(getter_AddRefs(window)); |
michael@0 | 671 | |
michael@0 | 672 | nsCOMPtr<nsIDOMDocument> doc; |
michael@0 | 673 | window->GetDocument(getter_AddRefs(doc)); |
michael@0 | 674 | |
michael@0 | 675 | nsCOMPtr<nsIHTMLDocument> htmlDoc(do_QueryInterface(doc)); |
michael@0 | 676 | |
michael@0 | 677 | if (htmlDoc && htmlDoc->IsWriting()) |
michael@0 | 678 | { |
michael@0 | 679 | nsCOMPtr<nsIDOMHTMLDocument> htmlDomDoc = do_QueryInterface(doc); |
michael@0 | 680 | nsAutoString designMode; |
michael@0 | 681 | htmlDomDoc->GetDesignMode(designMode); |
michael@0 | 682 | |
michael@0 | 683 | if (designMode.EqualsLiteral("on")) |
michael@0 | 684 | { |
michael@0 | 685 | // This notification is for data coming in through |
michael@0 | 686 | // document.open/write/close(), ignore it. |
michael@0 | 687 | |
michael@0 | 688 | return NS_OK; |
michael@0 | 689 | } |
michael@0 | 690 | } |
michael@0 | 691 | |
michael@0 | 692 | mCanCreateEditor = true; |
michael@0 | 693 | StartDocumentLoad(aWebProgress, progressIsForTargetDocument); |
michael@0 | 694 | } |
michael@0 | 695 | } |
michael@0 | 696 | } |
michael@0 | 697 | // |
michael@0 | 698 | // A Request is being processed |
michael@0 | 699 | // |
michael@0 | 700 | else if (aStateFlags & nsIWebProgressListener::STATE_TRANSFERRING) |
michael@0 | 701 | { |
michael@0 | 702 | if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) |
michael@0 | 703 | { |
michael@0 | 704 | // document transfer started |
michael@0 | 705 | } |
michael@0 | 706 | } |
michael@0 | 707 | // |
michael@0 | 708 | // Got a redirection |
michael@0 | 709 | // |
michael@0 | 710 | else if (aStateFlags & nsIWebProgressListener::STATE_REDIRECTING) |
michael@0 | 711 | { |
michael@0 | 712 | if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) |
michael@0 | 713 | { |
michael@0 | 714 | // got a redirect |
michael@0 | 715 | } |
michael@0 | 716 | } |
michael@0 | 717 | // |
michael@0 | 718 | // A network or document Request has finished... |
michael@0 | 719 | // |
michael@0 | 720 | else if (aStateFlags & nsIWebProgressListener::STATE_STOP) |
michael@0 | 721 | { |
michael@0 | 722 | |
michael@0 | 723 | #ifdef NOISY_DOC_LOADING |
michael@0 | 724 | { |
michael@0 | 725 | nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); |
michael@0 | 726 | if (channel) |
michael@0 | 727 | { |
michael@0 | 728 | nsCOMPtr<nsIURI> uri; |
michael@0 | 729 | channel->GetURI(getter_AddRefs(uri)); |
michael@0 | 730 | if (uri) |
michael@0 | 731 | { |
michael@0 | 732 | nsXPIDLCString spec; |
michael@0 | 733 | uri->GetSpec(spec); |
michael@0 | 734 | printf(" **** STATE_STOP: CHANNEL URI=%s, flags=%x\n", |
michael@0 | 735 | spec.get(), aStateFlags); |
michael@0 | 736 | } |
michael@0 | 737 | } |
michael@0 | 738 | else |
michael@0 | 739 | printf(" STATE_STOP: NO CHANNEL flags=%x\n", aStateFlags); |
michael@0 | 740 | } |
michael@0 | 741 | #endif |
michael@0 | 742 | |
michael@0 | 743 | // Document level notification... |
michael@0 | 744 | if (aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) |
michael@0 | 745 | { |
michael@0 | 746 | nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); |
michael@0 | 747 | EndDocumentLoad(aWebProgress, channel, aStatus, |
michael@0 | 748 | IsProgressForTargetDocument(aWebProgress)); |
michael@0 | 749 | #ifdef NOISY_DOC_LOADING |
michael@0 | 750 | printf("STATE_STOP & STATE_IS_DOCUMENT flags=%x\n", aStateFlags); |
michael@0 | 751 | #endif |
michael@0 | 752 | } |
michael@0 | 753 | |
michael@0 | 754 | // Page level notification... |
michael@0 | 755 | if (aStateFlags & nsIWebProgressListener::STATE_IS_NETWORK) |
michael@0 | 756 | { |
michael@0 | 757 | nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest); |
michael@0 | 758 | (void)EndPageLoad(aWebProgress, channel, aStatus); |
michael@0 | 759 | #ifdef NOISY_DOC_LOADING |
michael@0 | 760 | printf("STATE_STOP & STATE_IS_NETWORK flags=%x\n", aStateFlags); |
michael@0 | 761 | #endif |
michael@0 | 762 | } |
michael@0 | 763 | } |
michael@0 | 764 | |
michael@0 | 765 | return NS_OK; |
michael@0 | 766 | } |
michael@0 | 767 | |
michael@0 | 768 | /*--------------------------------------------------------------------------- |
michael@0 | 769 | |
michael@0 | 770 | OnProgressChange |
michael@0 | 771 | |
michael@0 | 772 | ----------------------------------------------------------------------------*/ |
michael@0 | 773 | NS_IMETHODIMP |
michael@0 | 774 | nsEditingSession::OnProgressChange(nsIWebProgress *aWebProgress, |
michael@0 | 775 | nsIRequest *aRequest, |
michael@0 | 776 | int32_t aCurSelfProgress, |
michael@0 | 777 | int32_t aMaxSelfProgress, |
michael@0 | 778 | int32_t aCurTotalProgress, |
michael@0 | 779 | int32_t aMaxTotalProgress) |
michael@0 | 780 | { |
michael@0 | 781 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 782 | return NS_OK; |
michael@0 | 783 | } |
michael@0 | 784 | |
michael@0 | 785 | /*--------------------------------------------------------------------------- |
michael@0 | 786 | |
michael@0 | 787 | OnLocationChange |
michael@0 | 788 | |
michael@0 | 789 | ----------------------------------------------------------------------------*/ |
michael@0 | 790 | NS_IMETHODIMP |
michael@0 | 791 | nsEditingSession::OnLocationChange(nsIWebProgress *aWebProgress, |
michael@0 | 792 | nsIRequest *aRequest, nsIURI *aURI, |
michael@0 | 793 | uint32_t aFlags) |
michael@0 | 794 | { |
michael@0 | 795 | nsCOMPtr<nsIDOMWindow> domWindow; |
michael@0 | 796 | nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); |
michael@0 | 797 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 798 | |
michael@0 | 799 | nsCOMPtr<nsIDOMDocument> domDoc; |
michael@0 | 800 | rv = domWindow->GetDocument(getter_AddRefs(domDoc)); |
michael@0 | 801 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 802 | |
michael@0 | 803 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); |
michael@0 | 804 | NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); |
michael@0 | 805 | |
michael@0 | 806 | doc->SetDocumentURI(aURI); |
michael@0 | 807 | |
michael@0 | 808 | // Notify the location-changed observer that |
michael@0 | 809 | // the document URL has changed |
michael@0 | 810 | nsIDocShell *docShell = GetDocShellFromWindow(domWindow); |
michael@0 | 811 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 812 | |
michael@0 | 813 | nsCOMPtr<nsICommandManager> commandManager = do_GetInterface(docShell); |
michael@0 | 814 | nsCOMPtr<nsPICommandUpdater> commandUpdater = |
michael@0 | 815 | do_QueryInterface(commandManager); |
michael@0 | 816 | NS_ENSURE_TRUE(commandUpdater, NS_ERROR_FAILURE); |
michael@0 | 817 | |
michael@0 | 818 | return commandUpdater->CommandStatusChanged("obs_documentLocationChanged"); |
michael@0 | 819 | } |
michael@0 | 820 | |
michael@0 | 821 | /*--------------------------------------------------------------------------- |
michael@0 | 822 | |
michael@0 | 823 | OnStatusChange |
michael@0 | 824 | |
michael@0 | 825 | ----------------------------------------------------------------------------*/ |
michael@0 | 826 | NS_IMETHODIMP |
michael@0 | 827 | nsEditingSession::OnStatusChange(nsIWebProgress *aWebProgress, |
michael@0 | 828 | nsIRequest *aRequest, |
michael@0 | 829 | nsresult aStatus, |
michael@0 | 830 | const char16_t *aMessage) |
michael@0 | 831 | { |
michael@0 | 832 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 833 | return NS_OK; |
michael@0 | 834 | } |
michael@0 | 835 | |
michael@0 | 836 | /*--------------------------------------------------------------------------- |
michael@0 | 837 | |
michael@0 | 838 | OnSecurityChange |
michael@0 | 839 | |
michael@0 | 840 | ----------------------------------------------------------------------------*/ |
michael@0 | 841 | NS_IMETHODIMP |
michael@0 | 842 | nsEditingSession::OnSecurityChange(nsIWebProgress *aWebProgress, |
michael@0 | 843 | nsIRequest *aRequest, uint32_t state) |
michael@0 | 844 | { |
michael@0 | 845 | NS_NOTREACHED("notification excluded in AddProgressListener(...)"); |
michael@0 | 846 | return NS_OK; |
michael@0 | 847 | } |
michael@0 | 848 | |
michael@0 | 849 | |
michael@0 | 850 | /*--------------------------------------------------------------------------- |
michael@0 | 851 | |
michael@0 | 852 | IsProgressForTargetDocument |
michael@0 | 853 | |
michael@0 | 854 | Check that this notification is for our document. |
michael@0 | 855 | ----------------------------------------------------------------------------*/ |
michael@0 | 856 | |
michael@0 | 857 | bool |
michael@0 | 858 | nsEditingSession::IsProgressForTargetDocument(nsIWebProgress *aWebProgress) |
michael@0 | 859 | { |
michael@0 | 860 | nsCOMPtr<nsIWebProgress> editedWebProgress = do_QueryReferent(mDocShell); |
michael@0 | 861 | return editedWebProgress == aWebProgress; |
michael@0 | 862 | } |
michael@0 | 863 | |
michael@0 | 864 | |
michael@0 | 865 | /*--------------------------------------------------------------------------- |
michael@0 | 866 | |
michael@0 | 867 | GetEditorStatus |
michael@0 | 868 | |
michael@0 | 869 | Called during GetCommandStateParams("obs_documentCreated"...) |
michael@0 | 870 | to determine if editor was created and document |
michael@0 | 871 | was loaded successfully |
michael@0 | 872 | ----------------------------------------------------------------------------*/ |
michael@0 | 873 | NS_IMETHODIMP |
michael@0 | 874 | nsEditingSession::GetEditorStatus(uint32_t *aStatus) |
michael@0 | 875 | { |
michael@0 | 876 | NS_ENSURE_ARG_POINTER(aStatus); |
michael@0 | 877 | *aStatus = mEditorStatus; |
michael@0 | 878 | return NS_OK; |
michael@0 | 879 | } |
michael@0 | 880 | |
michael@0 | 881 | /*--------------------------------------------------------------------------- |
michael@0 | 882 | |
michael@0 | 883 | StartDocumentLoad |
michael@0 | 884 | |
michael@0 | 885 | Called on start of load in a single frame |
michael@0 | 886 | ----------------------------------------------------------------------------*/ |
michael@0 | 887 | nsresult |
michael@0 | 888 | nsEditingSession::StartDocumentLoad(nsIWebProgress *aWebProgress, |
michael@0 | 889 | bool aIsToBeMadeEditable) |
michael@0 | 890 | { |
michael@0 | 891 | #ifdef NOISY_DOC_LOADING |
michael@0 | 892 | printf("======= StartDocumentLoad ========\n"); |
michael@0 | 893 | #endif |
michael@0 | 894 | |
michael@0 | 895 | NS_ENSURE_ARG_POINTER(aWebProgress); |
michael@0 | 896 | |
michael@0 | 897 | // If we have an editor here, then we got a reload after making the editor. |
michael@0 | 898 | // We need to blow it away and make a new one at the end of the load. |
michael@0 | 899 | nsCOMPtr<nsIDOMWindow> domWindow; |
michael@0 | 900 | aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); |
michael@0 | 901 | if (domWindow) |
michael@0 | 902 | { |
michael@0 | 903 | nsIDocShell *docShell = GetDocShellFromWindow(domWindow); |
michael@0 | 904 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 905 | docShell->DetachEditorFromWindow(); |
michael@0 | 906 | } |
michael@0 | 907 | |
michael@0 | 908 | if (aIsToBeMadeEditable) |
michael@0 | 909 | mEditorStatus = eEditorCreationInProgress; |
michael@0 | 910 | |
michael@0 | 911 | return NS_OK; |
michael@0 | 912 | } |
michael@0 | 913 | |
michael@0 | 914 | /*--------------------------------------------------------------------------- |
michael@0 | 915 | |
michael@0 | 916 | EndDocumentLoad |
michael@0 | 917 | |
michael@0 | 918 | Called on end of load in a single frame |
michael@0 | 919 | ----------------------------------------------------------------------------*/ |
michael@0 | 920 | nsresult |
michael@0 | 921 | nsEditingSession::EndDocumentLoad(nsIWebProgress *aWebProgress, |
michael@0 | 922 | nsIChannel* aChannel, nsresult aStatus, |
michael@0 | 923 | bool aIsToBeMadeEditable) |
michael@0 | 924 | { |
michael@0 | 925 | NS_ENSURE_ARG_POINTER(aWebProgress); |
michael@0 | 926 | |
michael@0 | 927 | #ifdef NOISY_DOC_LOADING |
michael@0 | 928 | printf("======= EndDocumentLoad ========\n"); |
michael@0 | 929 | printf("with status %d, ", aStatus); |
michael@0 | 930 | nsCOMPtr<nsIURI> uri; |
michael@0 | 931 | nsXPIDLCString spec; |
michael@0 | 932 | if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) { |
michael@0 | 933 | uri->GetSpec(spec); |
michael@0 | 934 | printf(" uri %s\n", spec.get()); |
michael@0 | 935 | } |
michael@0 | 936 | #endif |
michael@0 | 937 | |
michael@0 | 938 | // We want to call the base class EndDocumentLoad, |
michael@0 | 939 | // but avoid some of the stuff |
michael@0 | 940 | // that nsDocShell does (need to refactor). |
michael@0 | 941 | |
michael@0 | 942 | // OK, time to make an editor on this document |
michael@0 | 943 | nsCOMPtr<nsIDOMWindow> domWindow; |
michael@0 | 944 | aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); |
michael@0 | 945 | |
michael@0 | 946 | // Set the error state -- we will create an editor |
michael@0 | 947 | // anyway and load empty doc later |
michael@0 | 948 | if (aIsToBeMadeEditable) { |
michael@0 | 949 | if (aStatus == NS_ERROR_FILE_NOT_FOUND) |
michael@0 | 950 | mEditorStatus = eEditorErrorFileNotFound; |
michael@0 | 951 | } |
michael@0 | 952 | |
michael@0 | 953 | nsIDocShell *docShell = GetDocShellFromWindow(domWindow); |
michael@0 | 954 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); // better error handling? |
michael@0 | 955 | |
michael@0 | 956 | // cancel refresh from meta tags |
michael@0 | 957 | // we need to make sure that all pages in editor (whether editable or not) |
michael@0 | 958 | // can't refresh contents being edited |
michael@0 | 959 | nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell); |
michael@0 | 960 | if (refreshURI) |
michael@0 | 961 | refreshURI->CancelRefreshURITimers(); |
michael@0 | 962 | |
michael@0 | 963 | nsresult rv = NS_OK; |
michael@0 | 964 | |
michael@0 | 965 | // did someone set the flag to make this shell editable? |
michael@0 | 966 | if (aIsToBeMadeEditable && mCanCreateEditor) |
michael@0 | 967 | { |
michael@0 | 968 | bool makeEditable; |
michael@0 | 969 | docShell->GetEditable(&makeEditable); |
michael@0 | 970 | |
michael@0 | 971 | if (makeEditable) |
michael@0 | 972 | { |
michael@0 | 973 | // To keep pre Gecko 1.9 behavior, setup editor always when |
michael@0 | 974 | // mMakeWholeDocumentEditable. |
michael@0 | 975 | bool needsSetup = false; |
michael@0 | 976 | if (mMakeWholeDocumentEditable) { |
michael@0 | 977 | needsSetup = true; |
michael@0 | 978 | } else { |
michael@0 | 979 | // do we already have an editor here? |
michael@0 | 980 | nsCOMPtr<nsIEditor> editor; |
michael@0 | 981 | rv = docShell->GetEditor(getter_AddRefs(editor)); |
michael@0 | 982 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 983 | |
michael@0 | 984 | needsSetup = !editor; |
michael@0 | 985 | } |
michael@0 | 986 | |
michael@0 | 987 | if (needsSetup) |
michael@0 | 988 | { |
michael@0 | 989 | mCanCreateEditor = false; |
michael@0 | 990 | rv = SetupEditorOnWindow(domWindow); |
michael@0 | 991 | if (NS_FAILED(rv)) |
michael@0 | 992 | { |
michael@0 | 993 | // If we had an error, setup timer to load a blank page later |
michael@0 | 994 | if (mLoadBlankDocTimer) |
michael@0 | 995 | { |
michael@0 | 996 | // Must cancel previous timer? |
michael@0 | 997 | mLoadBlankDocTimer->Cancel(); |
michael@0 | 998 | mLoadBlankDocTimer = nullptr; |
michael@0 | 999 | } |
michael@0 | 1000 | |
michael@0 | 1001 | mLoadBlankDocTimer = do_CreateInstance("@mozilla.org/timer;1", &rv); |
michael@0 | 1002 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1003 | |
michael@0 | 1004 | mEditorStatus = eEditorCreationInProgress; |
michael@0 | 1005 | mLoadBlankDocTimer->InitWithFuncCallback( |
michael@0 | 1006 | nsEditingSession::TimerCallback, |
michael@0 | 1007 | static_cast<void*> (mDocShell.get()), |
michael@0 | 1008 | 10, nsITimer::TYPE_ONE_SHOT); |
michael@0 | 1009 | } |
michael@0 | 1010 | } |
michael@0 | 1011 | } |
michael@0 | 1012 | } |
michael@0 | 1013 | return rv; |
michael@0 | 1014 | } |
michael@0 | 1015 | |
michael@0 | 1016 | |
michael@0 | 1017 | void |
michael@0 | 1018 | nsEditingSession::TimerCallback(nsITimer* aTimer, void* aClosure) |
michael@0 | 1019 | { |
michael@0 | 1020 | nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(static_cast<nsIWeakReference*> (aClosure)); |
michael@0 | 1021 | if (docShell) |
michael@0 | 1022 | { |
michael@0 | 1023 | nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(docShell)); |
michael@0 | 1024 | if (webNav) |
michael@0 | 1025 | webNav->LoadURI(MOZ_UTF16("about:blank"), |
michael@0 | 1026 | 0, nullptr, nullptr, nullptr); |
michael@0 | 1027 | } |
michael@0 | 1028 | } |
michael@0 | 1029 | |
michael@0 | 1030 | /*--------------------------------------------------------------------------- |
michael@0 | 1031 | |
michael@0 | 1032 | StartPageLoad |
michael@0 | 1033 | |
michael@0 | 1034 | Called on start load of the entire page (incl. subframes) |
michael@0 | 1035 | ----------------------------------------------------------------------------*/ |
michael@0 | 1036 | nsresult |
michael@0 | 1037 | nsEditingSession::StartPageLoad(nsIChannel *aChannel) |
michael@0 | 1038 | { |
michael@0 | 1039 | #ifdef NOISY_DOC_LOADING |
michael@0 | 1040 | printf("======= StartPageLoad ========\n"); |
michael@0 | 1041 | #endif |
michael@0 | 1042 | return NS_OK; |
michael@0 | 1043 | } |
michael@0 | 1044 | |
michael@0 | 1045 | /*--------------------------------------------------------------------------- |
michael@0 | 1046 | |
michael@0 | 1047 | EndPageLoad |
michael@0 | 1048 | |
michael@0 | 1049 | Called on end load of the entire page (incl. subframes) |
michael@0 | 1050 | ----------------------------------------------------------------------------*/ |
michael@0 | 1051 | nsresult |
michael@0 | 1052 | nsEditingSession::EndPageLoad(nsIWebProgress *aWebProgress, |
michael@0 | 1053 | nsIChannel* aChannel, nsresult aStatus) |
michael@0 | 1054 | { |
michael@0 | 1055 | #ifdef NOISY_DOC_LOADING |
michael@0 | 1056 | printf("======= EndPageLoad ========\n"); |
michael@0 | 1057 | printf(" with status %d, ", aStatus); |
michael@0 | 1058 | nsCOMPtr<nsIURI> uri; |
michael@0 | 1059 | nsXPIDLCString spec; |
michael@0 | 1060 | if (NS_SUCCEEDED(aChannel->GetURI(getter_AddRefs(uri)))) { |
michael@0 | 1061 | uri->GetSpec(spec); |
michael@0 | 1062 | printf("uri %s\n", spec.get()); |
michael@0 | 1063 | } |
michael@0 | 1064 | |
michael@0 | 1065 | nsAutoCString contentType; |
michael@0 | 1066 | aChannel->GetContentType(contentType); |
michael@0 | 1067 | if (!contentType.IsEmpty()) |
michael@0 | 1068 | printf(" flags = %d, status = %d, MIMETYPE = %s\n", |
michael@0 | 1069 | mEditorFlags, mEditorStatus, contentType.get()); |
michael@0 | 1070 | #endif |
michael@0 | 1071 | |
michael@0 | 1072 | // Set the error state -- we will create an editor anyway |
michael@0 | 1073 | // and load empty doc later |
michael@0 | 1074 | if (aStatus == NS_ERROR_FILE_NOT_FOUND) |
michael@0 | 1075 | mEditorStatus = eEditorErrorFileNotFound; |
michael@0 | 1076 | |
michael@0 | 1077 | nsCOMPtr<nsIDOMWindow> domWindow; |
michael@0 | 1078 | aWebProgress->GetDOMWindow(getter_AddRefs(domWindow)); |
michael@0 | 1079 | |
michael@0 | 1080 | nsIDocShell *docShell = GetDocShellFromWindow(domWindow); |
michael@0 | 1081 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 1082 | |
michael@0 | 1083 | // cancel refresh from meta tags |
michael@0 | 1084 | // we need to make sure that all pages in editor (whether editable or not) |
michael@0 | 1085 | // can't refresh contents being edited |
michael@0 | 1086 | nsCOMPtr<nsIRefreshURI> refreshURI = do_QueryInterface(docShell); |
michael@0 | 1087 | if (refreshURI) |
michael@0 | 1088 | refreshURI->CancelRefreshURITimers(); |
michael@0 | 1089 | |
michael@0 | 1090 | #if 0 |
michael@0 | 1091 | // Shouldn't we do this when we want to edit sub-frames? |
michael@0 | 1092 | return MakeWindowEditable(domWindow, "html", false, mInteractive); |
michael@0 | 1093 | #else |
michael@0 | 1094 | return NS_OK; |
michael@0 | 1095 | #endif |
michael@0 | 1096 | } |
michael@0 | 1097 | |
michael@0 | 1098 | /*--------------------------------------------------------------------------- |
michael@0 | 1099 | |
michael@0 | 1100 | GetDocShellFromWindow |
michael@0 | 1101 | |
michael@0 | 1102 | Utility method. This will always return nullptr if no docShell is found. |
michael@0 | 1103 | ----------------------------------------------------------------------------*/ |
michael@0 | 1104 | nsIDocShell * |
michael@0 | 1105 | nsEditingSession::GetDocShellFromWindow(nsIDOMWindow *aWindow) |
michael@0 | 1106 | { |
michael@0 | 1107 | nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow); |
michael@0 | 1108 | NS_ENSURE_TRUE(window, nullptr); |
michael@0 | 1109 | |
michael@0 | 1110 | return window->GetDocShell(); |
michael@0 | 1111 | } |
michael@0 | 1112 | |
michael@0 | 1113 | /*--------------------------------------------------------------------------- |
michael@0 | 1114 | |
michael@0 | 1115 | PrepareForEditing |
michael@0 | 1116 | |
michael@0 | 1117 | Set up this editing session for one or more editors |
michael@0 | 1118 | ----------------------------------------------------------------------------*/ |
michael@0 | 1119 | nsresult |
michael@0 | 1120 | nsEditingSession::PrepareForEditing(nsIDOMWindow *aWindow) |
michael@0 | 1121 | { |
michael@0 | 1122 | if (mProgressListenerRegistered) |
michael@0 | 1123 | return NS_OK; |
michael@0 | 1124 | |
michael@0 | 1125 | nsIDocShell *docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 1126 | |
michael@0 | 1127 | // register callback |
michael@0 | 1128 | nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); |
michael@0 | 1129 | NS_ENSURE_TRUE(webProgress, NS_ERROR_FAILURE); |
michael@0 | 1130 | |
michael@0 | 1131 | nsresult rv = |
michael@0 | 1132 | webProgress->AddProgressListener(this, |
michael@0 | 1133 | (nsIWebProgress::NOTIFY_STATE_NETWORK | |
michael@0 | 1134 | nsIWebProgress::NOTIFY_STATE_DOCUMENT | |
michael@0 | 1135 | nsIWebProgress::NOTIFY_LOCATION)); |
michael@0 | 1136 | |
michael@0 | 1137 | mProgressListenerRegistered = NS_SUCCEEDED(rv); |
michael@0 | 1138 | |
michael@0 | 1139 | return rv; |
michael@0 | 1140 | } |
michael@0 | 1141 | |
michael@0 | 1142 | /*--------------------------------------------------------------------------- |
michael@0 | 1143 | |
michael@0 | 1144 | SetupEditorCommandController |
michael@0 | 1145 | |
michael@0 | 1146 | Create a command controller, append to controllers, |
michael@0 | 1147 | get and return the controller ID, and set the context |
michael@0 | 1148 | ----------------------------------------------------------------------------*/ |
michael@0 | 1149 | nsresult |
michael@0 | 1150 | nsEditingSession::SetupEditorCommandController( |
michael@0 | 1151 | const char *aControllerClassName, |
michael@0 | 1152 | nsIDOMWindow *aWindow, |
michael@0 | 1153 | nsISupports *aContext, |
michael@0 | 1154 | uint32_t *aControllerId) |
michael@0 | 1155 | { |
michael@0 | 1156 | NS_ENSURE_ARG_POINTER(aControllerClassName); |
michael@0 | 1157 | NS_ENSURE_ARG_POINTER(aWindow); |
michael@0 | 1158 | NS_ENSURE_ARG_POINTER(aContext); |
michael@0 | 1159 | NS_ENSURE_ARG_POINTER(aControllerId); |
michael@0 | 1160 | |
michael@0 | 1161 | nsCOMPtr<nsIControllers> controllers; |
michael@0 | 1162 | nsresult rv = aWindow->GetControllers(getter_AddRefs(controllers)); |
michael@0 | 1163 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1164 | |
michael@0 | 1165 | // We only have to create each singleton controller once |
michael@0 | 1166 | // We know this has happened once we have a controllerId value |
michael@0 | 1167 | if (!*aControllerId) |
michael@0 | 1168 | { |
michael@0 | 1169 | nsCOMPtr<nsIController> controller; |
michael@0 | 1170 | controller = do_CreateInstance(aControllerClassName, &rv); |
michael@0 | 1171 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1172 | |
michael@0 | 1173 | // We must insert at head of the list to be sure our |
michael@0 | 1174 | // controller is found before other implementations |
michael@0 | 1175 | // (e.g., not-implemented versions by browser) |
michael@0 | 1176 | rv = controllers->InsertControllerAt(0, controller); |
michael@0 | 1177 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1178 | |
michael@0 | 1179 | // Remember the ID for the controller |
michael@0 | 1180 | rv = controllers->GetControllerId(controller, aControllerId); |
michael@0 | 1181 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1182 | } |
michael@0 | 1183 | |
michael@0 | 1184 | // Set the context |
michael@0 | 1185 | return SetContextOnControllerById(controllers, aContext, *aControllerId); |
michael@0 | 1186 | } |
michael@0 | 1187 | |
michael@0 | 1188 | /*--------------------------------------------------------------------------- |
michael@0 | 1189 | |
michael@0 | 1190 | SetEditorOnControllers |
michael@0 | 1191 | |
michael@0 | 1192 | Set the editor on the controller(s) for this window |
michael@0 | 1193 | ----------------------------------------------------------------------------*/ |
michael@0 | 1194 | NS_IMETHODIMP |
michael@0 | 1195 | nsEditingSession::SetEditorOnControllers(nsIDOMWindow *aWindow, |
michael@0 | 1196 | nsIEditor* aEditor) |
michael@0 | 1197 | { |
michael@0 | 1198 | NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER); |
michael@0 | 1199 | |
michael@0 | 1200 | nsCOMPtr<nsIControllers> controllers; |
michael@0 | 1201 | nsresult rv = aWindow->GetControllers(getter_AddRefs(controllers)); |
michael@0 | 1202 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1203 | |
michael@0 | 1204 | nsCOMPtr<nsISupports> editorAsISupports = do_QueryInterface(aEditor); |
michael@0 | 1205 | if (mBaseCommandControllerId) |
michael@0 | 1206 | { |
michael@0 | 1207 | rv = SetContextOnControllerById(controllers, editorAsISupports, |
michael@0 | 1208 | mBaseCommandControllerId); |
michael@0 | 1209 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1210 | } |
michael@0 | 1211 | |
michael@0 | 1212 | if (mDocStateControllerId) |
michael@0 | 1213 | { |
michael@0 | 1214 | rv = SetContextOnControllerById(controllers, editorAsISupports, |
michael@0 | 1215 | mDocStateControllerId); |
michael@0 | 1216 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1217 | } |
michael@0 | 1218 | |
michael@0 | 1219 | if (mHTMLCommandControllerId) |
michael@0 | 1220 | rv = SetContextOnControllerById(controllers, editorAsISupports, |
michael@0 | 1221 | mHTMLCommandControllerId); |
michael@0 | 1222 | |
michael@0 | 1223 | return rv; |
michael@0 | 1224 | } |
michael@0 | 1225 | |
michael@0 | 1226 | nsresult |
michael@0 | 1227 | nsEditingSession::SetContextOnControllerById(nsIControllers* aControllers, |
michael@0 | 1228 | nsISupports* aContext, |
michael@0 | 1229 | uint32_t aID) |
michael@0 | 1230 | { |
michael@0 | 1231 | NS_ENSURE_ARG_POINTER(aControllers); |
michael@0 | 1232 | |
michael@0 | 1233 | // aContext can be null (when destroying editor) |
michael@0 | 1234 | nsCOMPtr<nsIController> controller; |
michael@0 | 1235 | aControllers->GetControllerById(aID, getter_AddRefs(controller)); |
michael@0 | 1236 | |
michael@0 | 1237 | // ok with nil controller |
michael@0 | 1238 | nsCOMPtr<nsIControllerContext> editorController = |
michael@0 | 1239 | do_QueryInterface(controller); |
michael@0 | 1240 | NS_ENSURE_TRUE(editorController, NS_ERROR_FAILURE); |
michael@0 | 1241 | |
michael@0 | 1242 | return editorController->SetCommandContext(aContext); |
michael@0 | 1243 | } |
michael@0 | 1244 | |
michael@0 | 1245 | void |
michael@0 | 1246 | nsEditingSession::RemoveEditorControllers(nsIDOMWindow *aWindow) |
michael@0 | 1247 | { |
michael@0 | 1248 | // Remove editor controllers from the aWindow, call when we're |
michael@0 | 1249 | // tearing down/detaching editor. |
michael@0 | 1250 | |
michael@0 | 1251 | nsCOMPtr<nsIControllers> controllers; |
michael@0 | 1252 | if (aWindow) |
michael@0 | 1253 | aWindow->GetControllers(getter_AddRefs(controllers)); |
michael@0 | 1254 | |
michael@0 | 1255 | if (controllers) |
michael@0 | 1256 | { |
michael@0 | 1257 | nsCOMPtr<nsIController> controller; |
michael@0 | 1258 | if (mBaseCommandControllerId) |
michael@0 | 1259 | { |
michael@0 | 1260 | controllers->GetControllerById(mBaseCommandControllerId, |
michael@0 | 1261 | getter_AddRefs(controller)); |
michael@0 | 1262 | if (controller) |
michael@0 | 1263 | controllers->RemoveController(controller); |
michael@0 | 1264 | } |
michael@0 | 1265 | |
michael@0 | 1266 | if (mDocStateControllerId) |
michael@0 | 1267 | { |
michael@0 | 1268 | controllers->GetControllerById(mDocStateControllerId, |
michael@0 | 1269 | getter_AddRefs(controller)); |
michael@0 | 1270 | if (controller) |
michael@0 | 1271 | controllers->RemoveController(controller); |
michael@0 | 1272 | } |
michael@0 | 1273 | |
michael@0 | 1274 | if (mHTMLCommandControllerId) |
michael@0 | 1275 | { |
michael@0 | 1276 | controllers->GetControllerById(mHTMLCommandControllerId, |
michael@0 | 1277 | getter_AddRefs(controller)); |
michael@0 | 1278 | if (controller) |
michael@0 | 1279 | controllers->RemoveController(controller); |
michael@0 | 1280 | } |
michael@0 | 1281 | } |
michael@0 | 1282 | |
michael@0 | 1283 | // Clear IDs to trigger creation of new controllers. |
michael@0 | 1284 | mBaseCommandControllerId = 0; |
michael@0 | 1285 | mDocStateControllerId = 0; |
michael@0 | 1286 | mHTMLCommandControllerId = 0; |
michael@0 | 1287 | } |
michael@0 | 1288 | |
michael@0 | 1289 | void |
michael@0 | 1290 | nsEditingSession::RemoveWebProgressListener(nsIDOMWindow *aWindow) |
michael@0 | 1291 | { |
michael@0 | 1292 | nsIDocShell *docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 1293 | nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell); |
michael@0 | 1294 | if (webProgress) |
michael@0 | 1295 | { |
michael@0 | 1296 | webProgress->RemoveProgressListener(this); |
michael@0 | 1297 | mProgressListenerRegistered = false; |
michael@0 | 1298 | } |
michael@0 | 1299 | } |
michael@0 | 1300 | |
michael@0 | 1301 | void |
michael@0 | 1302 | nsEditingSession::RestoreAnimationMode(nsIDOMWindow *aWindow) |
michael@0 | 1303 | { |
michael@0 | 1304 | if (!mInteractive) |
michael@0 | 1305 | { |
michael@0 | 1306 | nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow)); |
michael@0 | 1307 | if (utils) |
michael@0 | 1308 | utils->SetImageAnimationMode(mImageAnimationMode); |
michael@0 | 1309 | } |
michael@0 | 1310 | } |
michael@0 | 1311 | |
michael@0 | 1312 | nsresult |
michael@0 | 1313 | nsEditingSession::DetachFromWindow(nsIDOMWindow* aWindow) |
michael@0 | 1314 | { |
michael@0 | 1315 | NS_ENSURE_TRUE(mDoneSetup, NS_OK); |
michael@0 | 1316 | |
michael@0 | 1317 | NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist."); |
michael@0 | 1318 | |
michael@0 | 1319 | // Kill any existing reload timer |
michael@0 | 1320 | if (mLoadBlankDocTimer) |
michael@0 | 1321 | { |
michael@0 | 1322 | mLoadBlankDocTimer->Cancel(); |
michael@0 | 1323 | mLoadBlankDocTimer = nullptr; |
michael@0 | 1324 | } |
michael@0 | 1325 | |
michael@0 | 1326 | // Remove controllers, webprogress listener, and otherwise |
michael@0 | 1327 | // make things the way they were before we started editing. |
michael@0 | 1328 | RemoveEditorControllers(aWindow); |
michael@0 | 1329 | RemoveWebProgressListener(aWindow); |
michael@0 | 1330 | RestoreJSAndPlugins(aWindow); |
michael@0 | 1331 | RestoreAnimationMode(aWindow); |
michael@0 | 1332 | |
michael@0 | 1333 | // Kill our weak reference to our original window, in case |
michael@0 | 1334 | // it changes on restore, or otherwise dies. |
michael@0 | 1335 | mDocShell = nullptr; |
michael@0 | 1336 | |
michael@0 | 1337 | return NS_OK; |
michael@0 | 1338 | } |
michael@0 | 1339 | |
michael@0 | 1340 | nsresult |
michael@0 | 1341 | nsEditingSession::ReattachToWindow(nsIDOMWindow* aWindow) |
michael@0 | 1342 | { |
michael@0 | 1343 | NS_ENSURE_TRUE(mDoneSetup, NS_OK); |
michael@0 | 1344 | |
michael@0 | 1345 | NS_ASSERTION(mStateMaintainer, "mStateMaintainer should exist."); |
michael@0 | 1346 | |
michael@0 | 1347 | // Imitate nsEditorDocShell::MakeEditable() to reattach the |
michael@0 | 1348 | // old editor ot the window. |
michael@0 | 1349 | nsresult rv; |
michael@0 | 1350 | |
michael@0 | 1351 | nsIDocShell *docShell = GetDocShellFromWindow(aWindow); |
michael@0 | 1352 | NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); |
michael@0 | 1353 | mDocShell = do_GetWeakReference(docShell); |
michael@0 | 1354 | |
michael@0 | 1355 | // Disable plugins. |
michael@0 | 1356 | if (!mInteractive) |
michael@0 | 1357 | { |
michael@0 | 1358 | rv = DisableJSAndPlugins(aWindow); |
michael@0 | 1359 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1360 | } |
michael@0 | 1361 | |
michael@0 | 1362 | // Tells embedder that startup is in progress. |
michael@0 | 1363 | mEditorStatus = eEditorCreationInProgress; |
michael@0 | 1364 | |
michael@0 | 1365 | // Adds back web progress listener. |
michael@0 | 1366 | rv = PrepareForEditing(aWindow); |
michael@0 | 1367 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1368 | |
michael@0 | 1369 | // Setup the command controllers again. |
michael@0 | 1370 | rv = SetupEditorCommandController("@mozilla.org/editor/editingcontroller;1", |
michael@0 | 1371 | aWindow, |
michael@0 | 1372 | static_cast<nsIEditingSession*>(this), |
michael@0 | 1373 | &mBaseCommandControllerId); |
michael@0 | 1374 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1375 | |
michael@0 | 1376 | rv = SetupEditorCommandController("@mozilla.org/editor/editordocstatecontroller;1", |
michael@0 | 1377 | aWindow, |
michael@0 | 1378 | static_cast<nsIEditingSession*>(this), |
michael@0 | 1379 | &mDocStateControllerId); |
michael@0 | 1380 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1381 | |
michael@0 | 1382 | if (mStateMaintainer) |
michael@0 | 1383 | mStateMaintainer->Init(aWindow); |
michael@0 | 1384 | |
michael@0 | 1385 | // Get editor |
michael@0 | 1386 | nsCOMPtr<nsIEditor> editor; |
michael@0 | 1387 | rv = GetEditorForWindow(aWindow, getter_AddRefs(editor)); |
michael@0 | 1388 | NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE); |
michael@0 | 1389 | |
michael@0 | 1390 | if (!mInteractive) |
michael@0 | 1391 | { |
michael@0 | 1392 | // Disable animation of images in this document: |
michael@0 | 1393 | nsCOMPtr<nsIDOMWindowUtils> utils(do_GetInterface(aWindow)); |
michael@0 | 1394 | NS_ENSURE_TRUE(utils, NS_ERROR_FAILURE); |
michael@0 | 1395 | |
michael@0 | 1396 | rv = utils->GetImageAnimationMode(&mImageAnimationMode); |
michael@0 | 1397 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1398 | utils->SetImageAnimationMode(imgIContainer::kDontAnimMode); |
michael@0 | 1399 | } |
michael@0 | 1400 | |
michael@0 | 1401 | // The third controller takes an nsIEditor as the context |
michael@0 | 1402 | rv = SetupEditorCommandController("@mozilla.org/editor/htmleditorcontroller;1", |
michael@0 | 1403 | aWindow, editor, |
michael@0 | 1404 | &mHTMLCommandControllerId); |
michael@0 | 1405 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1406 | |
michael@0 | 1407 | // Set context on all controllers to be the editor |
michael@0 | 1408 | rv = SetEditorOnControllers(aWindow, editor); |
michael@0 | 1409 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1410 | |
michael@0 | 1411 | #ifdef DEBUG |
michael@0 | 1412 | { |
michael@0 | 1413 | bool isEditable; |
michael@0 | 1414 | rv = WindowIsEditable(aWindow, &isEditable); |
michael@0 | 1415 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1416 | NS_ASSERTION(isEditable, "Window is not editable after reattaching editor."); |
michael@0 | 1417 | } |
michael@0 | 1418 | #endif // DEBUG |
michael@0 | 1419 | |
michael@0 | 1420 | return NS_OK; |
michael@0 | 1421 | } |