Bug 1776056 - Switch to the tab an animation is running and make sure the animation...
[gecko.git] / editor / libeditor / HTMLEditorCommands.cpp
blob2565a382790baaa728db1acb0d7d45cb8f07dd5a
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/. */
6 #include "mozilla/EditorCommands.h"
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
26 class nsISupports;
28 namespace mozilla {
29 using dom::Element;
31 // prototype
32 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
33 nsAString& aLocalName);
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"
45 /*****************************************************************************
46 * mozilla::StateUpdatingCommandBase
47 *****************************************************************************/
49 bool StateUpdatingCommandBase::IsCommandEnabled(Command aCommand,
50 EditorBase* aEditorBase) const {
51 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
52 if (!htmlEditor) {
53 return false;
55 if (!htmlEditor->IsSelectionEditable()) {
56 return false;
58 if (aCommand == Command::FormatAbsolutePosition) {
59 return htmlEditor->IsAbsolutePositionEditorEnabled();
61 return true;
64 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;
71 nsStaticAtom* tagName = GetTagName(aCommand);
72 if (NS_WARN_IF(!tagName)) {
73 return NS_ERROR_UNEXPECTED;
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;
82 nsresult StateUpdatingCommandBase::GetCommandStateParams(
83 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
84 nsIEditingSession* aEditingSession) const {
85 if (!aEditorBase) {
86 return NS_OK;
88 HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
89 if (NS_WARN_IF(!htmlEditor)) {
90 return NS_ERROR_FAILURE;
92 nsStaticAtom* tagName = GetTagName(aCommand);
93 if (NS_WARN_IF(!tagName)) {
94 return NS_ERROR_UNEXPECTED;
96 // MOZ_KnownLive(htmlEditor) because the lifetime of aEditorBase is guaranteed
97 // by the callers.
98 // MOZ_KnownLive(tagName) because nsStaticAtom instances are alive until
99 // shutting down.
100 nsresult rv = GetCurrentState(MOZ_KnownLive(*tagName),
101 MOZ_KnownLive(*htmlEditor), aParams);
102 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
103 "StateUpdatingCommandBase::GetCurrentState() failed");
104 return rv;
107 /*****************************************************************************
108 * mozilla::PasteNoFormattingCommand
109 *****************************************************************************/
111 StaticRefPtr<PasteNoFormattingCommand> PasteNoFormattingCommand::sInstance;
113 bool PasteNoFormattingCommand::IsCommandEnabled(Command aCommand,
114 EditorBase* aEditorBase) const {
115 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
116 if (!htmlEditor) {
117 return false;
119 return htmlEditor->CanPaste(nsIClipboard::kGlobalClipboard);
122 nsresult PasteNoFormattingCommand::DoCommand(Command aCommand,
123 EditorBase& aEditorBase,
124 nsIPrincipal* aPrincipal) const {
125 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
126 if (NS_WARN_IF(!htmlEditor)) {
127 return NS_ERROR_FAILURE;
129 // Known live because we hold a ref above in "editor"
130 nsresult rv = MOZ_KnownLive(htmlEditor)
131 ->PasteNoFormattingAsAction(nsIClipboard::kGlobalClipboard,
132 aPrincipal);
133 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
134 "HTMLEditor::PasteNoFormattingAsAction() failed");
135 return rv;
138 nsresult PasteNoFormattingCommand::GetCommandStateParams(
139 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
140 nsIEditingSession* aEditingSession) const {
141 return aParams.SetBool(STATE_ENABLED,
142 IsCommandEnabled(aCommand, aEditorBase));
145 /*****************************************************************************
146 * mozilla::StyleUpdatingCommand
147 *****************************************************************************/
149 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
151 nsresult StyleUpdatingCommand::GetCurrentState(nsStaticAtom& aTagName,
152 HTMLEditor& aHTMLEditor,
153 nsCommandParams& aParams) const {
154 bool firstOfSelectionHasProp = false;
155 bool anyOfSelectionHasProp = false;
156 bool allOfSelectionHasProp = false;
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");
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;
173 nsresult StyleUpdatingCommand::ToggleState(nsStaticAtom& aTagName,
174 HTMLEditor& aHTMLEditor,
175 nsIPrincipal* aPrincipal) const {
176 RefPtr<nsCommandParams> params = new nsCommandParams();
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;
191 ErrorResult error;
192 doTagRemoval = params->GetBool(STATE_ALL, error);
193 if (NS_WARN_IF(error.Failed())) {
194 return error.StealNSResult();
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;
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;
213 /*****************************************************************************
214 * mozilla::ListCommand
215 *****************************************************************************/
217 StaticRefPtr<ListCommand> ListCommand::sInstance;
219 nsresult ListCommand::GetCurrentState(nsStaticAtom& aTagName,
220 HTMLEditor& aHTMLEditor,
221 nsCommandParams& aParams) const {
222 bool bMixed;
223 nsAutoString localName;
224 nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
225 if (NS_FAILED(rv)) {
226 NS_WARNING("GetListState() failed");
227 return rv;
230 bool inList = aTagName.Equals(localName);
231 aParams.SetBool(STATE_ALL, !bMixed && inList);
232 aParams.SetBool(STATE_MIXED, bMixed);
233 aParams.SetBool(STATE_ENABLED, true);
234 return NS_OK;
237 nsresult ListCommand::ToggleState(nsStaticAtom& aTagName,
238 HTMLEditor& aHTMLEditor,
239 nsIPrincipal* aPrincipal) const {
240 RefPtr<nsCommandParams> params = new nsCommandParams();
241 nsresult rv = GetCurrentState(aTagName, aHTMLEditor, *params);
242 if (NS_FAILED(rv)) {
243 NS_WARNING("ListCommand::GetCurrentState() failed");
244 return rv;
247 ErrorResult error;
248 bool inList = params->GetBool(STATE_ALL, error);
249 if (NS_WARN_IF(error.Failed())) {
250 return error.StealNSResult();
253 nsDependentAtomString listType(&aTagName);
254 if (inList) {
255 nsresult rv = aHTMLEditor.RemoveListAsAction(listType, aPrincipal);
256 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
257 "HTMLEditor::RemoveListAsAction() failed");
258 return rv;
261 rv = aHTMLEditor.MakeOrChangeListAsAction(
262 aTagName, u""_ns, HTMLEditor::SelectAllOfCurrentList::No, aPrincipal);
263 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
264 "HTMLEditor::MakeOrChangeListAsAction() failed");
265 return rv;
268 /*****************************************************************************
269 * mozilla::ListItemCommand
270 *****************************************************************************/
272 StaticRefPtr<ListItemCommand> ListItemCommand::sInstance;
274 nsresult ListItemCommand::GetCurrentState(nsStaticAtom& aTagName,
275 HTMLEditor& aHTMLEditor,
276 nsCommandParams& aParams) const {
277 ErrorResult error;
278 ListItemElementSelectionState state(aHTMLEditor, error);
279 if (error.Failed()) {
280 NS_WARNING("ListItemElementSelectionState failed");
281 return error.StealNSResult();
284 if (state.IsNotOneTypeDefinitionListItemElementSelected()) {
285 aParams.SetBool(STATE_ALL, false);
286 aParams.SetBool(STATE_MIXED, true);
287 return NS_OK;
290 nsStaticAtom* selectedListItemTagName = nullptr;
291 if (state.IsLIElementSelected()) {
292 selectedListItemTagName = nsGkAtoms::li;
293 } else if (state.IsDTElementSelected()) {
294 selectedListItemTagName = nsGkAtoms::dt;
295 } else if (state.IsDDElementSelected()) {
296 selectedListItemTagName = nsGkAtoms::dd;
298 aParams.SetBool(STATE_ALL, &aTagName == selectedListItemTagName);
299 aParams.SetBool(STATE_MIXED, false);
300 return NS_OK;
303 nsresult ListItemCommand::ToggleState(nsStaticAtom& aTagName,
304 HTMLEditor& aHTMLEditor,
305 nsIPrincipal* aPrincipal) const {
306 // Need to use aTagName????
307 RefPtr<nsCommandParams> params = new nsCommandParams();
308 GetCurrentState(aTagName, aHTMLEditor, *params);
309 ErrorResult error;
310 bool inList = params->GetBool(STATE_ALL, error);
311 if (NS_WARN_IF(error.Failed())) {
312 return error.StealNSResult();
315 if (inList) {
316 // To remove a list, first get what kind of list we're in
317 bool bMixed;
318 nsAutoString localName;
319 nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
320 if (NS_FAILED(rv)) {
321 NS_WARNING("GetListState() failed");
322 return rv;
324 if (localName.IsEmpty() || bMixed) {
325 return NS_OK;
327 rv = aHTMLEditor.RemoveListAsAction(localName, aPrincipal);
328 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
329 "HTMLEditor::RemoveListAsAction() failed");
330 return rv;
333 // Set to the requested paragraph type
334 // XXX Note: This actually doesn't work for "LI",
335 // but we currently don't use this for non DL lists anyway.
336 // Problem: won't this replace any current block paragraph style?
337 nsresult rv = aHTMLEditor.SetParagraphFormatAsAction(
338 nsDependentAtomString(&aTagName), aPrincipal);
339 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
340 "HTMLEditor::SetParagraphFormatAsAction() failed");
341 return rv;
344 /*****************************************************************************
345 * mozilla::RemoveListCommand
346 *****************************************************************************/
348 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
350 bool RemoveListCommand::IsCommandEnabled(Command aCommand,
351 EditorBase* aEditorBase) const {
352 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
353 if (!htmlEditor) {
354 return false;
357 if (!htmlEditor->IsSelectionEditable()) {
358 return false;
361 // It is enabled if we are in any list type
362 bool bMixed;
363 nsAutoString localName;
364 nsresult rv = GetListState(MOZ_KnownLive(htmlEditor), &bMixed, localName);
365 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetListState() failed");
366 return NS_SUCCEEDED(rv) && (bMixed || !localName.IsEmpty());
369 nsresult RemoveListCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
370 nsIPrincipal* aPrincipal) const {
371 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
372 if (NS_WARN_IF(!htmlEditor)) {
373 return NS_OK;
375 // This removes any list type
376 nsresult rv =
377 MOZ_KnownLive(htmlEditor)->RemoveListAsAction(u""_ns, aPrincipal);
378 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
379 "HTMLEditor::RemoveListAsAction() failed");
380 return rv;
383 nsresult RemoveListCommand::GetCommandStateParams(
384 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
385 nsIEditingSession* aEditingSession) const {
386 return aParams.SetBool(STATE_ENABLED,
387 IsCommandEnabled(aCommand, aEditorBase));
390 /*****************************************************************************
391 * mozilla::IndentCommand
392 *****************************************************************************/
394 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
396 bool IndentCommand::IsCommandEnabled(Command aCommand,
397 EditorBase* aEditorBase) const {
398 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
399 if (!htmlEditor) {
400 return false;
402 return htmlEditor->IsSelectionEditable();
405 nsresult IndentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
406 nsIPrincipal* aPrincipal) const {
407 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
408 if (NS_WARN_IF(!htmlEditor)) {
409 return NS_OK;
411 nsresult rv = MOZ_KnownLive(htmlEditor)->IndentAsAction(aPrincipal);
412 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::IndentAsAction() failed");
413 return rv;
416 nsresult IndentCommand::GetCommandStateParams(
417 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
418 nsIEditingSession* aEditingSession) const {
419 return aParams.SetBool(STATE_ENABLED,
420 IsCommandEnabled(aCommand, aEditorBase));
423 /*****************************************************************************
424 * mozilla::OutdentCommand
425 *****************************************************************************/
427 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
429 bool OutdentCommand::IsCommandEnabled(Command aCommand,
430 EditorBase* aEditorBase) const {
431 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
432 if (!htmlEditor) {
433 return false;
435 return htmlEditor->IsSelectionEditable();
438 nsresult OutdentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
439 nsIPrincipal* aPrincipal) const {
440 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
441 if (NS_WARN_IF(!htmlEditor)) {
442 return NS_OK;
444 nsresult rv = MOZ_KnownLive(htmlEditor)->OutdentAsAction(aPrincipal);
445 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
446 "HTMLEditor::OutdentAsAction() failed");
447 return rv;
450 nsresult OutdentCommand::GetCommandStateParams(
451 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
452 nsIEditingSession* aEditingSession) const {
453 return aParams.SetBool(STATE_ENABLED,
454 IsCommandEnabled(aCommand, aEditorBase));
457 /*****************************************************************************
458 * mozilla::MultiStateCommandBase
459 *****************************************************************************/
461 bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
462 EditorBase* aEditorBase) const {
463 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
464 if (!htmlEditor) {
465 return false;
467 // should be disabled sometimes, like if the current selection is an image
468 return htmlEditor->IsSelectionEditable();
471 nsresult MultiStateCommandBase::DoCommand(Command aCommand,
472 EditorBase& aEditorBase,
473 nsIPrincipal* aPrincipal) const {
474 NS_WARNING(
475 "who is calling MultiStateCommandBase::DoCommand (no implementation)?");
476 return NS_OK;
479 nsresult MultiStateCommandBase::DoCommandParam(Command aCommand,
480 const nsAString& aStringParam,
481 EditorBase& aEditorBase,
482 nsIPrincipal* aPrincipal) const {
483 NS_WARNING_ASSERTION(aCommand != Command::FormatJustify,
484 "Command::FormatJustify should be used only for "
485 "IsCommandEnabled() and GetCommandStateParams()");
486 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
487 if (NS_WARN_IF(!htmlEditor)) {
488 return NS_ERROR_FAILURE;
490 nsresult rv = SetState(MOZ_KnownLive(htmlEditor), aStringParam, aPrincipal);
491 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
492 "MultiStateCommandBase::SetState() failed");
493 return rv;
496 nsresult MultiStateCommandBase::GetCommandStateParams(
497 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
498 nsIEditingSession* aEditingSession) const {
499 if (!aEditorBase) {
500 return NS_OK;
502 HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
503 if (NS_WARN_IF(!htmlEditor)) {
504 return NS_ERROR_FAILURE;
506 nsresult rv = GetCurrentState(MOZ_KnownLive(htmlEditor), aParams);
507 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
508 "MultiStateCommandBase::GetCurrentState() failed");
509 return rv;
512 /*****************************************************************************
513 * mozilla::ParagraphStateCommand
514 *****************************************************************************/
516 StaticRefPtr<ParagraphStateCommand> ParagraphStateCommand::sInstance;
518 nsresult ParagraphStateCommand::GetCurrentState(
519 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
520 if (NS_WARN_IF(!aHTMLEditor)) {
521 return NS_ERROR_INVALID_ARG;
524 ErrorResult error;
525 ParagraphStateAtSelection state(*aHTMLEditor, error);
526 if (error.Failed()) {
527 NS_WARNING("ParagraphStateAtSelection failed");
528 return error.StealNSResult();
530 aParams.SetBool(STATE_MIXED, state.IsMixed());
531 if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
532 // XXX This is odd behavior, we should fix this later.
533 aParams.SetCString(STATE_ATTRIBUTE, "x"_ns);
534 } else {
535 nsCString paragraphState; // Don't use `nsAutoCString` for avoiding copy.
536 state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
537 aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
539 return NS_OK;
542 nsresult ParagraphStateCommand::SetState(HTMLEditor* aHTMLEditor,
543 const nsAString& aNewState,
544 nsIPrincipal* aPrincipal) const {
545 if (NS_WARN_IF(!aHTMLEditor)) {
546 return NS_ERROR_INVALID_ARG;
548 nsresult rv = aHTMLEditor->SetParagraphFormatAsAction(aNewState, aPrincipal);
549 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
550 "HTMLEditor::SetParagraphFormatAsAction() failed");
551 return rv;
554 /*****************************************************************************
555 * mozilla::FontFaceStateCommand
556 *****************************************************************************/
558 StaticRefPtr<FontFaceStateCommand> FontFaceStateCommand::sInstance;
560 nsresult FontFaceStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
561 nsCommandParams& aParams) const {
562 if (NS_WARN_IF(!aHTMLEditor)) {
563 return NS_ERROR_INVALID_ARG;
566 nsAutoString outStateString;
567 bool outMixed;
568 nsresult rv = aHTMLEditor->GetFontFaceState(&outMixed, outStateString);
569 if (NS_FAILED(rv)) {
570 NS_WARNING("HTMLEditor::GetFontFaceState() failed");
571 return rv;
573 aParams.SetBool(STATE_MIXED, outMixed);
574 aParams.SetCString(STATE_ATTRIBUTE, NS_ConvertUTF16toUTF8(outStateString));
575 return NS_OK;
578 nsresult FontFaceStateCommand::SetState(HTMLEditor* aHTMLEditor,
579 const nsAString& aNewState,
580 nsIPrincipal* aPrincipal) const {
581 if (NS_WARN_IF(!aHTMLEditor)) {
582 return NS_ERROR_INVALID_ARG;
585 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
586 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
587 *nsGkAtoms::font, nsGkAtoms::face, aPrincipal);
588 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
589 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
590 "font, nsGkAtoms::face) failed");
591 return rv;
594 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
595 *nsGkAtoms::font, nsGkAtoms::face, aNewState, aPrincipal);
596 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
597 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
598 "nsGkAtoms::face) failed");
599 return rv;
602 /*****************************************************************************
603 * mozilla::FontSizeStateCommand
604 *****************************************************************************/
606 StaticRefPtr<FontSizeStateCommand> FontSizeStateCommand::sInstance;
608 nsresult FontSizeStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
609 nsCommandParams& aParams) const {
610 if (NS_WARN_IF(!aHTMLEditor)) {
611 return NS_ERROR_INVALID_ARG;
614 nsAutoString outStateString;
615 bool firstHas, anyHas, allHas;
616 nsresult rv = aHTMLEditor->GetInlinePropertyWithAttrValue(
617 *nsGkAtoms::font, nsGkAtoms::size, u""_ns, &firstHas, &anyHas, &allHas,
618 outStateString);
619 if (NS_FAILED(rv)) {
620 NS_WARNING(
621 "HTMLEditor::GetInlinePropertyWithAttrValue(nsGkAtoms::font, "
622 "nsGkAtoms::size) failed");
623 return rv;
626 nsAutoCString tOutStateString;
627 LossyCopyUTF16toASCII(outStateString, tOutStateString);
628 aParams.SetBool(STATE_MIXED, anyHas && !allHas);
629 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
630 aParams.SetBool(STATE_ENABLED, true);
632 return NS_OK;
635 // acceptable values for "aNewState" are:
636 // -2
637 // -1
638 // 0
639 // +1
640 // +2
641 // +3
642 // medium
643 // normal
644 nsresult FontSizeStateCommand::SetState(HTMLEditor* aHTMLEditor,
645 const nsAString& aNewState,
646 nsIPrincipal* aPrincipal) const {
647 if (NS_WARN_IF(!aHTMLEditor)) {
648 return NS_ERROR_INVALID_ARG;
651 if (!aNewState.IsEmpty() && !aNewState.EqualsLiteral("normal") &&
652 !aNewState.EqualsLiteral("medium")) {
653 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
654 *nsGkAtoms::font, nsGkAtoms::size, aNewState, aPrincipal);
655 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
656 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::"
657 "font, nsGkAtoms::size) failed");
658 return rv;
661 // remove any existing font size, big or small
662 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
663 *nsGkAtoms::font, nsGkAtoms::size, aPrincipal);
664 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
665 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
666 "font, nsGkAtoms::size) failed");
667 return rv;
670 /*****************************************************************************
671 * mozilla::FontColorStateCommand
672 *****************************************************************************/
674 StaticRefPtr<FontColorStateCommand> FontColorStateCommand::sInstance;
676 nsresult FontColorStateCommand::GetCurrentState(
677 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
678 if (NS_WARN_IF(!aHTMLEditor)) {
679 return NS_ERROR_INVALID_ARG;
682 bool outMixed;
683 nsAutoString outStateString;
684 nsresult rv = aHTMLEditor->GetFontColorState(&outMixed, outStateString);
685 if (NS_FAILED(rv)) {
686 NS_WARNING("HTMLEditor::GetFontColorState() failed");
687 return rv;
690 nsAutoCString tOutStateString;
691 LossyCopyUTF16toASCII(outStateString, tOutStateString);
692 aParams.SetBool(STATE_MIXED, outMixed);
693 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
694 return NS_OK;
697 nsresult FontColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
698 const nsAString& aNewState,
699 nsIPrincipal* aPrincipal) const {
700 if (NS_WARN_IF(!aHTMLEditor)) {
701 return NS_ERROR_INVALID_ARG;
704 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
705 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
706 *nsGkAtoms::font, nsGkAtoms::color, aPrincipal);
707 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
708 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
709 "font, nsGkAtoms::color) failed");
710 return rv;
713 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
714 *nsGkAtoms::font, nsGkAtoms::color, aNewState, aPrincipal);
715 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
716 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
717 "nsGkAtoms::color) failed");
718 return rv;
721 /*****************************************************************************
722 * mozilla::HighlightColorStateCommand
723 *****************************************************************************/
725 StaticRefPtr<HighlightColorStateCommand> HighlightColorStateCommand::sInstance;
727 nsresult HighlightColorStateCommand::GetCurrentState(
728 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
729 if (NS_WARN_IF(!aHTMLEditor)) {
730 return NS_ERROR_INVALID_ARG;
733 bool outMixed;
734 nsAutoString outStateString;
735 nsresult rv = aHTMLEditor->GetHighlightColorState(&outMixed, outStateString);
736 if (NS_FAILED(rv)) {
737 NS_WARNING("HTMLEditor::GetHighlightColorState() failed");
738 return rv;
741 nsAutoCString tOutStateString;
742 LossyCopyUTF16toASCII(outStateString, tOutStateString);
743 aParams.SetBool(STATE_MIXED, outMixed);
744 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
745 return NS_OK;
748 nsresult HighlightColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
749 const nsAString& aNewState,
750 nsIPrincipal* aPrincipal) const {
751 if (NS_WARN_IF(!aHTMLEditor)) {
752 return NS_ERROR_INVALID_ARG;
755 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
756 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
757 *nsGkAtoms::font, nsGkAtoms::bgcolor, aPrincipal);
758 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
759 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
760 "font, nsGkAtoms::bgcolor) failed");
761 return rv;
764 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
765 *nsGkAtoms::font, nsGkAtoms::bgcolor, aNewState, aPrincipal);
766 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
767 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
768 "nsGkAtoms::bgcolor) failed");
769 return rv;
772 /*****************************************************************************
773 * mozilla::BackgroundColorStateCommand
774 *****************************************************************************/
776 StaticRefPtr<BackgroundColorStateCommand>
777 BackgroundColorStateCommand::sInstance;
779 nsresult BackgroundColorStateCommand::GetCurrentState(
780 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
781 if (NS_WARN_IF(!aHTMLEditor)) {
782 return NS_ERROR_INVALID_ARG;
785 bool outMixed;
786 nsAutoString outStateString;
787 nsresult rv = aHTMLEditor->GetBackgroundColorState(&outMixed, outStateString);
788 if (NS_FAILED(rv)) {
789 NS_WARNING("HTMLEditor::GetBackgroundColorState() failed");
790 return rv;
793 nsAutoCString tOutStateString;
794 LossyCopyUTF16toASCII(outStateString, tOutStateString);
795 aParams.SetBool(STATE_MIXED, outMixed);
796 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
797 return NS_OK;
800 nsresult BackgroundColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
801 const nsAString& aNewState,
802 nsIPrincipal* aPrincipal) const {
803 if (NS_WARN_IF(!aHTMLEditor)) {
804 return NS_ERROR_INVALID_ARG;
806 nsresult rv = aHTMLEditor->SetBackgroundColorAsAction(aNewState, aPrincipal);
807 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
808 "HTMLEditor::SetBackgroundColorAsAction() failed");
809 return rv;
812 /*****************************************************************************
813 * mozilla::AlignCommand
814 *****************************************************************************/
816 StaticRefPtr<AlignCommand> AlignCommand::sInstance;
818 nsresult AlignCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
819 nsCommandParams& aParams) const {
820 if (NS_WARN_IF(!aHTMLEditor)) {
821 return NS_ERROR_INVALID_ARG;
824 ErrorResult error;
825 AlignStateAtSelection state(*aHTMLEditor, error);
826 if (error.Failed()) {
827 if (!state.IsSelectionRangesFound()) {
828 // If there was no selection ranges, we shouldn't throw exception for
829 // compatibility with the other browsers, but I have no better idea
830 // than returning empty string in this case. Oddly, Blink/WebKit returns
831 // "true" or "false", but it's different from us and the value does not
832 // make sense. Additionally, WPT loves our behavior.
833 error.SuppressException();
834 aParams.SetBool(STATE_MIXED, false);
835 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
836 return NS_OK;
838 NS_WARNING("AlignStateAtSelection failed");
839 return error.StealNSResult();
841 nsCString alignment; // Don't use `nsAutoCString` to avoid copying string.
842 switch (state.AlignmentAtSelectionStart()) {
843 default:
844 case nsIHTMLEditor::eLeft:
845 alignment.AssignLiteral("left");
846 break;
847 case nsIHTMLEditor::eCenter:
848 alignment.AssignLiteral("center");
849 break;
850 case nsIHTMLEditor::eRight:
851 alignment.AssignLiteral("right");
852 break;
853 case nsIHTMLEditor::eJustify:
854 alignment.AssignLiteral("justify");
855 break;
857 aParams.SetBool(STATE_MIXED, false);
858 aParams.SetCString(STATE_ATTRIBUTE, alignment);
859 return NS_OK;
862 nsresult AlignCommand::SetState(HTMLEditor* aHTMLEditor,
863 const nsAString& aNewState,
864 nsIPrincipal* aPrincipal) const {
865 if (NS_WARN_IF(!aHTMLEditor)) {
866 return NS_ERROR_INVALID_ARG;
868 nsresult rv = aHTMLEditor->AlignAsAction(aNewState, aPrincipal);
869 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::AlignAsAction() failed");
870 return rv;
873 /*****************************************************************************
874 * mozilla::AbsolutePositioningCommand
875 *****************************************************************************/
877 StaticRefPtr<AbsolutePositioningCommand> AbsolutePositioningCommand::sInstance;
879 nsresult AbsolutePositioningCommand::GetCurrentState(
880 nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
881 nsCommandParams& aParams) const {
882 if (!aHTMLEditor.IsAbsolutePositionEditorEnabled()) {
883 aParams.SetBool(STATE_MIXED, false);
884 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
885 return NS_OK;
888 RefPtr<Element> container =
889 aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
890 aParams.SetBool(STATE_MIXED, false);
891 aParams.SetCString(STATE_ATTRIBUTE, container ? "absolute"_ns : ""_ns);
892 return NS_OK;
895 nsresult AbsolutePositioningCommand::ToggleState(
896 nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
897 nsIPrincipal* aPrincipal) const {
898 RefPtr<Element> container =
899 aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
900 nsresult rv = aHTMLEditor.SetSelectionToAbsoluteOrStaticAsAction(!container,
901 aPrincipal);
902 NS_WARNING_ASSERTION(
903 NS_SUCCEEDED(rv),
904 "HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction() failed");
905 return rv;
908 /*****************************************************************************
909 * mozilla::DecreaseZIndexCommand
910 *****************************************************************************/
912 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
914 bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
915 EditorBase* aEditorBase) const {
916 RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(aEditorBase);
917 if (!htmlEditor) {
918 return false;
920 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
921 return false;
923 RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
924 if (!positionedElement) {
925 return false;
927 return htmlEditor->GetZIndex(*positionedElement) > 0;
930 nsresult DecreaseZIndexCommand::DoCommand(Command aCommand,
931 EditorBase& aEditorBase,
932 nsIPrincipal* aPrincipal) const {
933 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
934 if (NS_WARN_IF(!htmlEditor)) {
935 return NS_ERROR_FAILURE;
937 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(-1, aPrincipal);
938 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
939 "HTMLEditor::AddZIndexAsAction(-1) failed");
940 return rv;
943 nsresult DecreaseZIndexCommand::GetCommandStateParams(
944 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
945 nsIEditingSession* aEditingSession) const {
946 return aParams.SetBool(STATE_ENABLED,
947 IsCommandEnabled(aCommand, aEditorBase));
950 /*****************************************************************************
951 * mozilla::IncreaseZIndexCommand
952 *****************************************************************************/
954 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
956 bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
957 EditorBase* aEditorBase) const {
958 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
959 if (!htmlEditor) {
960 return false;
962 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
963 return false;
965 return !!htmlEditor->GetPositionedElement();
968 nsresult IncreaseZIndexCommand::DoCommand(Command aCommand,
969 EditorBase& aEditorBase,
970 nsIPrincipal* aPrincipal) const {
971 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
972 if (NS_WARN_IF(!htmlEditor)) {
973 return NS_ERROR_FAILURE;
975 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(1, aPrincipal);
976 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
977 "HTMLEditor::AddZIndexAsAction(1) failed");
978 return rv;
981 nsresult IncreaseZIndexCommand::GetCommandStateParams(
982 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
983 nsIEditingSession* aEditingSession) const {
984 return aParams.SetBool(STATE_ENABLED,
985 IsCommandEnabled(aCommand, aEditorBase));
988 /*****************************************************************************
989 * mozilla::RemoveStylesCommand
990 *****************************************************************************/
992 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
994 bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
995 EditorBase* aEditorBase) const {
996 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
997 if (!htmlEditor) {
998 return false;
1000 // test if we have any styles?
1001 return htmlEditor->IsSelectionEditable();
1004 nsresult RemoveStylesCommand::DoCommand(Command aCommand,
1005 EditorBase& aEditorBase,
1006 nsIPrincipal* aPrincipal) const {
1007 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1008 if (NS_WARN_IF(!htmlEditor)) {
1009 return NS_OK;
1011 nsresult rv =
1012 MOZ_KnownLive(htmlEditor)->RemoveAllInlinePropertiesAsAction(aPrincipal);
1013 NS_WARNING_ASSERTION(
1014 NS_SUCCEEDED(rv),
1015 "HTMLEditor::RemoveAllInlinePropertiesAsAction() failed");
1016 return rv;
1019 nsresult RemoveStylesCommand::GetCommandStateParams(
1020 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1021 nsIEditingSession* aEditingSession) const {
1022 return aParams.SetBool(STATE_ENABLED,
1023 IsCommandEnabled(aCommand, aEditorBase));
1026 /*****************************************************************************
1027 * mozilla::IncreaseFontSizeCommand
1028 *****************************************************************************/
1030 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
1032 bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1033 EditorBase* aEditorBase) const {
1034 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1035 if (!htmlEditor) {
1036 return false;
1038 // test if we are at max size?
1039 return htmlEditor->IsSelectionEditable();
1042 nsresult IncreaseFontSizeCommand::DoCommand(Command aCommand,
1043 EditorBase& aEditorBase,
1044 nsIPrincipal* aPrincipal) const {
1045 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1046 if (NS_WARN_IF(!htmlEditor)) {
1047 return NS_OK;
1049 nsresult rv = MOZ_KnownLive(htmlEditor)->IncreaseFontSizeAsAction(aPrincipal);
1050 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1051 "HTMLEditor::IncreaseFontSizeAsAction() failed");
1052 return rv;
1055 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
1056 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1057 nsIEditingSession* aEditingSession) const {
1058 return aParams.SetBool(STATE_ENABLED,
1059 IsCommandEnabled(aCommand, aEditorBase));
1062 /*****************************************************************************
1063 * mozilla::DecreaseFontSizeCommand
1064 *****************************************************************************/
1066 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
1068 bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1069 EditorBase* aEditorBase) const {
1070 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1071 if (!htmlEditor) {
1072 return false;
1074 // test if we are at min size?
1075 return htmlEditor->IsSelectionEditable();
1078 nsresult DecreaseFontSizeCommand::DoCommand(Command aCommand,
1079 EditorBase& aEditorBase,
1080 nsIPrincipal* aPrincipal) const {
1081 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1082 if (NS_WARN_IF(!htmlEditor)) {
1083 return NS_OK;
1085 nsresult rv = MOZ_KnownLive(htmlEditor)->DecreaseFontSizeAsAction(aPrincipal);
1086 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1087 "HTMLEditor::DecreaseFontSizeAsAction() failed");
1088 return rv;
1091 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
1092 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1093 nsIEditingSession* aEditingSession) const {
1094 return aParams.SetBool(STATE_ENABLED,
1095 IsCommandEnabled(aCommand, aEditorBase));
1098 /*****************************************************************************
1099 * mozilla::InsertHTMLCommand
1100 *****************************************************************************/
1102 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
1104 bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
1105 EditorBase* aEditorBase) const {
1106 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1107 if (!htmlEditor) {
1108 return false;
1110 return htmlEditor->IsSelectionEditable();
1113 nsresult InsertHTMLCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
1114 nsIPrincipal* aPrincipal) const {
1115 // If InsertHTMLCommand is called with no parameters, it was probably called
1116 // with an empty string parameter ''. In this case, it should act the same as
1117 // the delete command
1118 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1119 if (NS_WARN_IF(!htmlEditor)) {
1120 return NS_ERROR_FAILURE;
1122 nsresult rv =
1123 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(u""_ns, aPrincipal);
1124 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1125 "HTMLEditor::InsertHTMLAsAction() failed");
1126 return rv;
1129 nsresult InsertHTMLCommand::DoCommandParam(Command aCommand,
1130 const nsAString& aStringParam,
1131 EditorBase& aEditorBase,
1132 nsIPrincipal* aPrincipal) const {
1133 if (NS_WARN_IF(aStringParam.IsVoid())) {
1134 return NS_ERROR_INVALID_ARG;
1137 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1138 if (NS_WARN_IF(!htmlEditor)) {
1139 return NS_ERROR_FAILURE;
1141 nsresult rv =
1142 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(aStringParam, aPrincipal);
1143 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1144 "HTMLEditor::InsertHTMLAsAction() failed");
1145 return rv;
1148 nsresult InsertHTMLCommand::GetCommandStateParams(
1149 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1150 nsIEditingSession* aEditingSession) const {
1151 return aParams.SetBool(STATE_ENABLED,
1152 IsCommandEnabled(aCommand, aEditorBase));
1155 /*****************************************************************************
1156 * mozilla::InsertTagCommand
1157 *****************************************************************************/
1159 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
1161 bool InsertTagCommand::IsCommandEnabled(Command aCommand,
1162 EditorBase* aEditorBase) const {
1163 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1164 if (!htmlEditor) {
1165 return false;
1167 return htmlEditor->IsSelectionEditable();
1170 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
1171 nsresult InsertTagCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
1172 nsIPrincipal* aPrincipal) const {
1173 nsAtom* tagName = GetTagName(aCommand);
1174 if (NS_WARN_IF(tagName != nsGkAtoms::hr)) {
1175 return NS_ERROR_NOT_IMPLEMENTED;
1178 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1179 if (NS_WARN_IF(!htmlEditor)) {
1180 return NS_ERROR_FAILURE;
1183 RefPtr<Element> newElement =
1184 MOZ_KnownLive(htmlEditor)
1185 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1186 if (NS_WARN_IF(!newElement)) {
1187 return NS_ERROR_FAILURE;
1189 nsresult rv =
1190 MOZ_KnownLive(htmlEditor)
1191 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1192 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1193 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1194 return rv;
1197 nsresult InsertTagCommand::DoCommandParam(Command aCommand,
1198 const nsAString& aStringParam,
1199 EditorBase& aEditorBase,
1200 nsIPrincipal* aPrincipal) const {
1201 MOZ_ASSERT(aCommand != Command::InsertHorizontalRule);
1203 if (NS_WARN_IF(aStringParam.IsEmpty())) {
1204 return NS_ERROR_INVALID_ARG;
1206 nsAtom* tagName = GetTagName(aCommand);
1207 if (NS_WARN_IF(!tagName)) {
1208 return NS_ERROR_UNEXPECTED;
1211 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1212 if (NS_WARN_IF(!htmlEditor)) {
1213 return NS_ERROR_FAILURE;
1216 // filter out tags we don't know how to insert
1217 nsAtom* attribute = nullptr;
1218 if (tagName == nsGkAtoms::a) {
1219 attribute = nsGkAtoms::href;
1220 } else if (tagName == nsGkAtoms::img) {
1221 attribute = nsGkAtoms::src;
1222 } else {
1223 return NS_ERROR_NOT_IMPLEMENTED;
1226 RefPtr<Element> newElement =
1227 MOZ_KnownLive(htmlEditor)
1228 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1229 if (!newElement) {
1230 NS_WARNING("HTMLEditor::CreateElementWithDefaults() failed");
1231 return NS_ERROR_FAILURE;
1234 ErrorResult error;
1235 newElement->SetAttr(attribute, aStringParam, error);
1236 if (error.Failed()) {
1237 NS_WARNING("Element::SetAttr() failed");
1238 return error.StealNSResult();
1241 // do actual insertion
1242 if (tagName == nsGkAtoms::a) {
1243 nsresult rv =
1244 MOZ_KnownLive(htmlEditor)
1245 ->InsertLinkAroundSelectionAsAction(newElement, aPrincipal);
1246 NS_WARNING_ASSERTION(
1247 NS_SUCCEEDED(rv),
1248 "HTMLEditor::InsertLinkAroundSelectionAsAction() failed");
1249 return rv;
1252 nsresult rv =
1253 MOZ_KnownLive(htmlEditor)
1254 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1255 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1256 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1257 return rv;
1260 nsresult InsertTagCommand::GetCommandStateParams(
1261 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1262 nsIEditingSession* aEditingSession) const {
1263 return aParams.SetBool(STATE_ENABLED,
1264 IsCommandEnabled(aCommand, aEditorBase));
1267 /*****************************************************************************
1268 * Helper methods
1269 *****************************************************************************/
1271 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
1272 nsAString& aLocalName) {
1273 MOZ_ASSERT(aHTMLEditor);
1274 MOZ_ASSERT(aMixed);
1276 *aMixed = false;
1277 aLocalName.Truncate();
1279 ErrorResult error;
1280 ListElementSelectionState state(*aHTMLEditor, error);
1281 if (error.Failed()) {
1282 NS_WARNING("ListElementSelectionState failed");
1283 return error.StealNSResult();
1285 if (state.IsNotOneTypeListElementSelected()) {
1286 *aMixed = true;
1287 return NS_OK;
1290 if (state.IsOLElementSelected()) {
1291 aLocalName.AssignLiteral("ol");
1292 } else if (state.IsULElementSelected()) {
1293 aLocalName.AssignLiteral("ul");
1294 } else if (state.IsDLElementSelected()) {
1295 aLocalName.AssignLiteral("dl");
1297 return NS_OK;
1300 } // namespace mozilla