editor/libeditor/base/SetDocTitleTxn.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:22f98e298666
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "SetDocTitleTxn.h"
7 #include "mozilla/dom/Element.h" // for Element
8 #include "nsAString.h"
9 #include "nsCOMPtr.h" // for nsCOMPtr, getter_AddRefs, etc
10 #include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc
11 #include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc
12 #include "nsIDOMCharacterData.h" // for nsIDOMCharacterData
13 #include "nsIDOMDocument.h" // for nsIDOMDocument
14 #include "nsIDOMElement.h" // for nsIDOMElement
15 #include "nsIDOMNode.h" // for nsIDOMNode
16 #include "nsIDOMNodeList.h" // for nsIDOMNodeList
17 #include "nsIDOMText.h" // for nsIDOMText
18 #include "nsIDocument.h" // for nsIDocument
19 #include "nsIEditor.h" // for nsIEditor
20 #include "nsIHTMLEditor.h" // for nsIHTMLEditor
21 #include "nsLiteralString.h" // for NS_LITERAL_STRING
22
23 using namespace mozilla;
24
25 // note that aEditor is not refcounted
26 SetDocTitleTxn::SetDocTitleTxn()
27 : EditTxn()
28 , mIsTransient(false)
29 {
30 }
31
32 NS_IMETHODIMP SetDocTitleTxn::Init(nsIHTMLEditor *aEditor,
33 const nsAString *aValue)
34
35 {
36 NS_ASSERTION(aEditor && aValue, "null args");
37 if (!aEditor || !aValue) { return NS_ERROR_NULL_POINTER; }
38
39 mEditor = aEditor;
40 mValue = *aValue;
41
42 return NS_OK;
43 }
44
45 NS_IMETHODIMP SetDocTitleTxn::DoTransaction(void)
46 {
47 return SetDomTitle(mValue);
48 }
49
50 NS_IMETHODIMP SetDocTitleTxn::UndoTransaction(void)
51 {
52 // No extra work required; the DOM changes alone are enough
53 return NS_OK;
54 }
55
56 NS_IMETHODIMP SetDocTitleTxn::RedoTransaction(void)
57 {
58 // No extra work required; the DOM changes alone are enough
59 return NS_OK;
60 }
61
62 nsresult SetDocTitleTxn::SetDomTitle(const nsAString& aTitle)
63 {
64 nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
65 NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE);
66 nsCOMPtr<nsIDOMDocument> domDoc;
67 nsresult res = editor->GetDocument(getter_AddRefs(domDoc));
68 NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE);
69
70 nsCOMPtr<nsIDOMNodeList> titleList;
71 res = domDoc->GetElementsByTagName(NS_LITERAL_STRING("title"), getter_AddRefs(titleList));
72 NS_ENSURE_SUCCESS(res, res);
73
74 // First assume we will NOT really do anything
75 // (transaction will not be pushed on stack)
76 mIsTransient = true;
77
78 nsCOMPtr<nsIDOMNode>titleNode;
79 if(titleList)
80 {
81 res = titleList->Item(0, getter_AddRefs(titleNode));
82 NS_ENSURE_SUCCESS(res, res);
83 if (titleNode)
84 {
85 // Delete existing child textnode of title node
86 // (Note: all contents under a TITLE node are always in a single text node)
87 nsCOMPtr<nsIDOMNode> child;
88 res = titleNode->GetFirstChild(getter_AddRefs(child));
89 if(NS_FAILED(res)) return res;
90 if(child)
91 {
92 // Save current text as the undo value
93 nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(child);
94 if(textNode)
95 {
96 textNode->GetData(mUndoValue);
97
98 // If title text is identical to what already exists,
99 // quit now (mIsTransient is now TRUE)
100 if (mUndoValue == aTitle)
101 return NS_OK;
102 }
103 res = editor->DeleteNode(child);
104 if(NS_FAILED(res)) return res;
105 }
106 }
107 }
108
109 // We didn't return above, thus we really will be changing the title
110 mIsTransient = false;
111
112 // Get the <HEAD> node, create a <TITLE> and insert it under the HEAD
113 nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
114 NS_ENSURE_STATE(document);
115
116 dom::Element* head = document->GetHeadElement();
117 NS_ENSURE_STATE(head);
118
119 bool newTitleNode = false;
120 uint32_t newTitleIndex = 0;
121
122 if (!titleNode)
123 {
124 // Didn't find one above: Create a new one
125 nsCOMPtr<nsIDOMElement>titleElement;
126 res = domDoc->CreateElement(NS_LITERAL_STRING("title"), getter_AddRefs(titleElement));
127 NS_ENSURE_SUCCESS(res, res);
128 NS_ENSURE_TRUE(titleElement, NS_ERROR_FAILURE);
129
130 titleNode = do_QueryInterface(titleElement);
131 newTitleNode = true;
132
133 // Get index so we append new title node after all existing HEAD children.
134 newTitleIndex = head->GetChildCount();
135 }
136
137 // Append a text node under the TITLE
138 // only if the title text isn't empty
139 if (titleNode && !aTitle.IsEmpty())
140 {
141 nsCOMPtr<nsIDOMText> textNode;
142 res = domDoc->CreateTextNode(aTitle, getter_AddRefs(textNode));
143 NS_ENSURE_SUCCESS(res, res);
144 nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(textNode);
145 NS_ENSURE_TRUE(newNode, NS_ERROR_FAILURE);
146
147 if (newTitleNode)
148 {
149 // Not undoable: We will insert newTitleNode below
150 nsCOMPtr<nsIDOMNode> resultNode;
151 res = titleNode->AppendChild(newNode, getter_AddRefs(resultNode));
152 }
153 else
154 {
155 // This is an undoable transaction
156 res = editor->InsertNode(newNode, titleNode, 0);
157 }
158 NS_ENSURE_SUCCESS(res, res);
159 }
160
161 if (newTitleNode)
162 {
163 // Undoable transaction to insert title+text together
164 res = editor->InsertNode(titleNode, head->AsDOMNode(), newTitleIndex);
165 }
166 return res;
167 }
168
169 NS_IMETHODIMP SetDocTitleTxn::GetTxnDescription(nsAString& aString)
170 {
171 aString.AssignLiteral("SetDocTitleTxn: ");
172 aString += mValue;
173 return NS_OK;
174 }
175
176 NS_IMETHODIMP SetDocTitleTxn::GetIsTransient(bool *aIsTransient)
177 {
178 NS_ENSURE_TRUE(aIsTransient, NS_ERROR_NULL_POINTER);
179 *aIsTransient = mIsTransient;
180 return NS_OK;
181 }
182

mercurial