1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/editor/libeditor/base/SetDocTitleTxn.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,182 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "SetDocTitleTxn.h" 1.10 +#include "mozilla/dom/Element.h" // for Element 1.11 +#include "nsAString.h" 1.12 +#include "nsCOMPtr.h" // for nsCOMPtr, getter_AddRefs, etc 1.13 +#include "nsDebug.h" // for NS_ENSURE_SUCCESS, etc 1.14 +#include "nsError.h" // for NS_OK, NS_ERROR_FAILURE, etc 1.15 +#include "nsIDOMCharacterData.h" // for nsIDOMCharacterData 1.16 +#include "nsIDOMDocument.h" // for nsIDOMDocument 1.17 +#include "nsIDOMElement.h" // for nsIDOMElement 1.18 +#include "nsIDOMNode.h" // for nsIDOMNode 1.19 +#include "nsIDOMNodeList.h" // for nsIDOMNodeList 1.20 +#include "nsIDOMText.h" // for nsIDOMText 1.21 +#include "nsIDocument.h" // for nsIDocument 1.22 +#include "nsIEditor.h" // for nsIEditor 1.23 +#include "nsIHTMLEditor.h" // for nsIHTMLEditor 1.24 +#include "nsLiteralString.h" // for NS_LITERAL_STRING 1.25 + 1.26 +using namespace mozilla; 1.27 + 1.28 +// note that aEditor is not refcounted 1.29 +SetDocTitleTxn::SetDocTitleTxn() 1.30 + : EditTxn() 1.31 +, mIsTransient(false) 1.32 +{ 1.33 +} 1.34 + 1.35 +NS_IMETHODIMP SetDocTitleTxn::Init(nsIHTMLEditor *aEditor, 1.36 + const nsAString *aValue) 1.37 + 1.38 +{ 1.39 + NS_ASSERTION(aEditor && aValue, "null args"); 1.40 + if (!aEditor || !aValue) { return NS_ERROR_NULL_POINTER; } 1.41 + 1.42 + mEditor = aEditor; 1.43 + mValue = *aValue; 1.44 + 1.45 + return NS_OK; 1.46 +} 1.47 + 1.48 +NS_IMETHODIMP SetDocTitleTxn::DoTransaction(void) 1.49 +{ 1.50 + return SetDomTitle(mValue); 1.51 +} 1.52 + 1.53 +NS_IMETHODIMP SetDocTitleTxn::UndoTransaction(void) 1.54 +{ 1.55 + // No extra work required; the DOM changes alone are enough 1.56 + return NS_OK; 1.57 +} 1.58 + 1.59 +NS_IMETHODIMP SetDocTitleTxn::RedoTransaction(void) 1.60 +{ 1.61 + // No extra work required; the DOM changes alone are enough 1.62 + return NS_OK; 1.63 +} 1.64 + 1.65 +nsresult SetDocTitleTxn::SetDomTitle(const nsAString& aTitle) 1.66 +{ 1.67 + nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor); 1.68 + NS_ENSURE_TRUE(editor, NS_ERROR_FAILURE); 1.69 + nsCOMPtr<nsIDOMDocument> domDoc; 1.70 + nsresult res = editor->GetDocument(getter_AddRefs(domDoc)); 1.71 + NS_ENSURE_TRUE(domDoc, NS_ERROR_FAILURE); 1.72 + 1.73 + nsCOMPtr<nsIDOMNodeList> titleList; 1.74 + res = domDoc->GetElementsByTagName(NS_LITERAL_STRING("title"), getter_AddRefs(titleList)); 1.75 + NS_ENSURE_SUCCESS(res, res); 1.76 + 1.77 + // First assume we will NOT really do anything 1.78 + // (transaction will not be pushed on stack) 1.79 + mIsTransient = true; 1.80 + 1.81 + nsCOMPtr<nsIDOMNode>titleNode; 1.82 + if(titleList) 1.83 + { 1.84 + res = titleList->Item(0, getter_AddRefs(titleNode)); 1.85 + NS_ENSURE_SUCCESS(res, res); 1.86 + if (titleNode) 1.87 + { 1.88 + // Delete existing child textnode of title node 1.89 + // (Note: all contents under a TITLE node are always in a single text node) 1.90 + nsCOMPtr<nsIDOMNode> child; 1.91 + res = titleNode->GetFirstChild(getter_AddRefs(child)); 1.92 + if(NS_FAILED(res)) return res; 1.93 + if(child) 1.94 + { 1.95 + // Save current text as the undo value 1.96 + nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(child); 1.97 + if(textNode) 1.98 + { 1.99 + textNode->GetData(mUndoValue); 1.100 + 1.101 + // If title text is identical to what already exists, 1.102 + // quit now (mIsTransient is now TRUE) 1.103 + if (mUndoValue == aTitle) 1.104 + return NS_OK; 1.105 + } 1.106 + res = editor->DeleteNode(child); 1.107 + if(NS_FAILED(res)) return res; 1.108 + } 1.109 + } 1.110 + } 1.111 + 1.112 + // We didn't return above, thus we really will be changing the title 1.113 + mIsTransient = false; 1.114 + 1.115 + // Get the <HEAD> node, create a <TITLE> and insert it under the HEAD 1.116 + nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc); 1.117 + NS_ENSURE_STATE(document); 1.118 + 1.119 + dom::Element* head = document->GetHeadElement(); 1.120 + NS_ENSURE_STATE(head); 1.121 + 1.122 + bool newTitleNode = false; 1.123 + uint32_t newTitleIndex = 0; 1.124 + 1.125 + if (!titleNode) 1.126 + { 1.127 + // Didn't find one above: Create a new one 1.128 + nsCOMPtr<nsIDOMElement>titleElement; 1.129 + res = domDoc->CreateElement(NS_LITERAL_STRING("title"), getter_AddRefs(titleElement)); 1.130 + NS_ENSURE_SUCCESS(res, res); 1.131 + NS_ENSURE_TRUE(titleElement, NS_ERROR_FAILURE); 1.132 + 1.133 + titleNode = do_QueryInterface(titleElement); 1.134 + newTitleNode = true; 1.135 + 1.136 + // Get index so we append new title node after all existing HEAD children. 1.137 + newTitleIndex = head->GetChildCount(); 1.138 + } 1.139 + 1.140 + // Append a text node under the TITLE 1.141 + // only if the title text isn't empty 1.142 + if (titleNode && !aTitle.IsEmpty()) 1.143 + { 1.144 + nsCOMPtr<nsIDOMText> textNode; 1.145 + res = domDoc->CreateTextNode(aTitle, getter_AddRefs(textNode)); 1.146 + NS_ENSURE_SUCCESS(res, res); 1.147 + nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(textNode); 1.148 + NS_ENSURE_TRUE(newNode, NS_ERROR_FAILURE); 1.149 + 1.150 + if (newTitleNode) 1.151 + { 1.152 + // Not undoable: We will insert newTitleNode below 1.153 + nsCOMPtr<nsIDOMNode> resultNode; 1.154 + res = titleNode->AppendChild(newNode, getter_AddRefs(resultNode)); 1.155 + } 1.156 + else 1.157 + { 1.158 + // This is an undoable transaction 1.159 + res = editor->InsertNode(newNode, titleNode, 0); 1.160 + } 1.161 + NS_ENSURE_SUCCESS(res, res); 1.162 + } 1.163 + 1.164 + if (newTitleNode) 1.165 + { 1.166 + // Undoable transaction to insert title+text together 1.167 + res = editor->InsertNode(titleNode, head->AsDOMNode(), newTitleIndex); 1.168 + } 1.169 + return res; 1.170 +} 1.171 + 1.172 +NS_IMETHODIMP SetDocTitleTxn::GetTxnDescription(nsAString& aString) 1.173 +{ 1.174 + aString.AssignLiteral("SetDocTitleTxn: "); 1.175 + aString += mValue; 1.176 + return NS_OK; 1.177 +} 1.178 + 1.179 +NS_IMETHODIMP SetDocTitleTxn::GetIsTransient(bool *aIsTransient) 1.180 +{ 1.181 + NS_ENSURE_TRUE(aIsTransient, NS_ERROR_NULL_POINTER); 1.182 + *aIsTransient = mIsTransient; 1.183 + return NS_OK; 1.184 +} 1.185 +