1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/dom/Element.h"
10 #include "nsHTMLEditUtils.h"
11 #include "nsHTMLEditor.h"
12 #include "nsIContent.h"
13 #include "nsIDOMElement.h"
14 #include "nsIDOMEventTarget.h"
15 #include "nsIDOMHTMLElement.h"
16 #include "nsIDOMNode.h"
17 #include "nsIHTMLEditor.h"
18 #include "nsIHTMLObjectResizer.h"
19 #include "nsIPresShell.h"
20 #include "nsLiteralString.h"
21 #include "nsReadableUtils.h"
25 // Uncomment the following line if you want to disable
26 // table deletion when the only column/row is removed
27 // #define DISABLE_TABLE_DELETION 1
30 nsHTMLEditor::SetInlineTableEditingEnabled(bool aIsEnabled
)
32 mIsInlineTableEditingEnabled
= aIsEnabled
;
37 nsHTMLEditor::GetInlineTableEditingEnabled(bool * aIsEnabled
)
39 *aIsEnabled
= mIsInlineTableEditingEnabled
;
44 nsHTMLEditor::ShowInlineTableEditingUI(nsIDOMElement
* aCell
)
46 NS_ENSURE_ARG_POINTER(aCell
);
48 // do nothing if aCell is not a table cell...
49 if (!nsHTMLEditUtils::IsTableCell(aCell
))
52 if (mInlineEditedCell
) {
53 NS_ERROR("call HideInlineTableEditingUI first");
54 return NS_ERROR_UNEXPECTED
;
57 // the resizers and the shadow will be anonymous children of the body
58 nsCOMPtr
<nsIDOMElement
> bodyElement
= do_QueryInterface(GetRoot());
59 NS_ENSURE_TRUE(bodyElement
, NS_ERROR_NULL_POINTER
);
61 CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement
,
62 NS_LITERAL_STRING("mozTableAddColumnBefore"),
63 false, getter_AddRefs(mAddColumnBeforeButton
));
64 CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement
,
65 NS_LITERAL_STRING("mozTableRemoveColumn"),
66 false, getter_AddRefs(mRemoveColumnButton
));
67 CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement
,
68 NS_LITERAL_STRING("mozTableAddColumnAfter"),
69 false, getter_AddRefs(mAddColumnAfterButton
));
71 CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement
,
72 NS_LITERAL_STRING("mozTableAddRowBefore"),
73 false, getter_AddRefs(mAddRowBeforeButton
));
74 CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement
,
75 NS_LITERAL_STRING("mozTableRemoveRow"),
76 false, getter_AddRefs(mRemoveRowButton
));
77 CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement
,
78 NS_LITERAL_STRING("mozTableAddRowAfter"),
79 false, getter_AddRefs(mAddRowAfterButton
));
81 AddMouseClickListener(mAddColumnBeforeButton
);
82 AddMouseClickListener(mRemoveColumnButton
);
83 AddMouseClickListener(mAddColumnAfterButton
);
84 AddMouseClickListener(mAddRowBeforeButton
);
85 AddMouseClickListener(mRemoveRowButton
);
86 AddMouseClickListener(mAddRowAfterButton
);
88 mInlineEditedCell
= aCell
;
89 return RefreshInlineTableEditingUI();
93 nsHTMLEditor::HideInlineTableEditingUI()
95 mInlineEditedCell
= nullptr;
97 RemoveMouseClickListener(mAddColumnBeforeButton
);
98 RemoveMouseClickListener(mRemoveColumnButton
);
99 RemoveMouseClickListener(mAddColumnAfterButton
);
100 RemoveMouseClickListener(mAddRowBeforeButton
);
101 RemoveMouseClickListener(mRemoveRowButton
);
102 RemoveMouseClickListener(mAddRowAfterButton
);
104 // get the presshell's document observer interface.
105 nsCOMPtr
<nsIPresShell
> ps
= GetPresShell();
106 // We allow the pres shell to be null; when it is, we presume there
107 // are no document observers to notify, but we still want to
110 // get the root content node.
111 nsCOMPtr
<nsIContent
> bodyContent
= GetRoot();
112 NS_ENSURE_TRUE(bodyContent
, NS_ERROR_FAILURE
);
114 DeleteRefToAnonymousNode(mAddColumnBeforeButton
, bodyContent
, ps
);
115 mAddColumnBeforeButton
= nullptr;
116 DeleteRefToAnonymousNode(mRemoveColumnButton
, bodyContent
, ps
);
117 mRemoveColumnButton
= nullptr;
118 DeleteRefToAnonymousNode(mAddColumnAfterButton
, bodyContent
, ps
);
119 mAddColumnAfterButton
= nullptr;
120 DeleteRefToAnonymousNode(mAddRowBeforeButton
, bodyContent
, ps
);
121 mAddRowBeforeButton
= nullptr;
122 DeleteRefToAnonymousNode(mRemoveRowButton
, bodyContent
, ps
);
123 mRemoveRowButton
= nullptr;
124 DeleteRefToAnonymousNode(mAddRowAfterButton
, bodyContent
, ps
);
125 mAddRowAfterButton
= nullptr;
131 nsHTMLEditor::DoInlineTableEditingAction(nsIDOMElement
* aElement
)
133 NS_ENSURE_ARG_POINTER(aElement
);
134 bool anonElement
= false;
136 NS_SUCCEEDED(aElement
->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement
)) &&
138 nsAutoString anonclass
;
139 nsresult res
= aElement
->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass
);
140 NS_ENSURE_SUCCESS(res
, res
);
142 if (!StringBeginsWith(anonclass
, NS_LITERAL_STRING("mozTable")))
145 nsCOMPtr
<nsIDOMNode
> tableNode
= GetEnclosingTable(mInlineEditedCell
);
146 nsCOMPtr
<nsIDOMElement
> tableElement
= do_QueryInterface(tableNode
);
147 int32_t rowCount
, colCount
;
148 res
= GetTableSize(tableElement
, &rowCount
, &colCount
);
149 NS_ENSURE_SUCCESS(res
, res
);
152 bool hideResizersWithInlineTableUI
= (mResizedObject
== tableElement
);
154 if (anonclass
.EqualsLiteral("mozTableAddColumnBefore"))
155 InsertTableColumn(1, false);
156 else if (anonclass
.EqualsLiteral("mozTableAddColumnAfter"))
157 InsertTableColumn(1, true);
158 else if (anonclass
.EqualsLiteral("mozTableAddRowBefore"))
159 InsertTableRow(1, false);
160 else if (anonclass
.EqualsLiteral("mozTableAddRowAfter"))
161 InsertTableRow(1, true);
162 else if (anonclass
.EqualsLiteral("mozTableRemoveColumn")) {
163 DeleteTableColumn(1);
164 #ifndef DISABLE_TABLE_DELETION
165 hideUI
= (colCount
== 1);
168 else if (anonclass
.EqualsLiteral("mozTableRemoveRow")) {
170 #ifndef DISABLE_TABLE_DELETION
171 hideUI
= (rowCount
== 1);
178 HideInlineTableEditingUI();
179 if (hideResizersWithInlineTableUI
)
188 nsHTMLEditor::AddMouseClickListener(nsIDOMElement
* aElement
)
190 nsCOMPtr
<nsIDOMEventTarget
> evtTarget(do_QueryInterface(aElement
));
192 evtTarget
->AddEventListener(NS_LITERAL_STRING("click"),
193 mEventListener
, true);
198 nsHTMLEditor::RemoveMouseClickListener(nsIDOMElement
* aElement
)
200 nsCOMPtr
<nsIDOMEventTarget
> evtTarget(do_QueryInterface(aElement
));
202 evtTarget
->RemoveEventListener(NS_LITERAL_STRING("click"),
203 mEventListener
, true);
208 nsHTMLEditor::RefreshInlineTableEditingUI()
210 nsCOMPtr
<nsIDOMHTMLElement
> htmlElement
= do_QueryInterface(mInlineEditedCell
);
212 return NS_ERROR_NULL_POINTER
;
215 int32_t xCell
, yCell
, wCell
, hCell
;
216 GetElementOrigin(mInlineEditedCell
, xCell
, yCell
);
218 nsresult res
= htmlElement
->GetOffsetWidth(&wCell
);
219 NS_ENSURE_SUCCESS(res
, res
);
220 res
= htmlElement
->GetOffsetHeight(&hCell
);
221 NS_ENSURE_SUCCESS(res
, res
);
223 int32_t xHoriz
= xCell
+ wCell
/2;
224 int32_t yVert
= yCell
+ hCell
/2;
226 nsCOMPtr
<nsIDOMNode
> tableNode
= GetEnclosingTable(mInlineEditedCell
);
227 nsCOMPtr
<nsIDOMElement
> tableElement
= do_QueryInterface(tableNode
);
228 int32_t rowCount
, colCount
;
229 res
= GetTableSize(tableElement
, &rowCount
, &colCount
);
230 NS_ENSURE_SUCCESS(res
, res
);
232 SetAnonymousElementPosition(xHoriz
-10, yCell
-7, mAddColumnBeforeButton
);
233 #ifdef DISABLE_TABLE_DELETION
234 NS_NAMED_LITERAL_STRING(classStr
, "class");
237 mRemoveColumnButton
->SetAttribute(classStr
,
238 NS_LITERAL_STRING("hidden"));
241 bool hasClass
= false;
242 res
= mRemoveColumnButton
->HasAttribute(classStr
, &hasClass
);
243 if (NS_SUCCEEDED(res
) && hasClass
)
244 mRemoveColumnButton
->RemoveAttribute(classStr
);
246 SetAnonymousElementPosition(xHoriz
-4, yCell
-7, mRemoveColumnButton
);
247 #ifdef DISABLE_TABLE_DELETION
250 SetAnonymousElementPosition(xHoriz
+6, yCell
-7, mAddColumnAfterButton
);
252 SetAnonymousElementPosition(xCell
-7, yVert
-10, mAddRowBeforeButton
);
253 #ifdef DISABLE_TABLE_DELETION
255 mRemoveRowButton
->SetAttribute(classStr
,
256 NS_LITERAL_STRING("hidden"));
259 bool hasClass
= false;
260 res
= mRemoveRowButton
->HasAttribute(classStr
, &hasClass
);
261 if (NS_SUCCEEDED(res
) && hasClass
)
262 mRemoveRowButton
->RemoveAttribute(classStr
);
264 SetAnonymousElementPosition(xCell
-7, yVert
-4, mRemoveRowButton
);
265 #ifdef DISABLE_TABLE_DELETION
268 SetAnonymousElementPosition(xCell
-7, yVert
+6, mAddRowAfterButton
);