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 #ifndef JoinNodesTransaction_h
7 #define JoinNodesTransaction_h
8 
9 #include "EditTransactionBase.h"  // for EditTransactionBase, etc.
10 
11 #include "EditorDOMPoint.h"  // for EditorDOMPoint, etc.
12 
13 #include "nsCOMPtr.h"  // for nsCOMPtr
14 #include "nsCycleCollectionParticipant.h"
15 #include "nsID.h"    // for REFNSIID
16 #include "nscore.h"  // for NS_IMETHOD
17 
18 class nsIContent;
19 class nsINode;
20 
21 namespace mozilla {
22 
23 class HTMLEditor;
24 
25 /**
26  * A transaction that joins two nodes E1 (left node) and E2 (right node) into a
27  * single node E.  The children of E are the children of E1 followed by the
28  * children of E2.  After DoTransaction() and RedoTransaction(), E1 is removed
29  * from the content tree and E2 remains.
30  */
31 class JoinNodesTransaction final : public EditTransactionBase {
32  protected:
33   JoinNodesTransaction(HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
34                        nsIContent& aRightContent);
35 
36  public:
37   /**
38    * Creates a join node transaction.  This returns nullptr if cannot join the
39    * nodes.
40    *
41    * @param aHTMLEditor     The provider of core editing operations.
42    * @param aLeftContent    The first of two nodes to join.
43    * @param aRightContent   The second of two nodes to join.
44    */
45   static already_AddRefed<JoinNodesTransaction> MaybeCreate(
46       HTMLEditor& aHTMLEditor, nsIContent& aLeftContent,
47       nsIContent& aRightContent);
48 
49   /**
50    * CanDoIt() returns true if there are enough members and can join or
51    * restore the nodes.  Otherwise, false.
52    */
53   bool CanDoIt() const;
54 
55   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(JoinNodesTransaction,
56                                            EditTransactionBase)
57   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
58 
59   NS_DECL_EDITTRANSACTIONBASE
60   NS_DECL_EDITTRANSACTIONBASE_GETASMETHODS_OVERRIDE(JoinNodesTransaction)
61 
62   MOZ_CAN_RUN_SCRIPT NS_IMETHOD RedoTransaction() override;
63 
64   /**
65    * GetExistingContent() and GetRemovedContent() never returns nullptr
66    * unless the cycle collector clears them out.
67    */
GetExistingContent()68   nsIContent* GetExistingContent() const { return mKeepingContent; }
GetRemovedContent()69   nsIContent* GetRemovedContent() const { return mRemovedContent; }
GetParentNode()70   nsINode* GetParentNode() const { return mParentNode; }
71 
72   template <typename EditorDOMPointType>
CreateJoinedPoint()73   EditorDOMPointType CreateJoinedPoint() const {
74     if (MOZ_UNLIKELY(!mKeepingContent)) {
75       return EditorDOMPointType();
76     }
77     return EditorDOMPointType(
78         mKeepingContent, std::min(mJoinedOffset, mKeepingContent->Length()));
79   }
80 
81   friend std::ostream& operator<<(std::ostream& aStream,
82                                   const JoinNodesTransaction& aTransaction);
83 
84  protected:
85   virtual ~JoinNodesTransaction() = default;
86 
87   enum class RedoingTransaction { No, Yes };
88   MOZ_CAN_RUN_SCRIPT nsresult DoTransactionInternal(RedoingTransaction);
89 
90   RefPtr<HTMLEditor> mHTMLEditor;
91 
92   // The original parent of the left/right nodes.
93   nsCOMPtr<nsINode> mParentNode;
94 
95   // Removed content after joined.
96   nsCOMPtr<nsIContent> mRemovedContent;
97 
98   // The keeping content node which contains ex-children of mRemovedContent.
99   nsCOMPtr<nsIContent> mKeepingContent;
100 
101   // Offset where the original first content is in mKeepingContent after
102   // doing or redoing.
103   uint32_t mJoinedOffset = 0u;
104 };
105 
106 }  // namespace mozilla
107 
108 #endif  // #ifndef JoinNodesTransaction_h
109