editor/composer/src/nsEditingSession.cpp

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

mercurial