editor/libeditor/base/SetDocTitleTxn.cpp

changeset 0
6474c204b198
     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 +

mercurial