Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/editor/libeditor/CreateElementTransaction.cpp
Line
Count
Source (jump to first uncovered line)
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 "CreateElementTransaction.h"
7
8
#include <algorithm>
9
#include <stdio.h>
10
11
#include "mozilla/dom/Element.h"
12
#include "mozilla/dom/Selection.h"
13
14
#include "mozilla/Casting.h"
15
#include "mozilla/EditorBase.h"
16
#include "mozilla/EditorDOMPoint.h"
17
18
#include "nsAlgorithm.h"
19
#include "nsAString.h"
20
#include "nsDebug.h"
21
#include "nsError.h"
22
#include "nsIContent.h"
23
#include "nsIEditor.h"
24
#include "nsINode.h"
25
#include "nsISupportsUtils.h"
26
#include "nsMemory.h"
27
#include "nsReadableUtils.h"
28
#include "nsStringFwd.h"
29
#include "nsString.h"
30
31
namespace mozilla {
32
33
using namespace dom;
34
35
template already_AddRefed<CreateElementTransaction>
36
CreateElementTransaction::Create(
37
                            EditorBase& aEditorBase,
38
                            nsAtom& aTag,
39
                            const EditorDOMPoint& aPointToInsert);
40
template already_AddRefed<CreateElementTransaction>
41
CreateElementTransaction::Create(
42
                            EditorBase& aEditorBase,
43
                            nsAtom& aTag,
44
                            const EditorRawDOMPoint& aPointToInsert);
45
46
template<typename PT, typename CT>
47
already_AddRefed<CreateElementTransaction>
48
CreateElementTransaction::Create(
49
                            EditorBase& aEditorBase,
50
                            nsAtom& aTag,
51
                            const EditorDOMPointBase<PT, CT>& aPointToInsert)
52
0
{
53
0
  RefPtr<CreateElementTransaction> transaction =
54
0
    new CreateElementTransaction(aEditorBase, aTag, aPointToInsert);
55
0
  return transaction.forget();
56
0
}
Unexecuted instantiation: already_AddRefed<mozilla::CreateElementTransaction> mozilla::CreateElementTransaction::Create<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorBase&, nsAtom&, mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&)
Unexecuted instantiation: already_AddRefed<mozilla::CreateElementTransaction> mozilla::CreateElementTransaction::Create<nsINode*, nsIContent*>(mozilla::EditorBase&, nsAtom&, mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&)
57
58
template<typename PT, typename CT>
59
CreateElementTransaction::CreateElementTransaction(
60
                            EditorBase& aEditorBase,
61
                            nsAtom& aTag,
62
                            const EditorDOMPointBase<PT, CT>& aPointToInsert)
63
  : EditTransactionBase()
64
  , mEditorBase(&aEditorBase)
65
  , mTag(&aTag)
66
  , mPointToInsert(aPointToInsert)
67
0
{
68
0
}
Unexecuted instantiation: mozilla::CreateElementTransaction::CreateElementTransaction<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> >(mozilla::EditorBase&, nsAtom&, mozilla::EditorDOMPointBase<nsCOMPtr<nsINode>, nsCOMPtr<nsIContent> > const&)
Unexecuted instantiation: mozilla::CreateElementTransaction::CreateElementTransaction<nsINode*, nsIContent*>(mozilla::EditorBase&, nsAtom&, mozilla::EditorDOMPointBase<nsINode*, nsIContent*> const&)
69
70
CreateElementTransaction::~CreateElementTransaction()
71
0
{
72
0
}
73
74
NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
75
                                   EditTransactionBase,
76
                                   mEditorBase,
77
                                   mPointToInsert,
78
                                   mNewNode)
79
80
NS_IMPL_ADDREF_INHERITED(CreateElementTransaction, EditTransactionBase)
81
NS_IMPL_RELEASE_INHERITED(CreateElementTransaction, EditTransactionBase)
82
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CreateElementTransaction)
83
0
NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
84
85
86
NS_IMETHODIMP
87
CreateElementTransaction::DoTransaction()
88
0
{
89
0
  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) ||
90
0
      NS_WARN_IF(!mPointToInsert.IsSet())) {
91
0
    return NS_ERROR_NOT_INITIALIZED;
92
0
  }
93
0
94
0
  mNewNode = mEditorBase->CreateHTMLContent(mTag);
95
0
  NS_ENSURE_STATE(mNewNode);
96
0
97
0
  // Try to insert formatting whitespace for the new node:
98
0
  mEditorBase->MarkNodeDirty(mNewNode);
99
0
100
0
  // Insert the new node
101
0
  ErrorResult error;
102
0
  InsertNewNode(error);
103
0
  if (NS_WARN_IF(error.Failed())) {
104
0
    return error.StealNSResult();
105
0
  }
106
0
107
0
  // Only set selection to insertion point if editor gives permission
108
0
  if (!mEditorBase->AllowsTransactionsToChangeSelection()) {
109
0
    // Do nothing - DOM range gravity will adjust selection
110
0
    return NS_OK;
111
0
  }
112
0
113
0
  RefPtr<Selection> selection = mEditorBase->GetSelection();
114
0
  NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
115
0
116
0
  EditorRawDOMPoint afterNewNode(mNewNode);
117
0
  if (NS_WARN_IF(!afterNewNode.AdvanceOffset())) {
118
0
    // If mutation observer or mutation event listener moved or removed the
119
0
    // new node, we hit this case.  Should we use script blocker while we're
120
0
    // in this method?
121
0
    return NS_ERROR_FAILURE;
122
0
  }
123
0
  selection->Collapse(afterNewNode, error);
124
0
  if (error.Failed()) {
125
0
    NS_WARNING("selection could not be collapsed after insert");
126
0
    error.SuppressException();
127
0
  }
128
0
  return NS_OK;
129
0
}
130
131
void
132
CreateElementTransaction::InsertNewNode(ErrorResult& aError)
133
0
{
134
0
  if (mPointToInsert.IsSetAndValid()) {
135
0
    if (mPointToInsert.IsEndOfContainer()) {
136
0
      mPointToInsert.GetContainer()->AppendChild(*mNewNode, aError);
137
0
      NS_WARNING_ASSERTION(!aError.Failed(), "Failed to append the new node");
138
0
      return;
139
0
    }
140
0
    mPointToInsert.GetContainer()->
141
0
                     InsertBefore(*mNewNode,
142
0
                                  mPointToInsert.GetChild(),
143
0
                                  aError);
144
0
    NS_WARNING_ASSERTION(!aError.Failed(), "Failed to insert the new node");
145
0
    return;
146
0
  }
147
0
148
0
  if (NS_WARN_IF(mPointToInsert.GetChild() &&
149
0
                 mPointToInsert.GetContainer() !=
150
0
                   mPointToInsert.GetChild()->GetParentNode())) {
151
0
    aError.Throw(NS_ERROR_FAILURE);
152
0
    return;
153
0
  }
154
0
155
0
  // If mPointToInsert has only offset and it's not valid, we need to treat
156
0
  // it as pointing end of the container.
157
0
  mPointToInsert.GetContainer()->AppendChild(*mNewNode, aError);
158
0
  NS_WARNING_ASSERTION(!aError.Failed(), "Failed to append the new node");
159
0
}
160
161
NS_IMETHODIMP
162
CreateElementTransaction::UndoTransaction()
163
0
{
164
0
  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet())) {
165
0
    return NS_ERROR_NOT_INITIALIZED;
166
0
  }
167
0
168
0
  ErrorResult error;
169
0
  mPointToInsert.GetContainer()->RemoveChild(*mNewNode, error);
170
0
  if (NS_WARN_IF(error.Failed())) {
171
0
    return error.StealNSResult();
172
0
  }
173
0
  return NS_OK;
174
0
}
175
176
NS_IMETHODIMP
177
CreateElementTransaction::RedoTransaction()
178
0
{
179
0
  if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mPointToInsert.IsSet())) {
180
0
    return NS_ERROR_NOT_INITIALIZED;
181
0
  }
182
0
183
0
  // First, reset mNewNode so it has no attributes or content
184
0
  // XXX We never actually did this, we only cleared mNewNode's contents if it
185
0
  // was a CharacterData node (which it's not, it's an Element)
186
0
  // XXX Don't we need to set selection like DoTransaction()?
187
0
188
0
  // Now, reinsert mNewNode
189
0
  ErrorResult error;
190
0
  InsertNewNode(error);
191
0
  if (NS_WARN_IF(error.Failed())) {
192
0
    return error.StealNSResult();
193
0
  }
194
0
  return NS_OK;
195
0
}
196
197
already_AddRefed<Element>
198
CreateElementTransaction::GetNewNode()
199
0
{
200
0
  return nsCOMPtr<Element>(mNewNode).forget();
201
0
}
202
203
} // namespace mozilla