1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla.org.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corp.
18 : * Portions created by the Initial Developer are Copyright (C) 2003
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Daniel Glazman (glazman@netscape.com) (Original author)
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "nsHTMLEditor.h"
39 : #include "nsIDOMHTMLElement.h"
40 : #include "nsIDOMEventTarget.h"
41 : #include "nsIPresShell.h"
42 : #include "nsIDocumentObserver.h"
43 : #include "nsIContent.h"
44 : #include "nsHTMLEditUtils.h"
45 : #include "nsReadableUtils.h"
46 : #include "mozilla/dom/Element.h"
47 :
48 : // Uncomment the following line if you want to disable
49 : // table deletion when the only column/row is removed
50 : // #define DISABLE_TABLE_DELETION 1
51 :
52 : NS_IMETHODIMP
53 0 : nsHTMLEditor::SetInlineTableEditingEnabled(bool aIsEnabled)
54 : {
55 0 : mIsInlineTableEditingEnabled = aIsEnabled;
56 0 : return NS_OK;
57 : }
58 :
59 : NS_IMETHODIMP
60 0 : nsHTMLEditor::GetInlineTableEditingEnabled(bool * aIsEnabled)
61 : {
62 0 : *aIsEnabled = mIsInlineTableEditingEnabled;
63 0 : return NS_OK;
64 : }
65 :
66 : NS_IMETHODIMP
67 0 : nsHTMLEditor::ShowInlineTableEditingUI(nsIDOMElement * aCell)
68 : {
69 0 : NS_ENSURE_ARG_POINTER(aCell);
70 :
71 : // do nothing if aCell is not a table cell...
72 0 : if (!nsHTMLEditUtils::IsTableCell(aCell))
73 0 : return NS_OK;
74 :
75 0 : if (mInlineEditedCell) {
76 0 : NS_ERROR("call HideInlineTableEditingUI first");
77 0 : return NS_ERROR_UNEXPECTED;
78 : }
79 :
80 : // the resizers and the shadow will be anonymous children of the body
81 0 : nsCOMPtr<nsIDOMElement> bodyElement = do_QueryInterface(GetRoot());
82 0 : NS_ENSURE_TRUE(bodyElement, NS_ERROR_NULL_POINTER);
83 :
84 0 : CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
85 0 : NS_LITERAL_STRING("mozTableAddColumnBefore"),
86 0 : false, getter_AddRefs(mAddColumnBeforeButton));
87 0 : CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
88 0 : NS_LITERAL_STRING("mozTableRemoveColumn"),
89 0 : false, getter_AddRefs(mRemoveColumnButton));
90 0 : CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
91 0 : NS_LITERAL_STRING("mozTableAddColumnAfter"),
92 0 : false, getter_AddRefs(mAddColumnAfterButton));
93 :
94 0 : CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
95 0 : NS_LITERAL_STRING("mozTableAddRowBefore"),
96 0 : false, getter_AddRefs(mAddRowBeforeButton));
97 0 : CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
98 0 : NS_LITERAL_STRING("mozTableRemoveRow"),
99 0 : false, getter_AddRefs(mRemoveRowButton));
100 0 : CreateAnonymousElement(NS_LITERAL_STRING("a"), bodyElement,
101 0 : NS_LITERAL_STRING("mozTableAddRowAfter"),
102 0 : false, getter_AddRefs(mAddRowAfterButton));
103 :
104 0 : AddMouseClickListener(mAddColumnBeforeButton);
105 0 : AddMouseClickListener(mRemoveColumnButton);
106 0 : AddMouseClickListener(mAddColumnAfterButton);
107 0 : AddMouseClickListener(mAddRowBeforeButton);
108 0 : AddMouseClickListener(mRemoveRowButton);
109 0 : AddMouseClickListener(mAddRowAfterButton);
110 :
111 0 : mInlineEditedCell = aCell;
112 0 : return RefreshInlineTableEditingUI();
113 : }
114 :
115 : NS_IMETHODIMP
116 0 : nsHTMLEditor::HideInlineTableEditingUI()
117 : {
118 0 : mInlineEditedCell = nsnull;
119 :
120 0 : RemoveMouseClickListener(mAddColumnBeforeButton);
121 0 : RemoveMouseClickListener(mRemoveColumnButton);
122 0 : RemoveMouseClickListener(mAddColumnAfterButton);
123 0 : RemoveMouseClickListener(mAddRowBeforeButton);
124 0 : RemoveMouseClickListener(mRemoveRowButton);
125 0 : RemoveMouseClickListener(mAddRowAfterButton);
126 :
127 : // get the presshell's document observer interface.
128 0 : nsCOMPtr<nsIPresShell> ps = GetPresShell();
129 : // We allow the pres shell to be null; when it is, we presume there
130 : // are no document observers to notify, but we still want to
131 : // UnbindFromTree.
132 :
133 : // get the root content node.
134 0 : nsCOMPtr<nsIContent> bodyContent = GetRoot();
135 0 : NS_ENSURE_TRUE(bodyContent, NS_ERROR_FAILURE);
136 :
137 0 : DeleteRefToAnonymousNode(mAddColumnBeforeButton, bodyContent, ps);
138 0 : mAddColumnBeforeButton = nsnull;
139 0 : DeleteRefToAnonymousNode(mRemoveColumnButton, bodyContent, ps);
140 0 : mRemoveColumnButton = nsnull;
141 0 : DeleteRefToAnonymousNode(mAddColumnAfterButton, bodyContent, ps);
142 0 : mAddColumnAfterButton = nsnull;
143 0 : DeleteRefToAnonymousNode(mAddRowBeforeButton, bodyContent, ps);
144 0 : mAddRowBeforeButton = nsnull;
145 0 : DeleteRefToAnonymousNode(mRemoveRowButton, bodyContent, ps);
146 0 : mRemoveRowButton = nsnull;
147 0 : DeleteRefToAnonymousNode(mAddRowAfterButton, bodyContent, ps);
148 0 : mAddRowAfterButton = nsnull;
149 :
150 0 : return NS_OK;
151 : }
152 :
153 : NS_IMETHODIMP
154 0 : nsHTMLEditor::DoInlineTableEditingAction(nsIDOMElement * aElement)
155 : {
156 0 : NS_ENSURE_ARG_POINTER(aElement);
157 0 : bool anonElement = false;
158 0 : if (aElement &&
159 0 : NS_SUCCEEDED(aElement->HasAttribute(NS_LITERAL_STRING("_moz_anonclass"), &anonElement)) &&
160 : anonElement) {
161 0 : nsAutoString anonclass;
162 0 : nsresult res = aElement->GetAttribute(NS_LITERAL_STRING("_moz_anonclass"), anonclass);
163 0 : NS_ENSURE_SUCCESS(res, res);
164 :
165 0 : if (!StringBeginsWith(anonclass, NS_LITERAL_STRING("mozTable")))
166 0 : return NS_OK;
167 :
168 0 : nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(mInlineEditedCell);
169 0 : nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode);
170 : PRInt32 rowCount, colCount;
171 0 : res = GetTableSize(tableElement, &rowCount, &colCount);
172 0 : NS_ENSURE_SUCCESS(res, res);
173 :
174 0 : bool hideUI = false;
175 0 : bool hideResizersWithInlineTableUI = (mResizedObject == tableElement);
176 :
177 0 : if (anonclass.EqualsLiteral("mozTableAddColumnBefore"))
178 0 : InsertTableColumn(1, false);
179 0 : else if (anonclass.EqualsLiteral("mozTableAddColumnAfter"))
180 0 : InsertTableColumn(1, true);
181 0 : else if (anonclass.EqualsLiteral("mozTableAddRowBefore"))
182 0 : InsertTableRow(1, false);
183 0 : else if (anonclass.EqualsLiteral("mozTableAddRowAfter"))
184 0 : InsertTableRow(1, true);
185 0 : else if (anonclass.EqualsLiteral("mozTableRemoveColumn")) {
186 0 : DeleteTableColumn(1);
187 : #ifndef DISABLE_TABLE_DELETION
188 0 : hideUI = (colCount == 1);
189 : #endif
190 : }
191 0 : else if (anonclass.EqualsLiteral("mozTableRemoveRow")) {
192 0 : DeleteTableRow(1);
193 : #ifndef DISABLE_TABLE_DELETION
194 0 : hideUI = (rowCount == 1);
195 : #endif
196 : }
197 : else
198 0 : return NS_OK;
199 :
200 0 : if (hideUI) {
201 0 : HideInlineTableEditingUI();
202 0 : if (hideResizersWithInlineTableUI)
203 0 : HideResizers();
204 : }
205 : }
206 :
207 0 : return NS_OK;
208 : }
209 :
210 : void
211 0 : nsHTMLEditor::AddMouseClickListener(nsIDOMElement * aElement)
212 : {
213 0 : nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
214 0 : if (evtTarget) {
215 0 : evtTarget->AddEventListener(NS_LITERAL_STRING("click"),
216 0 : mEventListener, true);
217 : }
218 0 : }
219 :
220 : void
221 0 : nsHTMLEditor::RemoveMouseClickListener(nsIDOMElement * aElement)
222 : {
223 0 : nsCOMPtr<nsIDOMEventTarget> evtTarget(do_QueryInterface(aElement));
224 0 : if (evtTarget) {
225 0 : evtTarget->RemoveEventListener(NS_LITERAL_STRING("click"),
226 0 : mEventListener, true);
227 : }
228 0 : }
229 :
230 : NS_IMETHODIMP
231 0 : nsHTMLEditor::RefreshInlineTableEditingUI()
232 : {
233 0 : nsCOMPtr<nsIDOMHTMLElement> htmlElement = do_QueryInterface(mInlineEditedCell);
234 0 : if (!htmlElement) {
235 0 : return NS_ERROR_NULL_POINTER;
236 : }
237 :
238 : PRInt32 xCell, yCell, wCell, hCell;
239 0 : GetElementOrigin(mInlineEditedCell, xCell, yCell);
240 :
241 0 : nsresult res = htmlElement->GetOffsetWidth(&wCell);
242 0 : NS_ENSURE_SUCCESS(res, res);
243 0 : res = htmlElement->GetOffsetHeight(&hCell);
244 0 : NS_ENSURE_SUCCESS(res, res);
245 :
246 0 : PRInt32 xHoriz = xCell + wCell/2;
247 0 : PRInt32 yVert = yCell + hCell/2;
248 :
249 0 : nsCOMPtr<nsIDOMNode> tableNode = GetEnclosingTable(mInlineEditedCell);
250 0 : nsCOMPtr<nsIDOMElement> tableElement = do_QueryInterface(tableNode);
251 : PRInt32 rowCount, colCount;
252 0 : res = GetTableSize(tableElement, &rowCount, &colCount);
253 0 : NS_ENSURE_SUCCESS(res, res);
254 :
255 0 : SetAnonymousElementPosition(xHoriz-10, yCell-7, mAddColumnBeforeButton);
256 : #ifdef DISABLE_TABLE_DELETION
257 : NS_NAMED_LITERAL_STRING(classStr, "class");
258 :
259 : if (colCount== 1) {
260 : mRemoveColumnButton->SetAttribute(classStr,
261 : NS_LITERAL_STRING("hidden"));
262 : }
263 : else {
264 : bool hasClass = false;
265 : res = mRemoveColumnButton->HasAttribute(classStr, &hasClass);
266 : if (NS_SUCCEEDED(res) && hasClass)
267 : mRemoveColumnButton->RemoveAttribute(classStr);
268 : #endif
269 0 : SetAnonymousElementPosition(xHoriz-4, yCell-7, mRemoveColumnButton);
270 : #ifdef DISABLE_TABLE_DELETION
271 : }
272 : #endif
273 0 : SetAnonymousElementPosition(xHoriz+6, yCell-7, mAddColumnAfterButton);
274 :
275 0 : SetAnonymousElementPosition(xCell-7, yVert-10, mAddRowBeforeButton);
276 : #ifdef DISABLE_TABLE_DELETION
277 : if (rowCount== 1) {
278 : mRemoveRowButton->SetAttribute(classStr,
279 : NS_LITERAL_STRING("hidden"));
280 : }
281 : else {
282 : bool hasClass = false;
283 : res = mRemoveRowButton->HasAttribute(classStr, &hasClass);
284 : if (NS_SUCCEEDED(res) && hasClass)
285 : mRemoveRowButton->RemoveAttribute(classStr);
286 : #endif
287 0 : SetAnonymousElementPosition(xCell-7, yVert-4, mRemoveRowButton);
288 : #ifdef DISABLE_TABLE_DELETION
289 : }
290 : #endif
291 0 : SetAnonymousElementPosition(xCell-7, yVert+6, mAddRowAfterButton);
292 :
293 0 : return NS_OK;
294 : }
295 :
|