Bumping manifests a=b2g-bump
[gecko.git] / editor / libeditor / SetDocTitleTxn.cpp
blob0337adbba69c27e548467b1e2eeb5340da702302
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/. */
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
23 using namespace mozilla;
25 // note that aEditor is not refcounted
26 SetDocTitleTxn::SetDocTitleTxn()
27 : EditTxn()
28 , mIsTransient(false)
32 NS_IMETHODIMP SetDocTitleTxn::Init(nsIHTMLEditor *aEditor,
33 const nsAString *aValue)
36 NS_ASSERTION(aEditor && aValue, "null args");
37 if (!aEditor || !aValue) { return NS_ERROR_NULL_POINTER; }
39 mEditor = aEditor;
40 mValue = *aValue;
42 return NS_OK;
45 NS_IMETHODIMP SetDocTitleTxn::DoTransaction(void)
47 return SetDomTitle(mValue);
50 NS_IMETHODIMP SetDocTitleTxn::UndoTransaction(void)
52 // No extra work required; the DOM changes alone are enough
53 return NS_OK;
56 NS_IMETHODIMP SetDocTitleTxn::RedoTransaction(void)
58 // No extra work required; the DOM changes alone are enough
59 return NS_OK;
62 nsresult SetDocTitleTxn::SetDomTitle(const nsAString& aTitle)
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);
70 nsCOMPtr<nsIDOMNodeList> titleList;
71 res = domDoc->GetElementsByTagName(NS_LITERAL_STRING("title"), getter_AddRefs(titleList));
72 NS_ENSURE_SUCCESS(res, res);
74 // First assume we will NOT really do anything
75 // (transaction will not be pushed on stack)
76 mIsTransient = true;
78 nsCOMPtr<nsIDOMNode>titleNode;
79 if(titleList)
81 res = titleList->Item(0, getter_AddRefs(titleNode));
82 NS_ENSURE_SUCCESS(res, res);
83 if (titleNode)
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)
92 // Save current text as the undo value
93 nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(child);
94 if(textNode)
96 textNode->GetData(mUndoValue);
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;
103 res = editor->DeleteNode(child);
104 if(NS_FAILED(res)) return res;
109 // We didn't return above, thus we really will be changing the title
110 mIsTransient = false;
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);
116 dom::Element* head = document->GetHeadElement();
117 NS_ENSURE_STATE(head);
119 bool newTitleNode = false;
120 uint32_t newTitleIndex = 0;
122 if (!titleNode)
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);
130 titleNode = do_QueryInterface(titleElement);
131 newTitleNode = true;
133 // Get index so we append new title node after all existing HEAD children.
134 newTitleIndex = head->GetChildCount();
137 // Append a text node under the TITLE
138 // only if the title text isn't empty
139 if (titleNode && !aTitle.IsEmpty())
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);
147 if (newTitleNode)
149 // Not undoable: We will insert newTitleNode below
150 nsCOMPtr<nsIDOMNode> resultNode;
151 res = titleNode->AppendChild(newNode, getter_AddRefs(resultNode));
153 else
155 // This is an undoable transaction
156 res = editor->InsertNode(newNode, titleNode, 0);
158 NS_ENSURE_SUCCESS(res, res);
161 if (newTitleNode)
163 // Undoable transaction to insert title+text together
164 res = editor->InsertNode(titleNode, head->AsDOMNode(), newTitleIndex);
166 return res;
169 NS_IMETHODIMP SetDocTitleTxn::GetTxnDescription(nsAString& aString)
171 aString.AssignLiteral("SetDocTitleTxn: ");
172 aString += mValue;
173 return NS_OK;
176 NS_IMETHODIMP SetDocTitleTxn::GetIsTransient(bool *aIsTransient)
178 NS_ENSURE_TRUE(aIsTransient, NS_ERROR_NULL_POINTER);
179 *aIsTransient = mIsTransient;
180 return NS_OK;