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 "mozilla/EditorCommands.h"
7
8 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
9 #include "mozilla/EditorBase.h" // for EditorBase
10 #include "mozilla/ErrorResult.h"
11 #include "mozilla/HTMLEditor.h" // for HTMLEditor
12 #include "mozilla/dom/Element.h"
13 #include "nsAString.h"
14 #include "nsAtom.h" // for nsAtom, nsStaticAtom, etc
15 #include "nsCommandParams.h" // for nsCommandParams, etc
16 #include "nsComponentManagerUtils.h" // for do_CreateInstance
17 #include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::font, etc
18 #include "nsIClipboard.h" // for nsIClipboard, etc
19 #include "nsIEditingSession.h"
20 #include "nsIPrincipal.h" // for nsIPrincipal
21 #include "nsLiteralString.h" // for NS_LITERAL_STRING
22 #include "nsReadableUtils.h" // for EmptyString
23 #include "nsString.h" // for nsAutoString, nsString, etc
24 #include "nsStringFwd.h" // for nsString
25
26 class nsISupports;
27
28 namespace mozilla {
29 using dom::Element;
30
31 // prototype
32 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
33 nsAString& aLocalName);
34
35 // defines
36 #define STATE_ENABLED "state_enabled"
37 #define STATE_ALL "state_all"
38 #define STATE_ANY "state_any"
39 #define STATE_MIXED "state_mixed"
40 #define STATE_BEGIN "state_begin"
41 #define STATE_END "state_end"
42 #define STATE_ATTRIBUTE "state_attribute"
43 #define STATE_DATA "state_data"
44
45 /*****************************************************************************
46 * mozilla::StateUpdatingCommandBase
47 *****************************************************************************/
48
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const49 bool StateUpdatingCommandBase::IsCommandEnabled(Command aCommand,
50 EditorBase* aEditorBase) const {
51 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
52 if (!htmlEditor) {
53 return false;
54 }
55 if (!htmlEditor->IsSelectionEditable()) {
56 return false;
57 }
58 if (aCommand == Command::FormatAbsolutePosition) {
59 return htmlEditor->IsAbsolutePositionEditorEnabled();
60 }
61 return true;
62 }
63
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const64 nsresult StateUpdatingCommandBase::DoCommand(Command aCommand,
65 EditorBase& aEditorBase,
66 nsIPrincipal* aPrincipal) const {
67 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
68 if (NS_WARN_IF(!htmlEditor)) {
69 return NS_ERROR_FAILURE;
70 }
71 nsStaticAtom* tagName = GetTagName(aCommand);
72 if (NS_WARN_IF(!tagName)) {
73 return NS_ERROR_UNEXPECTED;
74 }
75 nsresult rv = ToggleState(MOZ_KnownLive(*tagName), MOZ_KnownLive(*htmlEditor),
76 aPrincipal);
77 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
78 "StateUpdatingCommandBase::ToggleState() failed");
79 return rv;
80 }
81
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const82 nsresult StateUpdatingCommandBase::GetCommandStateParams(
83 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
84 nsIEditingSession* aEditingSession) const {
85 if (!aEditorBase) {
86 return NS_OK;
87 }
88 HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
89 if (NS_WARN_IF(!htmlEditor)) {
90 return NS_ERROR_FAILURE;
91 }
92 nsAtom* tagName = GetTagName(aCommand);
93 if (NS_WARN_IF(!tagName)) {
94 return NS_ERROR_UNEXPECTED;
95 }
96 nsresult rv = GetCurrentState(MOZ_KnownLive(tagName),
97 MOZ_KnownLive(htmlEditor), aParams);
98 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
99 "StateUpdatingCommandBase::GetCurrentState() failed");
100 return rv;
101 }
102
103 /*****************************************************************************
104 * mozilla::PasteNoFormattingCommand
105 *****************************************************************************/
106
107 StaticRefPtr<PasteNoFormattingCommand> PasteNoFormattingCommand::sInstance;
108
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const109 bool PasteNoFormattingCommand::IsCommandEnabled(Command aCommand,
110 EditorBase* aEditorBase) const {
111 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
112 if (!htmlEditor) {
113 return false;
114 }
115 return htmlEditor->CanPaste(nsIClipboard::kGlobalClipboard);
116 }
117
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const118 nsresult PasteNoFormattingCommand::DoCommand(Command aCommand,
119 EditorBase& aEditorBase,
120 nsIPrincipal* aPrincipal) const {
121 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
122 if (NS_WARN_IF(!htmlEditor)) {
123 return NS_ERROR_FAILURE;
124 }
125 // Known live because we hold a ref above in "editor"
126 nsresult rv = MOZ_KnownLive(htmlEditor)
127 ->PasteNoFormattingAsAction(nsIClipboard::kGlobalClipboard,
128 aPrincipal);
129 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
130 "HTMLEditor::PasteNoFormattingAsAction() failed");
131 return rv;
132 }
133
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const134 nsresult PasteNoFormattingCommand::GetCommandStateParams(
135 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
136 nsIEditingSession* aEditingSession) const {
137 return aParams.SetBool(STATE_ENABLED,
138 IsCommandEnabled(aCommand, aEditorBase));
139 }
140
141 /*****************************************************************************
142 * mozilla::StyleUpdatingCommand
143 *****************************************************************************/
144
145 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
146
GetCurrentState(nsAtom * aTagName,HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const147 nsresult StyleUpdatingCommand::GetCurrentState(nsAtom* aTagName,
148 HTMLEditor* aHTMLEditor,
149 nsCommandParams& aParams) const {
150 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
151 return NS_ERROR_INVALID_ARG;
152 }
153
154 bool firstOfSelectionHasProp = false;
155 bool anyOfSelectionHasProp = false;
156 bool allOfSelectionHasProp = false;
157
158 nsresult rv = aHTMLEditor->GetInlineProperty(
159 aTagName, nullptr, u""_ns, &firstOfSelectionHasProp,
160 &anyOfSelectionHasProp, &allOfSelectionHasProp);
161 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
162 "HTMLEditor::GetInlineProperty() failed");
163
164 aParams.SetBool(STATE_ENABLED, NS_SUCCEEDED(rv));
165 aParams.SetBool(STATE_ALL, allOfSelectionHasProp);
166 aParams.SetBool(STATE_ANY, anyOfSelectionHasProp);
167 aParams.SetBool(STATE_MIXED, anyOfSelectionHasProp && !allOfSelectionHasProp);
168 aParams.SetBool(STATE_BEGIN, firstOfSelectionHasProp);
169 aParams.SetBool(STATE_END, allOfSelectionHasProp); // not completely accurate
170 return NS_OK;
171 }
172
ToggleState(nsStaticAtom & aTagName,HTMLEditor & aHTMLEditor,nsIPrincipal * aPrincipal) const173 nsresult StyleUpdatingCommand::ToggleState(nsStaticAtom& aTagName,
174 HTMLEditor& aHTMLEditor,
175 nsIPrincipal* aPrincipal) const {
176 RefPtr<nsCommandParams> params = new nsCommandParams();
177
178 // tags "href" and "name" are special cases in the core editor
179 // they are used to remove named anchor/link and shouldn't be used for
180 // insertion
181 bool doTagRemoval;
182 if (&aTagName == nsGkAtoms::href || &aTagName == nsGkAtoms::name) {
183 doTagRemoval = true;
184 } else {
185 // check current selection; set doTagRemoval if formatting should be removed
186 nsresult rv = GetCurrentState(&aTagName, &aHTMLEditor, *params);
187 if (NS_FAILED(rv)) {
188 NS_WARNING("StyleUpdatingCommand::GetCurrentState() failed");
189 return rv;
190 }
191 ErrorResult error;
192 doTagRemoval = params->GetBool(STATE_ALL, error);
193 if (NS_WARN_IF(error.Failed())) {
194 return error.StealNSResult();
195 }
196 }
197
198 if (doTagRemoval) {
199 nsresult rv =
200 aHTMLEditor.RemoveInlinePropertyAsAction(aTagName, nullptr, aPrincipal);
201 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
202 "HTMLEditor::RemoveInlinePropertyAsAction() failed");
203 return rv;
204 }
205
206 nsresult rv = aHTMLEditor.SetInlinePropertyAsAction(aTagName, nullptr, u""_ns,
207 aPrincipal);
208 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
209 "HTMLEditor::SetInlinePropertyAsAction() failed");
210 return rv;
211 }
212
213 /*****************************************************************************
214 * mozilla::ListCommand
215 *****************************************************************************/
216
217 StaticRefPtr<ListCommand> ListCommand::sInstance;
218
GetCurrentState(nsAtom * aTagName,HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const219 nsresult ListCommand::GetCurrentState(nsAtom* aTagName, HTMLEditor* aHTMLEditor,
220 nsCommandParams& aParams) const {
221 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
222 return NS_ERROR_INVALID_ARG;
223 }
224
225 bool bMixed;
226 nsAutoString localName;
227 nsresult rv = GetListState(aHTMLEditor, &bMixed, localName);
228 if (NS_FAILED(rv)) {
229 NS_WARNING("GetListState() failed");
230 return rv;
231 }
232
233 bool inList = aTagName->Equals(localName);
234 aParams.SetBool(STATE_ALL, !bMixed && inList);
235 aParams.SetBool(STATE_MIXED, bMixed);
236 aParams.SetBool(STATE_ENABLED, true);
237 return NS_OK;
238 }
239
ToggleState(nsStaticAtom & aTagName,HTMLEditor & aHTMLEditor,nsIPrincipal * aPrincipal) const240 nsresult ListCommand::ToggleState(nsStaticAtom& aTagName,
241 HTMLEditor& aHTMLEditor,
242 nsIPrincipal* aPrincipal) const {
243 RefPtr<nsCommandParams> params = new nsCommandParams();
244 nsresult rv = GetCurrentState(&aTagName, &aHTMLEditor, *params);
245 if (NS_FAILED(rv)) {
246 NS_WARNING("ListCommand::GetCurrentState() failed");
247 return rv;
248 }
249
250 ErrorResult error;
251 bool inList = params->GetBool(STATE_ALL, error);
252 if (NS_WARN_IF(error.Failed())) {
253 return error.StealNSResult();
254 }
255
256 nsDependentAtomString listType(&aTagName);
257 if (inList) {
258 nsresult rv = aHTMLEditor.RemoveListAsAction(listType, aPrincipal);
259 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
260 "HTMLEditor::RemoveListAsAction() failed");
261 return rv;
262 }
263
264 rv = aHTMLEditor.MakeOrChangeListAsAction(
265 aTagName, u""_ns, HTMLEditor::SelectAllOfCurrentList::No, aPrincipal);
266 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
267 "HTMLEditor::MakeOrChangeListAsAction() failed");
268 return rv;
269 }
270
271 /*****************************************************************************
272 * mozilla::ListItemCommand
273 *****************************************************************************/
274
275 StaticRefPtr<ListItemCommand> ListItemCommand::sInstance;
276
GetCurrentState(nsAtom * aTagName,HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const277 nsresult ListItemCommand::GetCurrentState(nsAtom* aTagName,
278 HTMLEditor* aHTMLEditor,
279 nsCommandParams& aParams) const {
280 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
281 return NS_ERROR_INVALID_ARG;
282 }
283
284 ErrorResult error;
285 ListItemElementSelectionState state(*aHTMLEditor, error);
286 if (error.Failed()) {
287 NS_WARNING("ListItemElementSelectionState failed");
288 return error.StealNSResult();
289 }
290
291 if (state.IsNotOneTypeDefinitionListItemElementSelected()) {
292 aParams.SetBool(STATE_ALL, false);
293 aParams.SetBool(STATE_MIXED, true);
294 return NS_OK;
295 }
296
297 nsStaticAtom* selectedListItemTagName = nullptr;
298 if (state.IsLIElementSelected()) {
299 selectedListItemTagName = nsGkAtoms::li;
300 } else if (state.IsDTElementSelected()) {
301 selectedListItemTagName = nsGkAtoms::dt;
302 } else if (state.IsDDElementSelected()) {
303 selectedListItemTagName = nsGkAtoms::dd;
304 }
305 aParams.SetBool(STATE_ALL, aTagName == selectedListItemTagName);
306 aParams.SetBool(STATE_MIXED, false);
307 return NS_OK;
308 }
309
ToggleState(nsStaticAtom & aTagName,HTMLEditor & aHTMLEditor,nsIPrincipal * aPrincipal) const310 nsresult ListItemCommand::ToggleState(nsStaticAtom& aTagName,
311 HTMLEditor& aHTMLEditor,
312 nsIPrincipal* aPrincipal) const {
313 // Need to use aTagName????
314 RefPtr<nsCommandParams> params = new nsCommandParams();
315 GetCurrentState(&aTagName, &aHTMLEditor, *params);
316 ErrorResult error;
317 bool inList = params->GetBool(STATE_ALL, error);
318 if (NS_WARN_IF(error.Failed())) {
319 return error.StealNSResult();
320 }
321
322 if (inList) {
323 // To remove a list, first get what kind of list we're in
324 bool bMixed;
325 nsAutoString localName;
326 nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
327 if (NS_FAILED(rv)) {
328 NS_WARNING("GetListState() failed");
329 return rv;
330 }
331 if (localName.IsEmpty() || bMixed) {
332 return NS_OK;
333 }
334 rv = aHTMLEditor.RemoveListAsAction(localName, aPrincipal);
335 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
336 "HTMLEditor::RemoveListAsAction() failed");
337 return rv;
338 }
339
340 // Set to the requested paragraph type
341 // XXX Note: This actually doesn't work for "LI",
342 // but we currently don't use this for non DL lists anyway.
343 // Problem: won't this replace any current block paragraph style?
344 nsresult rv = aHTMLEditor.SetParagraphFormatAsAction(
345 nsDependentAtomString(&aTagName), aPrincipal);
346 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
347 "HTMLEditor::SetParagraphFormatAsAction() failed");
348 return rv;
349 }
350
351 /*****************************************************************************
352 * mozilla::RemoveListCommand
353 *****************************************************************************/
354
355 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
356
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const357 bool RemoveListCommand::IsCommandEnabled(Command aCommand,
358 EditorBase* aEditorBase) const {
359 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
360 if (!htmlEditor) {
361 return false;
362 }
363
364 if (!htmlEditor->IsSelectionEditable()) {
365 return false;
366 }
367
368 // It is enabled if we are in any list type
369 bool bMixed;
370 nsAutoString localName;
371 nsresult rv = GetListState(MOZ_KnownLive(htmlEditor), &bMixed, localName);
372 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetListState() failed");
373 return NS_SUCCEEDED(rv) && (bMixed || !localName.IsEmpty());
374 }
375
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const376 nsresult RemoveListCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
377 nsIPrincipal* aPrincipal) const {
378 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
379 if (NS_WARN_IF(!htmlEditor)) {
380 return NS_OK;
381 }
382 // This removes any list type
383 nsresult rv =
384 MOZ_KnownLive(htmlEditor)->RemoveListAsAction(u""_ns, aPrincipal);
385 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
386 "HTMLEditor::RemoveListAsAction() failed");
387 return rv;
388 }
389
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const390 nsresult RemoveListCommand::GetCommandStateParams(
391 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
392 nsIEditingSession* aEditingSession) const {
393 return aParams.SetBool(STATE_ENABLED,
394 IsCommandEnabled(aCommand, aEditorBase));
395 }
396
397 /*****************************************************************************
398 * mozilla::IndentCommand
399 *****************************************************************************/
400
401 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
402
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const403 bool IndentCommand::IsCommandEnabled(Command aCommand,
404 EditorBase* aEditorBase) const {
405 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
406 if (!htmlEditor) {
407 return false;
408 }
409 return htmlEditor->IsSelectionEditable();
410 }
411
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const412 nsresult IndentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
413 nsIPrincipal* aPrincipal) const {
414 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
415 if (NS_WARN_IF(!htmlEditor)) {
416 return NS_OK;
417 }
418 nsresult rv = MOZ_KnownLive(htmlEditor)->IndentAsAction(aPrincipal);
419 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::IndentAsAction() failed");
420 return rv;
421 }
422
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const423 nsresult IndentCommand::GetCommandStateParams(
424 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
425 nsIEditingSession* aEditingSession) const {
426 return aParams.SetBool(STATE_ENABLED,
427 IsCommandEnabled(aCommand, aEditorBase));
428 }
429
430 /*****************************************************************************
431 * mozilla::OutdentCommand
432 *****************************************************************************/
433
434 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
435
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const436 bool OutdentCommand::IsCommandEnabled(Command aCommand,
437 EditorBase* aEditorBase) const {
438 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
439 if (!htmlEditor) {
440 return false;
441 }
442 return htmlEditor->IsSelectionEditable();
443 }
444
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const445 nsresult OutdentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
446 nsIPrincipal* aPrincipal) const {
447 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
448 if (NS_WARN_IF(!htmlEditor)) {
449 return NS_OK;
450 }
451 nsresult rv = MOZ_KnownLive(htmlEditor)->OutdentAsAction(aPrincipal);
452 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
453 "HTMLEditor::OutdentAsAction() failed");
454 return rv;
455 }
456
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const457 nsresult OutdentCommand::GetCommandStateParams(
458 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
459 nsIEditingSession* aEditingSession) const {
460 return aParams.SetBool(STATE_ENABLED,
461 IsCommandEnabled(aCommand, aEditorBase));
462 }
463
464 /*****************************************************************************
465 * mozilla::MultiStateCommandBase
466 *****************************************************************************/
467
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const468 bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
469 EditorBase* aEditorBase) const {
470 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
471 if (!htmlEditor) {
472 return false;
473 }
474 // should be disabled sometimes, like if the current selection is an image
475 return htmlEditor->IsSelectionEditable();
476 }
477
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const478 nsresult MultiStateCommandBase::DoCommand(Command aCommand,
479 EditorBase& aEditorBase,
480 nsIPrincipal* aPrincipal) const {
481 NS_WARNING(
482 "who is calling MultiStateCommandBase::DoCommand (no implementation)?");
483 return NS_OK;
484 }
485
DoCommandParam(Command aCommand,const nsAString & aStringParam,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const486 nsresult MultiStateCommandBase::DoCommandParam(Command aCommand,
487 const nsAString& aStringParam,
488 EditorBase& aEditorBase,
489 nsIPrincipal* aPrincipal) const {
490 NS_WARNING_ASSERTION(aCommand != Command::FormatJustify,
491 "Command::FormatJustify should be used only for "
492 "IsCommandEnabled() and GetCommandStateParams()");
493 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
494 if (NS_WARN_IF(!htmlEditor)) {
495 return NS_ERROR_FAILURE;
496 }
497 nsresult rv = SetState(MOZ_KnownLive(htmlEditor), aStringParam, aPrincipal);
498 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
499 "MultiStateCommandBase::SetState() failed");
500 return rv;
501 }
502
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const503 nsresult MultiStateCommandBase::GetCommandStateParams(
504 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
505 nsIEditingSession* aEditingSession) const {
506 if (!aEditorBase) {
507 return NS_OK;
508 }
509 HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
510 if (NS_WARN_IF(!htmlEditor)) {
511 return NS_ERROR_FAILURE;
512 }
513 nsresult rv = GetCurrentState(MOZ_KnownLive(htmlEditor), aParams);
514 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
515 "MultiStateCommandBase::GetCurrentState() failed");
516 return rv;
517 }
518
519 /*****************************************************************************
520 * mozilla::ParagraphStateCommand
521 *****************************************************************************/
522
523 StaticRefPtr<ParagraphStateCommand> ParagraphStateCommand::sInstance;
524
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const525 nsresult ParagraphStateCommand::GetCurrentState(
526 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
527 if (NS_WARN_IF(!aHTMLEditor)) {
528 return NS_ERROR_INVALID_ARG;
529 }
530
531 ErrorResult error;
532 ParagraphStateAtSelection state(*aHTMLEditor, error);
533 if (error.Failed()) {
534 NS_WARNING("ParagraphStateAtSelection failed");
535 return error.StealNSResult();
536 }
537 aParams.SetBool(STATE_MIXED, state.IsMixed());
538 if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
539 // XXX This is odd behavior, we should fix this later.
540 aParams.SetCString(STATE_ATTRIBUTE, "x"_ns);
541 } else {
542 nsCString paragraphState; // Don't use `nsAutoCString` for avoiding copy.
543 state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
544 aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
545 }
546 return NS_OK;
547 }
548
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const549 nsresult ParagraphStateCommand::SetState(HTMLEditor* aHTMLEditor,
550 const nsAString& aNewState,
551 nsIPrincipal* aPrincipal) const {
552 if (NS_WARN_IF(!aHTMLEditor)) {
553 return NS_ERROR_INVALID_ARG;
554 }
555 nsresult rv = aHTMLEditor->SetParagraphFormatAsAction(aNewState, aPrincipal);
556 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
557 "HTMLEditor::SetParagraphFormatAsAction() failed");
558 return rv;
559 }
560
561 /*****************************************************************************
562 * mozilla::FontFaceStateCommand
563 *****************************************************************************/
564
565 StaticRefPtr<FontFaceStateCommand> FontFaceStateCommand::sInstance;
566
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const567 nsresult FontFaceStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
568 nsCommandParams& aParams) const {
569 if (NS_WARN_IF(!aHTMLEditor)) {
570 return NS_ERROR_INVALID_ARG;
571 }
572
573 nsAutoString outStateString;
574 bool outMixed;
575 nsresult rv = aHTMLEditor->GetFontFaceState(&outMixed, outStateString);
576 if (NS_FAILED(rv)) {
577 NS_WARNING("HTMLEditor::GetFontFaceState() failed");
578 return rv;
579 }
580 aParams.SetBool(STATE_MIXED, outMixed);
581 aParams.SetCString(STATE_ATTRIBUTE, NS_ConvertUTF16toUTF8(outStateString));
582 return NS_OK;
583 }
584
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const585 nsresult FontFaceStateCommand::SetState(HTMLEditor* aHTMLEditor,
586 const nsAString& aNewState,
587 nsIPrincipal* aPrincipal) const {
588 if (NS_WARN_IF(!aHTMLEditor)) {
589 return NS_ERROR_INVALID_ARG;
590 }
591
592 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
593 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
594 *nsGkAtoms::font, nsGkAtoms::face, aPrincipal);
595 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
596 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
597 "font, nsGkAtoms::face) failed");
598 return rv;
599 }
600
601 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
602 *nsGkAtoms::font, nsGkAtoms::face, aNewState, aPrincipal);
603 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
604 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
605 "nsGkAtoms::face) failed");
606 return rv;
607 }
608
609 /*****************************************************************************
610 * mozilla::FontSizeStateCommand
611 *****************************************************************************/
612
613 StaticRefPtr<FontSizeStateCommand> FontSizeStateCommand::sInstance;
614
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const615 nsresult FontSizeStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
616 nsCommandParams& aParams) const {
617 if (NS_WARN_IF(!aHTMLEditor)) {
618 return NS_ERROR_INVALID_ARG;
619 }
620
621 nsAutoString outStateString;
622 bool firstHas, anyHas, allHas;
623 nsresult rv = aHTMLEditor->GetInlinePropertyWithAttrValue(
624 nsGkAtoms::font, nsGkAtoms::size, u""_ns, &firstHas, &anyHas, &allHas,
625 outStateString);
626 if (NS_FAILED(rv)) {
627 NS_WARNING(
628 "HTMLEditor::GetInlinePropertyWithAttrValue(nsGkAtoms::font, "
629 "nsGkAtoms::size) failed");
630 return rv;
631 }
632
633 nsAutoCString tOutStateString;
634 LossyCopyUTF16toASCII(outStateString, tOutStateString);
635 aParams.SetBool(STATE_MIXED, anyHas && !allHas);
636 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
637 aParams.SetBool(STATE_ENABLED, true);
638
639 return NS_OK;
640 }
641
642 // acceptable values for "aNewState" are:
643 // -2
644 // -1
645 // 0
646 // +1
647 // +2
648 // +3
649 // medium
650 // normal
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const651 nsresult FontSizeStateCommand::SetState(HTMLEditor* aHTMLEditor,
652 const nsAString& aNewState,
653 nsIPrincipal* aPrincipal) const {
654 if (NS_WARN_IF(!aHTMLEditor)) {
655 return NS_ERROR_INVALID_ARG;
656 }
657
658 if (!aNewState.IsEmpty() && !aNewState.EqualsLiteral("normal") &&
659 !aNewState.EqualsLiteral("medium")) {
660 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
661 *nsGkAtoms::font, nsGkAtoms::size, aNewState, aPrincipal);
662 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
663 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::"
664 "font, nsGkAtoms::size) failed");
665 return rv;
666 }
667
668 // remove any existing font size, big or small
669 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
670 *nsGkAtoms::font, nsGkAtoms::size, aPrincipal);
671 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
672 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
673 "font, nsGkAtoms::size) failed");
674 return rv;
675 }
676
677 /*****************************************************************************
678 * mozilla::FontColorStateCommand
679 *****************************************************************************/
680
681 StaticRefPtr<FontColorStateCommand> FontColorStateCommand::sInstance;
682
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const683 nsresult FontColorStateCommand::GetCurrentState(
684 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
685 if (NS_WARN_IF(!aHTMLEditor)) {
686 return NS_ERROR_INVALID_ARG;
687 }
688
689 bool outMixed;
690 nsAutoString outStateString;
691 nsresult rv = aHTMLEditor->GetFontColorState(&outMixed, outStateString);
692 if (NS_FAILED(rv)) {
693 NS_WARNING("HTMLEditor::GetFontColorState() failed");
694 return rv;
695 }
696
697 nsAutoCString tOutStateString;
698 LossyCopyUTF16toASCII(outStateString, tOutStateString);
699 aParams.SetBool(STATE_MIXED, outMixed);
700 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
701 return NS_OK;
702 }
703
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const704 nsresult FontColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
705 const nsAString& aNewState,
706 nsIPrincipal* aPrincipal) const {
707 if (NS_WARN_IF(!aHTMLEditor)) {
708 return NS_ERROR_INVALID_ARG;
709 }
710
711 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
712 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
713 *nsGkAtoms::font, nsGkAtoms::color, aPrincipal);
714 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
715 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
716 "font, nsGkAtoms::color) failed");
717 return rv;
718 }
719
720 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
721 *nsGkAtoms::font, nsGkAtoms::color, aNewState, aPrincipal);
722 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
723 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
724 "nsGkAtoms::color) failed");
725 return rv;
726 }
727
728 /*****************************************************************************
729 * mozilla::HighlightColorStateCommand
730 *****************************************************************************/
731
732 StaticRefPtr<HighlightColorStateCommand> HighlightColorStateCommand::sInstance;
733
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const734 nsresult HighlightColorStateCommand::GetCurrentState(
735 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
736 if (NS_WARN_IF(!aHTMLEditor)) {
737 return NS_ERROR_INVALID_ARG;
738 }
739
740 bool outMixed;
741 nsAutoString outStateString;
742 nsresult rv = aHTMLEditor->GetHighlightColorState(&outMixed, outStateString);
743 if (NS_FAILED(rv)) {
744 NS_WARNING("HTMLEditor::GetHighlightColorState() failed");
745 return rv;
746 }
747
748 nsAutoCString tOutStateString;
749 LossyCopyUTF16toASCII(outStateString, tOutStateString);
750 aParams.SetBool(STATE_MIXED, outMixed);
751 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
752 return NS_OK;
753 }
754
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const755 nsresult HighlightColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
756 const nsAString& aNewState,
757 nsIPrincipal* aPrincipal) const {
758 if (NS_WARN_IF(!aHTMLEditor)) {
759 return NS_ERROR_INVALID_ARG;
760 }
761
762 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
763 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
764 *nsGkAtoms::font, nsGkAtoms::bgcolor, aPrincipal);
765 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
766 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
767 "font, nsGkAtoms::bgcolor) failed");
768 return rv;
769 }
770
771 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
772 *nsGkAtoms::font, nsGkAtoms::bgcolor, aNewState, aPrincipal);
773 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
774 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
775 "nsGkAtoms::bgcolor) failed");
776 return rv;
777 }
778
779 /*****************************************************************************
780 * mozilla::BackgroundColorStateCommand
781 *****************************************************************************/
782
783 StaticRefPtr<BackgroundColorStateCommand>
784 BackgroundColorStateCommand::sInstance;
785
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const786 nsresult BackgroundColorStateCommand::GetCurrentState(
787 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
788 if (NS_WARN_IF(!aHTMLEditor)) {
789 return NS_ERROR_INVALID_ARG;
790 }
791
792 bool outMixed;
793 nsAutoString outStateString;
794 nsresult rv = aHTMLEditor->GetBackgroundColorState(&outMixed, outStateString);
795 if (NS_FAILED(rv)) {
796 NS_WARNING("HTMLEditor::GetBackgroundColorState() failed");
797 return rv;
798 }
799
800 nsAutoCString tOutStateString;
801 LossyCopyUTF16toASCII(outStateString, tOutStateString);
802 aParams.SetBool(STATE_MIXED, outMixed);
803 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
804 return NS_OK;
805 }
806
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const807 nsresult BackgroundColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
808 const nsAString& aNewState,
809 nsIPrincipal* aPrincipal) const {
810 if (NS_WARN_IF(!aHTMLEditor)) {
811 return NS_ERROR_INVALID_ARG;
812 }
813 nsresult rv = aHTMLEditor->SetBackgroundColorAsAction(aNewState, aPrincipal);
814 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
815 "HTMLEditor::SetBackgroundColorAsAction() failed");
816 return rv;
817 }
818
819 /*****************************************************************************
820 * mozilla::AlignCommand
821 *****************************************************************************/
822
823 StaticRefPtr<AlignCommand> AlignCommand::sInstance;
824
GetCurrentState(HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const825 nsresult AlignCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
826 nsCommandParams& aParams) const {
827 if (NS_WARN_IF(!aHTMLEditor)) {
828 return NS_ERROR_INVALID_ARG;
829 }
830
831 ErrorResult error;
832 AlignStateAtSelection state(*aHTMLEditor, error);
833 if (error.Failed()) {
834 if (!state.IsSelectionRangesFound()) {
835 // If there was no selection ranges, we shouldn't throw exception for
836 // compatibility with the other browsers, but I have no better idea
837 // than returning empty string in this case. Oddly, Blink/WebKit returns
838 // "true" or "false", but it's different from us and the value does not
839 // make sense. Additionally, WPT loves our behavior.
840 error.SuppressException();
841 aParams.SetBool(STATE_MIXED, false);
842 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
843 return NS_OK;
844 }
845 NS_WARNING("AlignStateAtSelection failed");
846 return error.StealNSResult();
847 }
848 nsCString alignment; // Don't use `nsAutoCString` to avoid copying string.
849 switch (state.AlignmentAtSelectionStart()) {
850 default:
851 case nsIHTMLEditor::eLeft:
852 alignment.AssignLiteral("left");
853 break;
854 case nsIHTMLEditor::eCenter:
855 alignment.AssignLiteral("center");
856 break;
857 case nsIHTMLEditor::eRight:
858 alignment.AssignLiteral("right");
859 break;
860 case nsIHTMLEditor::eJustify:
861 alignment.AssignLiteral("justify");
862 break;
863 }
864 aParams.SetBool(STATE_MIXED, false);
865 aParams.SetCString(STATE_ATTRIBUTE, alignment);
866 return NS_OK;
867 }
868
SetState(HTMLEditor * aHTMLEditor,const nsAString & aNewState,nsIPrincipal * aPrincipal) const869 nsresult AlignCommand::SetState(HTMLEditor* aHTMLEditor,
870 const nsAString& aNewState,
871 nsIPrincipal* aPrincipal) const {
872 if (NS_WARN_IF(!aHTMLEditor)) {
873 return NS_ERROR_INVALID_ARG;
874 }
875 nsresult rv = aHTMLEditor->AlignAsAction(aNewState, aPrincipal);
876 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::AlignAsAction() failed");
877 return rv;
878 }
879
880 /*****************************************************************************
881 * mozilla::AbsolutePositioningCommand
882 *****************************************************************************/
883
884 StaticRefPtr<AbsolutePositioningCommand> AbsolutePositioningCommand::sInstance;
885
GetCurrentState(nsAtom * aTagName,HTMLEditor * aHTMLEditor,nsCommandParams & aParams) const886 nsresult AbsolutePositioningCommand::GetCurrentState(
887 nsAtom* aTagName, HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
888 if (NS_WARN_IF(!aHTMLEditor)) {
889 return NS_ERROR_INVALID_ARG;
890 }
891
892 if (!aHTMLEditor->IsAbsolutePositionEditorEnabled()) {
893 aParams.SetBool(STATE_MIXED, false);
894 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
895 return NS_OK;
896 }
897
898 RefPtr<Element> container =
899 aHTMLEditor->GetAbsolutelyPositionedSelectionContainer();
900 aParams.SetBool(STATE_MIXED, false);
901 aParams.SetCString(STATE_ATTRIBUTE, container ? "absolute"_ns : ""_ns);
902 return NS_OK;
903 }
904
ToggleState(nsStaticAtom & aTagName,HTMLEditor & aHTMLEditor,nsIPrincipal * aPrincipal) const905 nsresult AbsolutePositioningCommand::ToggleState(
906 nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
907 nsIPrincipal* aPrincipal) const {
908 RefPtr<Element> container =
909 aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
910 nsresult rv = aHTMLEditor.SetSelectionToAbsoluteOrStaticAsAction(!container,
911 aPrincipal);
912 NS_WARNING_ASSERTION(
913 NS_SUCCEEDED(rv),
914 "HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction() failed");
915 return rv;
916 }
917
918 /*****************************************************************************
919 * mozilla::DecreaseZIndexCommand
920 *****************************************************************************/
921
922 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
923
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const924 bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
925 EditorBase* aEditorBase) const {
926 RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(aEditorBase);
927 if (!htmlEditor) {
928 return false;
929 }
930 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
931 return false;
932 }
933 RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
934 if (!positionedElement) {
935 return false;
936 }
937 return htmlEditor->GetZIndex(*positionedElement) > 0;
938 }
939
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const940 nsresult DecreaseZIndexCommand::DoCommand(Command aCommand,
941 EditorBase& aEditorBase,
942 nsIPrincipal* aPrincipal) const {
943 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
944 if (NS_WARN_IF(!htmlEditor)) {
945 return NS_ERROR_FAILURE;
946 }
947 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(-1, aPrincipal);
948 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
949 "HTMLEditor::AddZIndexAsAction(-1) failed");
950 return rv;
951 }
952
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const953 nsresult DecreaseZIndexCommand::GetCommandStateParams(
954 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
955 nsIEditingSession* aEditingSession) const {
956 return aParams.SetBool(STATE_ENABLED,
957 IsCommandEnabled(aCommand, aEditorBase));
958 }
959
960 /*****************************************************************************
961 * mozilla::IncreaseZIndexCommand
962 *****************************************************************************/
963
964 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
965
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const966 bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
967 EditorBase* aEditorBase) const {
968 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
969 if (!htmlEditor) {
970 return false;
971 }
972 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
973 return false;
974 }
975 return !!htmlEditor->GetPositionedElement();
976 }
977
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const978 nsresult IncreaseZIndexCommand::DoCommand(Command aCommand,
979 EditorBase& aEditorBase,
980 nsIPrincipal* aPrincipal) const {
981 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
982 if (NS_WARN_IF(!htmlEditor)) {
983 return NS_ERROR_FAILURE;
984 }
985 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(1, aPrincipal);
986 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
987 "HTMLEditor::AddZIndexAsAction(1) failed");
988 return rv;
989 }
990
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const991 nsresult IncreaseZIndexCommand::GetCommandStateParams(
992 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
993 nsIEditingSession* aEditingSession) const {
994 return aParams.SetBool(STATE_ENABLED,
995 IsCommandEnabled(aCommand, aEditorBase));
996 }
997
998 /*****************************************************************************
999 * mozilla::RemoveStylesCommand
1000 *****************************************************************************/
1001
1002 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
1003
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const1004 bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
1005 EditorBase* aEditorBase) const {
1006 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1007 if (!htmlEditor) {
1008 return false;
1009 }
1010 // test if we have any styles?
1011 return htmlEditor->IsSelectionEditable();
1012 }
1013
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1014 nsresult RemoveStylesCommand::DoCommand(Command aCommand,
1015 EditorBase& aEditorBase,
1016 nsIPrincipal* aPrincipal) const {
1017 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1018 if (NS_WARN_IF(!htmlEditor)) {
1019 return NS_OK;
1020 }
1021 nsresult rv =
1022 MOZ_KnownLive(htmlEditor)->RemoveAllInlinePropertiesAsAction(aPrincipal);
1023 NS_WARNING_ASSERTION(
1024 NS_SUCCEEDED(rv),
1025 "HTMLEditor::RemoveAllInlinePropertiesAsAction() failed");
1026 return rv;
1027 }
1028
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const1029 nsresult RemoveStylesCommand::GetCommandStateParams(
1030 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1031 nsIEditingSession* aEditingSession) const {
1032 return aParams.SetBool(STATE_ENABLED,
1033 IsCommandEnabled(aCommand, aEditorBase));
1034 }
1035
1036 /*****************************************************************************
1037 * mozilla::IncreaseFontSizeCommand
1038 *****************************************************************************/
1039
1040 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
1041
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const1042 bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1043 EditorBase* aEditorBase) const {
1044 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1045 if (!htmlEditor) {
1046 return false;
1047 }
1048 // test if we are at max size?
1049 return htmlEditor->IsSelectionEditable();
1050 }
1051
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1052 nsresult IncreaseFontSizeCommand::DoCommand(Command aCommand,
1053 EditorBase& aEditorBase,
1054 nsIPrincipal* aPrincipal) const {
1055 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1056 if (NS_WARN_IF(!htmlEditor)) {
1057 return NS_OK;
1058 }
1059 nsresult rv = MOZ_KnownLive(htmlEditor)->IncreaseFontSizeAsAction(aPrincipal);
1060 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1061 "HTMLEditor::IncreaseFontSizeAsAction() failed");
1062 return rv;
1063 }
1064
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const1065 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
1066 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1067 nsIEditingSession* aEditingSession) const {
1068 return aParams.SetBool(STATE_ENABLED,
1069 IsCommandEnabled(aCommand, aEditorBase));
1070 }
1071
1072 /*****************************************************************************
1073 * mozilla::DecreaseFontSizeCommand
1074 *****************************************************************************/
1075
1076 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
1077
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const1078 bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1079 EditorBase* aEditorBase) const {
1080 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1081 if (!htmlEditor) {
1082 return false;
1083 }
1084 // test if we are at min size?
1085 return htmlEditor->IsSelectionEditable();
1086 }
1087
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1088 nsresult DecreaseFontSizeCommand::DoCommand(Command aCommand,
1089 EditorBase& aEditorBase,
1090 nsIPrincipal* aPrincipal) const {
1091 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1092 if (NS_WARN_IF(!htmlEditor)) {
1093 return NS_OK;
1094 }
1095 nsresult rv = MOZ_KnownLive(htmlEditor)->DecreaseFontSizeAsAction(aPrincipal);
1096 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1097 "HTMLEditor::DecreaseFontSizeAsAction() failed");
1098 return rv;
1099 }
1100
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const1101 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
1102 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1103 nsIEditingSession* aEditingSession) const {
1104 return aParams.SetBool(STATE_ENABLED,
1105 IsCommandEnabled(aCommand, aEditorBase));
1106 }
1107
1108 /*****************************************************************************
1109 * mozilla::InsertHTMLCommand
1110 *****************************************************************************/
1111
1112 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
1113
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const1114 bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
1115 EditorBase* aEditorBase) const {
1116 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1117 if (!htmlEditor) {
1118 return false;
1119 }
1120 return htmlEditor->IsSelectionEditable();
1121 }
1122
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1123 nsresult InsertHTMLCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
1124 nsIPrincipal* aPrincipal) const {
1125 // If InsertHTMLCommand is called with no parameters, it was probably called
1126 // with an empty string parameter ''. In this case, it should act the same as
1127 // the delete command
1128 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1129 if (NS_WARN_IF(!htmlEditor)) {
1130 return NS_ERROR_FAILURE;
1131 }
1132 nsresult rv =
1133 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(u""_ns, aPrincipal);
1134 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1135 "HTMLEditor::InsertHTMLAsAction() failed");
1136 return rv;
1137 }
1138
DoCommandParam(Command aCommand,const nsAString & aStringParam,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1139 nsresult InsertHTMLCommand::DoCommandParam(Command aCommand,
1140 const nsAString& aStringParam,
1141 EditorBase& aEditorBase,
1142 nsIPrincipal* aPrincipal) const {
1143 if (NS_WARN_IF(aStringParam.IsVoid())) {
1144 return NS_ERROR_INVALID_ARG;
1145 }
1146
1147 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1148 if (NS_WARN_IF(!htmlEditor)) {
1149 return NS_ERROR_FAILURE;
1150 }
1151 nsresult rv =
1152 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(aStringParam, aPrincipal);
1153 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1154 "HTMLEditor::InsertHTMLAsAction() failed");
1155 return rv;
1156 }
1157
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const1158 nsresult InsertHTMLCommand::GetCommandStateParams(
1159 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1160 nsIEditingSession* aEditingSession) const {
1161 return aParams.SetBool(STATE_ENABLED,
1162 IsCommandEnabled(aCommand, aEditorBase));
1163 }
1164
1165 /*****************************************************************************
1166 * mozilla::InsertTagCommand
1167 *****************************************************************************/
1168
1169 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
1170
IsCommandEnabled(Command aCommand,EditorBase * aEditorBase) const1171 bool InsertTagCommand::IsCommandEnabled(Command aCommand,
1172 EditorBase* aEditorBase) const {
1173 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1174 if (!htmlEditor) {
1175 return false;
1176 }
1177 return htmlEditor->IsSelectionEditable();
1178 }
1179
1180 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
DoCommand(Command aCommand,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1181 nsresult InsertTagCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
1182 nsIPrincipal* aPrincipal) const {
1183 nsAtom* tagName = GetTagName(aCommand);
1184 if (NS_WARN_IF(tagName != nsGkAtoms::hr)) {
1185 return NS_ERROR_NOT_IMPLEMENTED;
1186 }
1187
1188 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1189 if (NS_WARN_IF(!htmlEditor)) {
1190 return NS_ERROR_FAILURE;
1191 }
1192
1193 RefPtr<Element> newElement =
1194 MOZ_KnownLive(htmlEditor)
1195 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1196 if (NS_WARN_IF(!newElement)) {
1197 return NS_ERROR_FAILURE;
1198 }
1199 nsresult rv =
1200 MOZ_KnownLive(htmlEditor)
1201 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1202 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1203 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1204 return rv;
1205 }
1206
DoCommandParam(Command aCommand,const nsAString & aStringParam,EditorBase & aEditorBase,nsIPrincipal * aPrincipal) const1207 nsresult InsertTagCommand::DoCommandParam(Command aCommand,
1208 const nsAString& aStringParam,
1209 EditorBase& aEditorBase,
1210 nsIPrincipal* aPrincipal) const {
1211 MOZ_ASSERT(aCommand != Command::InsertHorizontalRule);
1212
1213 if (NS_WARN_IF(aStringParam.IsEmpty())) {
1214 return NS_ERROR_INVALID_ARG;
1215 }
1216 nsAtom* tagName = GetTagName(aCommand);
1217 if (NS_WARN_IF(!tagName)) {
1218 return NS_ERROR_UNEXPECTED;
1219 }
1220
1221 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1222 if (NS_WARN_IF(!htmlEditor)) {
1223 return NS_ERROR_FAILURE;
1224 }
1225
1226 // filter out tags we don't know how to insert
1227 nsAtom* attribute = nullptr;
1228 if (tagName == nsGkAtoms::a) {
1229 attribute = nsGkAtoms::href;
1230 } else if (tagName == nsGkAtoms::img) {
1231 attribute = nsGkAtoms::src;
1232 } else {
1233 return NS_ERROR_NOT_IMPLEMENTED;
1234 }
1235
1236 RefPtr<Element> newElement =
1237 MOZ_KnownLive(htmlEditor)
1238 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1239 if (!newElement) {
1240 NS_WARNING("HTMLEditor::CreateElementWithDefaults() failed");
1241 return NS_ERROR_FAILURE;
1242 }
1243
1244 ErrorResult error;
1245 newElement->SetAttr(attribute, aStringParam, error);
1246 if (error.Failed()) {
1247 NS_WARNING("Element::SetAttr() failed");
1248 return error.StealNSResult();
1249 }
1250
1251 // do actual insertion
1252 if (tagName == nsGkAtoms::a) {
1253 nsresult rv =
1254 MOZ_KnownLive(htmlEditor)
1255 ->InsertLinkAroundSelectionAsAction(newElement, aPrincipal);
1256 NS_WARNING_ASSERTION(
1257 NS_SUCCEEDED(rv),
1258 "HTMLEditor::InsertLinkAroundSelectionAsAction() failed");
1259 return rv;
1260 }
1261
1262 nsresult rv =
1263 MOZ_KnownLive(htmlEditor)
1264 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1265 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1266 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1267 return rv;
1268 }
1269
GetCommandStateParams(Command aCommand,nsCommandParams & aParams,EditorBase * aEditorBase,nsIEditingSession * aEditingSession) const1270 nsresult InsertTagCommand::GetCommandStateParams(
1271 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1272 nsIEditingSession* aEditingSession) const {
1273 return aParams.SetBool(STATE_ENABLED,
1274 IsCommandEnabled(aCommand, aEditorBase));
1275 }
1276
1277 /*****************************************************************************
1278 * Helper methods
1279 *****************************************************************************/
1280
GetListState(HTMLEditor * aHTMLEditor,bool * aMixed,nsAString & aLocalName)1281 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
1282 nsAString& aLocalName) {
1283 MOZ_ASSERT(aHTMLEditor);
1284 MOZ_ASSERT(aMixed);
1285
1286 *aMixed = false;
1287 aLocalName.Truncate();
1288
1289 ErrorResult error;
1290 ListElementSelectionState state(*aHTMLEditor, error);
1291 if (error.Failed()) {
1292 NS_WARNING("ListElementSelectionState failed");
1293 return error.StealNSResult();
1294 }
1295 if (state.IsNotOneTypeListElementSelected()) {
1296 *aMixed = true;
1297 return NS_OK;
1298 }
1299
1300 if (state.IsOLElementSelected()) {
1301 aLocalName.AssignLiteral("ol");
1302 } else if (state.IsULElementSelected()) {
1303 aLocalName.AssignLiteral("ul");
1304 } else if (state.IsDLElementSelected()) {
1305 aLocalName.AssignLiteral("dl");
1306 }
1307 return NS_OK;
1308 }
1309
1310 } // namespace mozilla
1311