Line data Source code
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 :
17 : #include "nsAlgorithm.h"
18 : #include "nsAString.h"
19 : #include "nsDebug.h"
20 : #include "nsError.h"
21 : #include "nsIContent.h"
22 : #include "nsIEditor.h"
23 : #include "nsINode.h"
24 : #include "nsISupportsUtils.h"
25 : #include "nsMemory.h"
26 : #include "nsReadableUtils.h"
27 : #include "nsStringFwd.h"
28 : #include "nsString.h"
29 :
30 : namespace mozilla {
31 :
32 : using namespace dom;
33 :
34 0 : CreateElementTransaction::CreateElementTransaction(EditorBase& aEditorBase,
35 : nsIAtom& aTag,
36 : nsINode& aParent,
37 0 : int32_t aOffsetInParent)
38 : : EditTransactionBase()
39 : , mEditorBase(&aEditorBase)
40 : , mTag(&aTag)
41 : , mParent(&aParent)
42 0 : , mOffsetInParent(aOffsetInParent)
43 : {
44 0 : }
45 :
46 0 : CreateElementTransaction::~CreateElementTransaction()
47 : {
48 0 : }
49 :
50 0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(CreateElementTransaction,
51 : EditTransactionBase,
52 : mEditorBase,
53 : mParent,
54 : mNewNode,
55 : mRefNode)
56 :
57 0 : NS_IMPL_ADDREF_INHERITED(CreateElementTransaction, EditTransactionBase)
58 0 : NS_IMPL_RELEASE_INHERITED(CreateElementTransaction, EditTransactionBase)
59 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CreateElementTransaction)
60 0 : NS_INTERFACE_MAP_END_INHERITING(EditTransactionBase)
61 :
62 :
63 : NS_IMETHODIMP
64 0 : CreateElementTransaction::DoTransaction()
65 : {
66 0 : if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mTag) || NS_WARN_IF(!mParent)) {
67 0 : return NS_ERROR_NOT_INITIALIZED;
68 : }
69 :
70 0 : mNewNode = mEditorBase->CreateHTMLContent(mTag);
71 0 : NS_ENSURE_STATE(mNewNode);
72 :
73 : // Try to insert formatting whitespace for the new node:
74 0 : mEditorBase->MarkNodeDirty(GetAsDOMNode(mNewNode));
75 :
76 : // Insert the new node
77 0 : ErrorResult rv;
78 0 : if (mOffsetInParent == -1) {
79 0 : mParent->AppendChild(*mNewNode, rv);
80 0 : return rv.StealNSResult();
81 : }
82 :
83 0 : mOffsetInParent = std::min(mOffsetInParent,
84 0 : static_cast<int32_t>(mParent->GetChildCount()));
85 :
86 : // Note, it's ok for mRefNode to be null. That means append
87 0 : mRefNode = mParent->GetChildAt(mOffsetInParent);
88 :
89 0 : nsCOMPtr<nsIContent> refNode = mRefNode;
90 0 : mParent->InsertBefore(*mNewNode, refNode, rv);
91 0 : NS_ENSURE_TRUE(!rv.Failed(), rv.StealNSResult());
92 :
93 : // Only set selection to insertion point if editor gives permission
94 0 : if (!mEditorBase->GetShouldTxnSetSelection()) {
95 : // Do nothing - DOM range gravity will adjust selection
96 0 : return NS_OK;
97 : }
98 :
99 0 : RefPtr<Selection> selection = mEditorBase->GetSelection();
100 0 : NS_ENSURE_TRUE(selection, NS_ERROR_NULL_POINTER);
101 :
102 0 : rv = selection->Collapse(mParent, mParent->IndexOf(mNewNode) + 1);
103 0 : NS_ASSERTION(!rv.Failed(),
104 : "selection could not be collapsed after insert");
105 0 : return NS_OK;
106 : }
107 :
108 : NS_IMETHODIMP
109 0 : CreateElementTransaction::UndoTransaction()
110 : {
111 0 : if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
112 0 : return NS_ERROR_NOT_INITIALIZED;
113 : }
114 :
115 0 : ErrorResult rv;
116 0 : mParent->RemoveChild(*mNewNode, rv);
117 :
118 0 : return rv.StealNSResult();
119 : }
120 :
121 : NS_IMETHODIMP
122 0 : CreateElementTransaction::RedoTransaction()
123 : {
124 0 : if (NS_WARN_IF(!mEditorBase) || NS_WARN_IF(!mParent)) {
125 0 : return NS_ERROR_NOT_INITIALIZED;
126 : }
127 :
128 : // First, reset mNewNode so it has no attributes or content
129 : // XXX We never actually did this, we only cleared mNewNode's contents if it
130 : // was a CharacterData node (which it's not, it's an Element)
131 :
132 : // Now, reinsert mNewNode
133 0 : ErrorResult rv;
134 0 : nsCOMPtr<nsIContent> refNode = mRefNode;
135 0 : mParent->InsertBefore(*mNewNode, refNode, rv);
136 0 : return rv.StealNSResult();
137 : }
138 :
139 : NS_IMETHODIMP
140 0 : CreateElementTransaction::GetTxnDescription(nsAString& aString)
141 : {
142 0 : aString.AssignLiteral("CreateElementTransaction: ");
143 0 : aString += nsDependentAtomString(mTag);
144 0 : return NS_OK;
145 : }
146 :
147 : already_AddRefed<Element>
148 0 : CreateElementTransaction::GetNewNode()
149 : {
150 0 : return nsCOMPtr<Element>(mNewNode).forget();
151 : }
152 :
153 : } // namespace mozilla
|