Line data Source code
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/. */
4 :
5 : #include "mozilla/HTMLEditor.h"
6 :
7 : #include "HTMLEditUtils.h"
8 : #include "mozilla/dom/Element.h"
9 : #include "nsAString.h"
10 : #include "nsCOMPtr.h"
11 : #include "nsDebug.h"
12 : #include "nsError.h"
13 : #include "nsIContent.h"
14 : #include "nsIDOMElement.h"
15 : #include "nsIDOMEventTarget.h"
16 : #include "nsIDOMHTMLElement.h"
17 : #include "nsIDOMNode.h"
18 : #include "nsIHTMLObjectResizer.h"
19 : #include "nsIPresShell.h"
20 : #include "nsLiteralString.h"
21 : #include "nsReadableUtils.h"
22 : #include "nsString.h"
23 : #include "nscore.h"
24 :
25 : namespace mozilla {
26 :
27 : // Uncomment the following line if you want to disable
28 : // table deletion when the only column/row is removed
29 : // #define DISABLE_TABLE_DELETION 1
30 :
31 : NS_IMETHODIMP
32 0 : HTMLEditor::SetInlineTableEditingEnabled(bool aIsEnabled)
33 : {
34 0 : mIsInlineTableEditingEnabled = aIsEnabled;
35 0 : return NS_OK;
36 : }
37 :
38 : NS_IMETHODIMP
39 0 : HTMLEditor::GetInlineTableEditingEnabled(bool* aIsEnabled)
40 : {
41 0 : *aIsEnabled = mIsInlineTableEditingEnabled;
42 0 : return NS_OK;
43 : }
44 :
45 : NS_IMETHODIMP
46 0 : HTMLEditor::ShowInlineTableEditingUI(nsIDOMElement* aCell)
47 : {
48 0 : NS_ENSURE_ARG_POINTER(aCell);
49 :
50 : // do nothing if aCell is not a table cell...
51 0 : if (!HTMLEditUtils::IsTableCell(aCell)) {
52 0 : return NS_OK;
53 : }
54 :
55 0 : if (mInlineEditedCell) {
56 0 : NS_ERROR("call HideInlineTableEditingUI first");
57 0 : return NS_ERROR_UNEXPECTED;
58 : }
59 :
60 : // the resizers and the shadow will be anonymous children of the body
61 0 : nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
62 0 : NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
63 :
64 : mAddColumnBeforeButton =
65 0 : CreateAnonymousElement(nsGkAtoms::a, bodyElement,
66 0 : NS_LITERAL_STRING("mozTableAddColumnBefore"), false);
67 : mRemoveColumnButton =
68 0 : CreateAnonymousElement(nsGkAtoms::a, bodyElement,
69 0 : NS_LITERAL_STRING("mozTableRemoveColumn"), false);
70 : mAddColumnAfterButton =
71 0 : CreateAnonymousElement(nsGkAtoms::a, bodyElement,
72 0 : NS_LITERAL_STRING("mozTableAddColumnAfter"), false);
73 :
74 : mAddRowBeforeButton =
75 0 : CreateAnonymousElement(nsGkAtoms::a, bodyElement,
76 0 : NS_LITERAL_STRING("mozTableAddRowBefore"), false);
77 : mRemoveRowButton =
78 0 : CreateAnonymousElement(nsGkAtoms::a, bodyElement,
79 0 : NS_LITERAL_STRING("mozTableRemoveRow"), false);
80 : mAddRowAfterButton =
81 0 : CreateAnonymousElement(nsGkAtoms::a, bodyElement,
82 0 : NS_LITERAL_STRING("mozTableAddRowAfter"), false);
83 :
84 0 : AddMouseClickListener(mAddColumnBeforeButton);
85 0 : AddMouseClickListener(mRemoveColumnButton);
86 0 : AddMouseClickListener(mAddColumnAfterButton);
87 0 : AddMouseClickListener(mAddRowBeforeButton);
88 0 : AddMouseClickListener(mRemoveRowButton);
89 0 : AddMouseClickListener(mAddRowAfterButton);
90 :
91 0 : mInlineEditedCell = aCell;
92 0 : return RefreshInlineTableEditingUI();
93 : }
94 :
95 : NS_IMETHODIMP
96 0 : HTMLEditor::HideInlineTableEditingUI()
97 : {
98 0 : mInlineEditedCell = nullptr;
99 :
100 0 : RemoveMouseClickListener(mAddColumnBeforeButton);
101 0 : RemoveMouseClickListener(mRemoveColumnButton);
102 0 : RemoveMouseClickListener(mAddColumnAfterButton);
103 0 : RemoveMouseClickListener(mAddRowBeforeButton);
104 0 : RemoveMouseClickListener(mRemoveRowButton);
105 0 : RemoveMouseClickListener(mAddRowAfterButton);
106 :
107 : // get the presshell's document observer interface.
108 0 : nsCOMPtr<nsIPresShell> ps = GetPresShell();
109 : // We allow the pres shell to be null; when it is, we presume there
110 : // are no document observers to notify, but we still want to
111 : // UnbindFromTree.
112 :
113 0 : DeleteRefToAnonymousNode(mAddColumnBeforeButton, ps);
114 0 : mAddColumnBeforeButton = nullptr;
115 0 : DeleteRefToAnonymousNode(mRemoveColumnButton, ps);
116 0 : mRemoveColumnButton = nullptr;
117 0 : DeleteRefToAnonymousNode(mAddColumnAfterButton, ps);
118 0 : mAddColumnAfterButton = nullptr;
119 0 : DeleteRefToAnonymousNode(mAddRowBeforeButton, ps);
120 0 : mAddRowBeforeButton = nullptr;
121 0 : DeleteRefToAnonymousNode(mRemoveRowButton, ps);
122 0 : mRemoveRowButton = nullptr;
123 0 : DeleteRefToAnonymousNode(mAddRowAfterButton, ps);
124 0 : mAddRowAfterButton = nullptr;
125 :
126 0 : return NS_OK;
127 : }
128 :
129 : NS_IMETHODIMP
130 0 : HTMLEditor::DoInlineTableEditingAction(nsIDOMElement* aElement)
131 : {
132 0 : NS_ENSURE_ARG_POINTER(aElement);
133 0 : bool anonElement = false;
134 0 : if (aElement &&
135 0 : NS_SUCCEEDED(aElement->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement)) &&
136 : anonElement) {
137 0 : nsAutoString anonclass;
138 : nsresult rv =
139 0 : aElement->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass);
140 0 : NS_ENSURE_SUCCESS(rv, rv);
141 :
142 0 : if (!StringBeginsWith(anonclass, NS_LITERAL_STRING("mozTable")))
143 0 : return NS_OK;
144 :
145 0 : nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(mInlineEditedCell);
146 0 : nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode);
147 : int32_t rowCount, colCount;
148 0 : rv = GetTableSize(tableElement, &rowCount, &colCount);
149 0 : NS_ENSURE_SUCCESS(rv, rv);
150 :
151 0 : bool hideUI = false;
152 0 : bool hideResizersWithInlineTableUI = (GetAsDOMNode(mResizedObject) == tableElement);
153 :
154 0 : if (anonclass.EqualsLiteral("mozTableAddColumnBefore"))
155 0 : InsertTableColumn(1, false);
156 0 : else if (anonclass.EqualsLiteral("mozTableAddColumnAfter"))
157 0 : InsertTableColumn(1, true);
158 0 : else if (anonclass.EqualsLiteral("mozTableAddRowBefore"))
159 0 : InsertTableRow(1, false);
160 0 : else if (anonclass.EqualsLiteral("mozTableAddRowAfter"))
161 0 : InsertTableRow(1, true);
162 0 : else if (anonclass.EqualsLiteral("mozTableRemoveColumn")) {
163 0 : DeleteTableColumn(1);
164 : #ifndef DISABLE_TABLE_DELETION
165 0 : hideUI = (colCount == 1);
166 : #endif
167 : }
168 0 : else if (anonclass.EqualsLiteral("mozTableRemoveRow")) {
169 0 : DeleteTableRow(1);
170 : #ifndef DISABLE_TABLE_DELETION
171 0 : hideUI = (rowCount == 1);
172 : #endif
173 : }
174 : else
175 0 : return NS_OK;
176 :
177 0 : if (hideUI) {
178 0 : HideInlineTableEditingUI();
179 0 : if (hideResizersWithInlineTableUI)
180 0 : HideResizers();
181 : }
182 : }
183 :
184 0 : return NS_OK;
185 : }
186 :
187 : void
188 0 : HTMLEditor::AddMouseClickListener(Element* aElement)
189 : {
190 0 : nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
191 0 : if (evtTarget) {
192 0 : evtTarget->AddEventListener(NS_LITERAL_STRING("click"),
193 0 : mEventListener, true);
194 : }
195 0 : }
196 :
197 : void
198 0 : HTMLEditor::RemoveMouseClickListener(Element* aElement)
199 : {
200 0 : nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
201 0 : if (evtTarget) {
202 0 : evtTarget->RemoveEventListener(NS_LITERAL_STRING("click"),
203 0 : mEventListener, true);
204 : }
205 0 : }
206 :
207 : NS_IMETHODIMP
208 0 : HTMLEditor::RefreshInlineTableEditingUI()
209 : {
210 0 : nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mInlineEditedCell);
211 0 : if (!htmlElement) {
212 0 : return NS_ERROR_NULL_POINTER;
213 : }
214 :
215 : int32_t xCell, yCell, wCell, hCell;
216 0 : GetElementOrigin(mInlineEditedCell, xCell, yCell);
217 :
218 0 : nsresult rv = htmlElement->GetOffsetWidth(&wCell);
219 0 : NS_ENSURE_SUCCESS(rv, rv);
220 0 : rv = htmlElement->GetOffsetHeight(&hCell);
221 0 : NS_ENSURE_SUCCESS(rv, rv);
222 :
223 0 : int32_t xHoriz = xCell + wCell/2;
224 0 : int32_t yVert = yCell + hCell/2;
225 :
226 0 : nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(mInlineEditedCell);
227 0 : nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode);
228 : int32_t rowCount, colCount;
229 0 : rv = GetTableSize(tableElement, &rowCount, &colCount);
230 0 : NS_ENSURE_SUCCESS(rv, rv);
231 :
232 0 : SetAnonymousElementPosition(xHoriz-10, yCell-7, mAddColumnBeforeButton);
233 : #ifdef DISABLE_TABLE_DELETION
234 : if (colCount== 1) {
235 : mRemoveColumnButton->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
236 : NS_LITERAL_STRING("hidden"), true);
237 : } else {
238 : if (mRemoveColumnButton->HasAttr(kNameSpaceID_None, nsGkAtoms::_class)) {
239 : mRemoveColumnButton->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class);
240 : }
241 : #endif
242 0 : SetAnonymousElementPosition(xHoriz-4, yCell-7, mRemoveColumnButton);
243 : #ifdef DISABLE_TABLE_DELETION
244 : }
245 : #endif
246 0 : SetAnonymousElementPosition(xHoriz+6, yCell-7, mAddColumnAfterButton);
247 :
248 0 : SetAnonymousElementPosition(xCell-7, yVert-10, mAddRowBeforeButton);
249 : #ifdef DISABLE_TABLE_DELETION
250 : if (rowCount== 1) {
251 : mRemoveRowButton->SetAttr(kNameSpaceID_None, nsGkAtoms::_class,
252 : NS_LITERAL_STRING("hidden"), true);
253 : } else {
254 : if (mRemoveRowButton->HasAttr(kNameSpaceID_None, nsGkAtoms::_class)) {
255 : mRemoveRowButton->UnsetAttr(kNameSpaceID_None, nsGkAtoms::_class, true);
256 : }
257 : #endif
258 0 : SetAnonymousElementPosition(xCell-7, yVert-4, mRemoveRowButton);
259 : #ifdef DISABLE_TABLE_DELETION
260 : }
261 : #endif
262 0 : SetAnonymousElementPosition(xCell-7, yVert+6, mAddRowAfterButton);
263 :
264 0 : return NS_OK;
265 : }
266 :
267 : } // namespace mozilla
|