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