Bug 1669129 - [devtools] Enable devtools.overflow.debugging.enabled. r=jdescottes
[gecko.git] / editor / libeditor / HTMLEditorCommands.cpp
blobc3f4c4972eebda03fdfdb4e057fcf5dead236808
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 TextEditor* aTextEditor) const {
51 if (!aTextEditor) {
52 return false;
54 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
55 if (!htmlEditor) {
56 return false;
58 if (!htmlEditor->IsSelectionEditable()) {
59 return false;
61 if (aCommand == Command::FormatAbsolutePosition) {
62 return htmlEditor->IsAbsolutePositionEditorEnabled();
64 return true;
67 nsresult StateUpdatingCommandBase::DoCommand(Command aCommand,
68 TextEditor& aTextEditor,
69 nsIPrincipal* aPrincipal) const {
70 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
71 if (NS_WARN_IF(!htmlEditor)) {
72 return NS_ERROR_FAILURE;
74 nsStaticAtom* tagName = GetTagName(aCommand);
75 if (NS_WARN_IF(!tagName)) {
76 return NS_ERROR_UNEXPECTED;
78 nsresult rv = ToggleState(MOZ_KnownLive(*tagName), MOZ_KnownLive(*htmlEditor),
79 aPrincipal);
80 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
81 "StateUpdatingCommandBase::ToggleState() failed");
82 return rv;
85 nsresult StateUpdatingCommandBase::GetCommandStateParams(
86 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
87 nsIEditingSession* aEditingSession) const {
88 if (!aTextEditor) {
89 return NS_OK;
91 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
92 if (NS_WARN_IF(!htmlEditor)) {
93 return NS_ERROR_FAILURE;
95 nsAtom* tagName = GetTagName(aCommand);
96 if (NS_WARN_IF(!tagName)) {
97 return NS_ERROR_UNEXPECTED;
99 nsresult rv = GetCurrentState(MOZ_KnownLive(tagName),
100 MOZ_KnownLive(htmlEditor), aParams);
101 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
102 "StateUpdatingCommandBase::GetCurrentState() failed");
103 return rv;
106 /*****************************************************************************
107 * mozilla::PasteNoFormattingCommand
108 *****************************************************************************/
110 StaticRefPtr<PasteNoFormattingCommand> PasteNoFormattingCommand::sInstance;
112 bool PasteNoFormattingCommand::IsCommandEnabled(Command aCommand,
113 TextEditor* aTextEditor) const {
114 if (!aTextEditor) {
115 return false;
117 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
118 if (!htmlEditor) {
119 return false;
121 return htmlEditor->CanPaste(nsIClipboard::kGlobalClipboard);
124 nsresult PasteNoFormattingCommand::DoCommand(Command aCommand,
125 TextEditor& aTextEditor,
126 nsIPrincipal* aPrincipal) const {
127 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
128 if (NS_WARN_IF(!htmlEditor)) {
129 return NS_ERROR_FAILURE;
131 // Known live because we hold a ref above in "editor"
132 nsresult rv = MOZ_KnownLive(htmlEditor)
133 ->PasteNoFormattingAsAction(nsIClipboard::kGlobalClipboard,
134 aPrincipal);
135 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
136 "HTMLEditor::PasteNoFormattingAsAction() failed");
137 return rv;
140 nsresult PasteNoFormattingCommand::GetCommandStateParams(
141 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
142 nsIEditingSession* aEditingSession) const {
143 return aParams.SetBool(STATE_ENABLED,
144 IsCommandEnabled(aCommand, aTextEditor));
147 /*****************************************************************************
148 * mozilla::StyleUpdatingCommand
149 *****************************************************************************/
151 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
153 nsresult StyleUpdatingCommand::GetCurrentState(nsAtom* aTagName,
154 HTMLEditor* aHTMLEditor,
155 nsCommandParams& aParams) const {
156 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
157 return NS_ERROR_INVALID_ARG;
160 bool firstOfSelectionHasProp = false;
161 bool anyOfSelectionHasProp = false;
162 bool allOfSelectionHasProp = false;
164 nsresult rv = aHTMLEditor->GetInlineProperty(
165 aTagName, nullptr, u""_ns, &firstOfSelectionHasProp,
166 &anyOfSelectionHasProp, &allOfSelectionHasProp);
167 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
168 "HTMLEditor::GetInlineProperty() failed");
170 aParams.SetBool(STATE_ENABLED, NS_SUCCEEDED(rv));
171 aParams.SetBool(STATE_ALL, allOfSelectionHasProp);
172 aParams.SetBool(STATE_ANY, anyOfSelectionHasProp);
173 aParams.SetBool(STATE_MIXED, anyOfSelectionHasProp && !allOfSelectionHasProp);
174 aParams.SetBool(STATE_BEGIN, firstOfSelectionHasProp);
175 aParams.SetBool(STATE_END, allOfSelectionHasProp); // not completely accurate
176 return NS_OK;
179 nsresult StyleUpdatingCommand::ToggleState(nsStaticAtom& aTagName,
180 HTMLEditor& aHTMLEditor,
181 nsIPrincipal* aPrincipal) const {
182 RefPtr<nsCommandParams> params = new nsCommandParams();
184 // tags "href" and "name" are special cases in the core editor
185 // they are used to remove named anchor/link and shouldn't be used for
186 // insertion
187 bool doTagRemoval;
188 if (&aTagName == nsGkAtoms::href || &aTagName == nsGkAtoms::name) {
189 doTagRemoval = true;
190 } else {
191 // check current selection; set doTagRemoval if formatting should be removed
192 nsresult rv = GetCurrentState(&aTagName, &aHTMLEditor, *params);
193 if (NS_FAILED(rv)) {
194 NS_WARNING("StyleUpdatingCommand::GetCurrentState() failed");
195 return rv;
197 ErrorResult error;
198 doTagRemoval = params->GetBool(STATE_ALL, error);
199 if (NS_WARN_IF(error.Failed())) {
200 return error.StealNSResult();
204 if (doTagRemoval) {
205 nsresult rv =
206 aHTMLEditor.RemoveInlinePropertyAsAction(aTagName, nullptr, aPrincipal);
207 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
208 "HTMLEditor::RemoveInlinePropertyAsAction() failed");
209 return rv;
212 nsresult rv = aHTMLEditor.SetInlinePropertyAsAction(aTagName, nullptr, u""_ns,
213 aPrincipal);
214 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
215 "HTMLEditor::SetInlinePropertyAsAction() failed");
216 return rv;
219 /*****************************************************************************
220 * mozilla::ListCommand
221 *****************************************************************************/
223 StaticRefPtr<ListCommand> ListCommand::sInstance;
225 nsresult ListCommand::GetCurrentState(nsAtom* aTagName, HTMLEditor* aHTMLEditor,
226 nsCommandParams& aParams) const {
227 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
228 return NS_ERROR_INVALID_ARG;
231 bool bMixed;
232 nsAutoString localName;
233 nsresult rv = GetListState(aHTMLEditor, &bMixed, localName);
234 if (NS_FAILED(rv)) {
235 NS_WARNING("GetListState() failed");
236 return rv;
239 bool inList = aTagName->Equals(localName);
240 aParams.SetBool(STATE_ALL, !bMixed && inList);
241 aParams.SetBool(STATE_MIXED, bMixed);
242 aParams.SetBool(STATE_ENABLED, true);
243 return NS_OK;
246 nsresult ListCommand::ToggleState(nsStaticAtom& aTagName,
247 HTMLEditor& aHTMLEditor,
248 nsIPrincipal* aPrincipal) const {
249 RefPtr<nsCommandParams> params = new nsCommandParams();
250 nsresult rv = GetCurrentState(&aTagName, &aHTMLEditor, *params);
251 if (NS_FAILED(rv)) {
252 NS_WARNING("ListCommand::GetCurrentState() failed");
253 return rv;
256 ErrorResult error;
257 bool inList = params->GetBool(STATE_ALL, error);
258 if (NS_WARN_IF(error.Failed())) {
259 return error.StealNSResult();
262 nsDependentAtomString listType(&aTagName);
263 if (inList) {
264 nsresult rv = aHTMLEditor.RemoveListAsAction(listType, aPrincipal);
265 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
266 "HTMLEditor::RemoveListAsAction() failed");
267 return rv;
270 rv = aHTMLEditor.MakeOrChangeListAsAction(
271 aTagName, u""_ns, HTMLEditor::SelectAllOfCurrentList::No, aPrincipal);
272 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
273 "HTMLEditor::MakeOrChangeListAsAction() failed");
274 return rv;
277 /*****************************************************************************
278 * mozilla::ListItemCommand
279 *****************************************************************************/
281 StaticRefPtr<ListItemCommand> ListItemCommand::sInstance;
283 nsresult ListItemCommand::GetCurrentState(nsAtom* aTagName,
284 HTMLEditor* aHTMLEditor,
285 nsCommandParams& aParams) const {
286 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
287 return NS_ERROR_INVALID_ARG;
290 ErrorResult error;
291 ListItemElementSelectionState state(*aHTMLEditor, error);
292 if (error.Failed()) {
293 NS_WARNING("ListItemElementSelectionState failed");
294 return error.StealNSResult();
297 if (state.IsNotOneTypeDefinitionListItemElementSelected()) {
298 aParams.SetBool(STATE_ALL, false);
299 aParams.SetBool(STATE_MIXED, true);
300 return NS_OK;
303 nsStaticAtom* selectedListItemTagName = nullptr;
304 if (state.IsLIElementSelected()) {
305 selectedListItemTagName = nsGkAtoms::li;
306 } else if (state.IsDTElementSelected()) {
307 selectedListItemTagName = nsGkAtoms::dt;
308 } else if (state.IsDDElementSelected()) {
309 selectedListItemTagName = nsGkAtoms::dd;
311 aParams.SetBool(STATE_ALL, aTagName == selectedListItemTagName);
312 aParams.SetBool(STATE_MIXED, false);
313 return NS_OK;
316 nsresult ListItemCommand::ToggleState(nsStaticAtom& aTagName,
317 HTMLEditor& aHTMLEditor,
318 nsIPrincipal* aPrincipal) const {
319 // Need to use aTagName????
320 RefPtr<nsCommandParams> params = new nsCommandParams();
321 GetCurrentState(&aTagName, &aHTMLEditor, *params);
322 ErrorResult error;
323 bool inList = params->GetBool(STATE_ALL, error);
324 if (NS_WARN_IF(error.Failed())) {
325 return error.StealNSResult();
328 if (inList) {
329 // To remove a list, first get what kind of list we're in
330 bool bMixed;
331 nsAutoString localName;
332 nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
333 if (NS_FAILED(rv)) {
334 NS_WARNING("GetListState() failed");
335 return rv;
337 if (localName.IsEmpty() || bMixed) {
338 return NS_OK;
340 rv = aHTMLEditor.RemoveListAsAction(localName, aPrincipal);
341 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
342 "HTMLEditor::RemoveListAsAction() failed");
343 return rv;
346 // Set to the requested paragraph type
347 // XXX Note: This actually doesn't work for "LI",
348 // but we currently don't use this for non DL lists anyway.
349 // Problem: won't this replace any current block paragraph style?
350 nsresult rv = aHTMLEditor.SetParagraphFormatAsAction(
351 nsDependentAtomString(&aTagName), aPrincipal);
352 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
353 "HTMLEditor::SetParagraphFormatAsAction() failed");
354 return rv;
357 /*****************************************************************************
358 * mozilla::RemoveListCommand
359 *****************************************************************************/
361 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
363 bool RemoveListCommand::IsCommandEnabled(Command aCommand,
364 TextEditor* aTextEditor) const {
365 if (!aTextEditor) {
366 return false;
369 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
370 if (!htmlEditor) {
371 return false;
374 if (!htmlEditor->IsSelectionEditable()) {
375 return false;
378 // It is enabled if we are in any list type
379 bool bMixed;
380 nsAutoString localName;
381 nsresult rv = GetListState(MOZ_KnownLive(htmlEditor), &bMixed, localName);
382 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetListState() failed");
383 return NS_SUCCEEDED(rv) && (bMixed || !localName.IsEmpty());
386 nsresult RemoveListCommand::DoCommand(Command aCommand, TextEditor& aTextEditor,
387 nsIPrincipal* aPrincipal) const {
388 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
389 if (NS_WARN_IF(!htmlEditor)) {
390 return NS_OK;
392 // This removes any list type
393 nsresult rv =
394 MOZ_KnownLive(htmlEditor)->RemoveListAsAction(u""_ns, aPrincipal);
395 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
396 "HTMLEditor::RemoveListAsAction() failed");
397 return rv;
400 nsresult RemoveListCommand::GetCommandStateParams(
401 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
402 nsIEditingSession* aEditingSession) const {
403 return aParams.SetBool(STATE_ENABLED,
404 IsCommandEnabled(aCommand, aTextEditor));
407 /*****************************************************************************
408 * mozilla::IndentCommand
409 *****************************************************************************/
411 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
413 bool IndentCommand::IsCommandEnabled(Command aCommand,
414 TextEditor* aTextEditor) const {
415 if (!aTextEditor) {
416 return false;
418 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
419 if (!htmlEditor) {
420 return false;
422 return htmlEditor->IsSelectionEditable();
425 nsresult IndentCommand::DoCommand(Command aCommand, TextEditor& aTextEditor,
426 nsIPrincipal* aPrincipal) const {
427 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
428 if (NS_WARN_IF(!htmlEditor)) {
429 return NS_OK;
431 nsresult rv = MOZ_KnownLive(htmlEditor)->IndentAsAction(aPrincipal);
432 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::IndentAsAction() failed");
433 return rv;
436 nsresult IndentCommand::GetCommandStateParams(
437 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
438 nsIEditingSession* aEditingSession) const {
439 return aParams.SetBool(STATE_ENABLED,
440 IsCommandEnabled(aCommand, aTextEditor));
443 /*****************************************************************************
444 * mozilla::OutdentCommand
445 *****************************************************************************/
447 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
449 bool OutdentCommand::IsCommandEnabled(Command aCommand,
450 TextEditor* aTextEditor) const {
451 if (!aTextEditor) {
452 return false;
454 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
455 if (!htmlEditor) {
456 return false;
458 return htmlEditor->IsSelectionEditable();
461 nsresult OutdentCommand::DoCommand(Command aCommand, TextEditor& aTextEditor,
462 nsIPrincipal* aPrincipal) const {
463 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
464 if (NS_WARN_IF(!htmlEditor)) {
465 return NS_OK;
467 nsresult rv = MOZ_KnownLive(htmlEditor)->OutdentAsAction(aPrincipal);
468 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
469 "HTMLEditor::OutdentAsAction() failed");
470 return rv;
473 nsresult OutdentCommand::GetCommandStateParams(
474 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
475 nsIEditingSession* aEditingSession) const {
476 return aParams.SetBool(STATE_ENABLED,
477 IsCommandEnabled(aCommand, aTextEditor));
480 /*****************************************************************************
481 * mozilla::MultiStateCommandBase
482 *****************************************************************************/
484 bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
485 TextEditor* aTextEditor) const {
486 if (!aTextEditor) {
487 return false;
489 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
490 if (!htmlEditor) {
491 return false;
493 // should be disabled sometimes, like if the current selection is an image
494 return htmlEditor->IsSelectionEditable();
497 nsresult MultiStateCommandBase::DoCommand(Command aCommand,
498 TextEditor& aTextEditor,
499 nsIPrincipal* aPrincipal) const {
500 NS_WARNING(
501 "who is calling MultiStateCommandBase::DoCommand (no implementation)?");
502 return NS_OK;
505 nsresult MultiStateCommandBase::DoCommandParam(Command aCommand,
506 const nsAString& aStringParam,
507 TextEditor& aTextEditor,
508 nsIPrincipal* aPrincipal) const {
509 NS_WARNING_ASSERTION(aCommand != Command::FormatJustify,
510 "Command::FormatJustify should be used only for "
511 "IsCommandEnabled() and GetCommandStateParams()");
512 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
513 if (NS_WARN_IF(!htmlEditor)) {
514 return NS_ERROR_FAILURE;
516 nsresult rv = SetState(MOZ_KnownLive(htmlEditor), aStringParam, aPrincipal);
517 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
518 "MultiStateCommandBase::SetState() failed");
519 return rv;
522 nsresult MultiStateCommandBase::GetCommandStateParams(
523 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
524 nsIEditingSession* aEditingSession) const {
525 if (!aTextEditor) {
526 return NS_OK;
528 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
529 if (NS_WARN_IF(!htmlEditor)) {
530 return NS_ERROR_FAILURE;
532 nsresult rv = GetCurrentState(MOZ_KnownLive(htmlEditor), aParams);
533 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
534 "MultiStateCommandBase::GetCurrentState() failed");
535 return rv;
538 /*****************************************************************************
539 * mozilla::ParagraphStateCommand
540 *****************************************************************************/
542 StaticRefPtr<ParagraphStateCommand> ParagraphStateCommand::sInstance;
544 nsresult ParagraphStateCommand::GetCurrentState(
545 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
546 if (NS_WARN_IF(!aHTMLEditor)) {
547 return NS_ERROR_INVALID_ARG;
550 ErrorResult error;
551 ParagraphStateAtSelection state(*aHTMLEditor, error);
552 if (error.Failed()) {
553 NS_WARNING("ParagraphStateAtSelection failed");
554 return error.StealNSResult();
556 aParams.SetBool(STATE_MIXED, state.IsMixed());
557 if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
558 // XXX This is odd behavior, we should fix this later.
559 aParams.SetCString(STATE_ATTRIBUTE, "x"_ns);
560 } else {
561 nsCString paragraphState; // Don't use `nsAutoCString` for avoiding copy.
562 state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
563 aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
565 return NS_OK;
568 nsresult ParagraphStateCommand::SetState(HTMLEditor* aHTMLEditor,
569 const nsAString& aNewState,
570 nsIPrincipal* aPrincipal) const {
571 if (NS_WARN_IF(!aHTMLEditor)) {
572 return NS_ERROR_INVALID_ARG;
574 nsresult rv = aHTMLEditor->SetParagraphFormatAsAction(aNewState, aPrincipal);
575 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
576 "HTMLEditor::SetParagraphFormatAsAction() failed");
577 return rv;
580 /*****************************************************************************
581 * mozilla::FontFaceStateCommand
582 *****************************************************************************/
584 StaticRefPtr<FontFaceStateCommand> FontFaceStateCommand::sInstance;
586 nsresult FontFaceStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
587 nsCommandParams& aParams) const {
588 if (NS_WARN_IF(!aHTMLEditor)) {
589 return NS_ERROR_INVALID_ARG;
592 nsAutoString outStateString;
593 bool outMixed;
594 nsresult rv = aHTMLEditor->GetFontFaceState(&outMixed, outStateString);
595 if (NS_FAILED(rv)) {
596 NS_WARNING("HTMLEditor::GetFontFaceState() failed");
597 return rv;
599 aParams.SetBool(STATE_MIXED, outMixed);
600 aParams.SetCString(STATE_ATTRIBUTE, NS_ConvertUTF16toUTF8(outStateString));
601 return NS_OK;
604 nsresult FontFaceStateCommand::SetState(HTMLEditor* aHTMLEditor,
605 const nsAString& aNewState,
606 nsIPrincipal* aPrincipal) const {
607 if (NS_WARN_IF(!aHTMLEditor)) {
608 return NS_ERROR_INVALID_ARG;
611 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
612 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
613 *nsGkAtoms::font, nsGkAtoms::face, aPrincipal);
614 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
615 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
616 "font, nsGkAtoms::face) failed");
617 return rv;
620 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
621 *nsGkAtoms::font, nsGkAtoms::face, aNewState, aPrincipal);
622 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
623 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
624 "nsGkAtoms::face) failed");
625 return rv;
628 /*****************************************************************************
629 * mozilla::FontSizeStateCommand
630 *****************************************************************************/
632 StaticRefPtr<FontSizeStateCommand> FontSizeStateCommand::sInstance;
634 nsresult FontSizeStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
635 nsCommandParams& aParams) const {
636 if (NS_WARN_IF(!aHTMLEditor)) {
637 return NS_ERROR_INVALID_ARG;
640 nsAutoString outStateString;
641 bool firstHas, anyHas, allHas;
642 nsresult rv = aHTMLEditor->GetInlinePropertyWithAttrValue(
643 nsGkAtoms::font, nsGkAtoms::size, u""_ns, &firstHas, &anyHas, &allHas,
644 outStateString);
645 if (NS_FAILED(rv)) {
646 NS_WARNING(
647 "HTMLEditor::GetInlinePropertyWithAttrValue(nsGkAtoms::font, "
648 "nsGkAtoms::size) failed");
649 return rv;
652 nsAutoCString tOutStateString;
653 LossyCopyUTF16toASCII(outStateString, tOutStateString);
654 aParams.SetBool(STATE_MIXED, anyHas && !allHas);
655 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
656 aParams.SetBool(STATE_ENABLED, true);
658 return NS_OK;
661 // acceptable values for "aNewState" are:
662 // -2
663 // -1
664 // 0
665 // +1
666 // +2
667 // +3
668 // medium
669 // normal
670 nsresult FontSizeStateCommand::SetState(HTMLEditor* aHTMLEditor,
671 const nsAString& aNewState,
672 nsIPrincipal* aPrincipal) const {
673 if (NS_WARN_IF(!aHTMLEditor)) {
674 return NS_ERROR_INVALID_ARG;
677 if (!aNewState.IsEmpty() && !aNewState.EqualsLiteral("normal") &&
678 !aNewState.EqualsLiteral("medium")) {
679 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
680 *nsGkAtoms::font, nsGkAtoms::size, aNewState, aPrincipal);
681 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
682 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::"
683 "font, nsGkAtoms::size) failed");
684 return rv;
687 // remove any existing font size, big or small
688 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
689 *nsGkAtoms::font, nsGkAtoms::size, aPrincipal);
690 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
691 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
692 "font, nsGkAtoms::size) failed");
693 return rv;
696 /*****************************************************************************
697 * mozilla::FontColorStateCommand
698 *****************************************************************************/
700 StaticRefPtr<FontColorStateCommand> FontColorStateCommand::sInstance;
702 nsresult FontColorStateCommand::GetCurrentState(
703 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
704 if (NS_WARN_IF(!aHTMLEditor)) {
705 return NS_ERROR_INVALID_ARG;
708 bool outMixed;
709 nsAutoString outStateString;
710 nsresult rv = aHTMLEditor->GetFontColorState(&outMixed, outStateString);
711 if (NS_FAILED(rv)) {
712 NS_WARNING("HTMLEditor::GetFontColorState() failed");
713 return rv;
716 nsAutoCString tOutStateString;
717 LossyCopyUTF16toASCII(outStateString, tOutStateString);
718 aParams.SetBool(STATE_MIXED, outMixed);
719 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
720 return NS_OK;
723 nsresult FontColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
724 const nsAString& aNewState,
725 nsIPrincipal* aPrincipal) const {
726 if (NS_WARN_IF(!aHTMLEditor)) {
727 return NS_ERROR_INVALID_ARG;
730 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
731 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
732 *nsGkAtoms::font, nsGkAtoms::color, aPrincipal);
733 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
734 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
735 "font, nsGkAtoms::color) failed");
736 return rv;
739 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
740 *nsGkAtoms::font, nsGkAtoms::color, aNewState, aPrincipal);
741 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
742 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
743 "nsGkAtoms::color) failed");
744 return rv;
747 /*****************************************************************************
748 * mozilla::HighlightColorStateCommand
749 *****************************************************************************/
751 StaticRefPtr<HighlightColorStateCommand> HighlightColorStateCommand::sInstance;
753 nsresult HighlightColorStateCommand::GetCurrentState(
754 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
755 if (NS_WARN_IF(!aHTMLEditor)) {
756 return NS_ERROR_INVALID_ARG;
759 bool outMixed;
760 nsAutoString outStateString;
761 nsresult rv = aHTMLEditor->GetHighlightColorState(&outMixed, outStateString);
762 if (NS_FAILED(rv)) {
763 NS_WARNING("HTMLEditor::GetHighlightColorState() failed");
764 return rv;
767 nsAutoCString tOutStateString;
768 LossyCopyUTF16toASCII(outStateString, tOutStateString);
769 aParams.SetBool(STATE_MIXED, outMixed);
770 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
771 return NS_OK;
774 nsresult HighlightColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
775 const nsAString& aNewState,
776 nsIPrincipal* aPrincipal) const {
777 if (NS_WARN_IF(!aHTMLEditor)) {
778 return NS_ERROR_INVALID_ARG;
781 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
782 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
783 *nsGkAtoms::font, nsGkAtoms::bgcolor, aPrincipal);
784 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
785 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
786 "font, nsGkAtoms::bgcolor) failed");
787 return rv;
790 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
791 *nsGkAtoms::font, nsGkAtoms::bgcolor, aNewState, aPrincipal);
792 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
793 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
794 "nsGkAtoms::bgcolor) failed");
795 return rv;
798 /*****************************************************************************
799 * mozilla::BackgroundColorStateCommand
800 *****************************************************************************/
802 StaticRefPtr<BackgroundColorStateCommand>
803 BackgroundColorStateCommand::sInstance;
805 nsresult BackgroundColorStateCommand::GetCurrentState(
806 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
807 if (NS_WARN_IF(!aHTMLEditor)) {
808 return NS_ERROR_INVALID_ARG;
811 bool outMixed;
812 nsAutoString outStateString;
813 nsresult rv = aHTMLEditor->GetBackgroundColorState(&outMixed, outStateString);
814 if (NS_FAILED(rv)) {
815 NS_WARNING("HTMLEditor::GetBackgroundColorState() failed");
816 return rv;
819 nsAutoCString tOutStateString;
820 LossyCopyUTF16toASCII(outStateString, tOutStateString);
821 aParams.SetBool(STATE_MIXED, outMixed);
822 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
823 return NS_OK;
826 nsresult BackgroundColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
827 const nsAString& aNewState,
828 nsIPrincipal* aPrincipal) const {
829 if (NS_WARN_IF(!aHTMLEditor)) {
830 return NS_ERROR_INVALID_ARG;
832 nsresult rv = aHTMLEditor->SetBackgroundColorAsAction(aNewState, aPrincipal);
833 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
834 "HTMLEditor::SetBackgroundColorAsAction() failed");
835 return rv;
838 /*****************************************************************************
839 * mozilla::AlignCommand
840 *****************************************************************************/
842 StaticRefPtr<AlignCommand> AlignCommand::sInstance;
844 nsresult AlignCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
845 nsCommandParams& aParams) const {
846 if (NS_WARN_IF(!aHTMLEditor)) {
847 return NS_ERROR_INVALID_ARG;
850 ErrorResult error;
851 AlignStateAtSelection state(*aHTMLEditor, error);
852 if (error.Failed()) {
853 if (!state.IsSelectionRangesFound()) {
854 // If there was no selection ranges, we shouldn't throw exception for
855 // compatibility with the other browsers, but I have no better idea
856 // than returning empty string in this case. Oddly, Blink/WebKit returns
857 // "true" or "false", but it's different from us and the value does not
858 // make sense. Additionally, WPT loves our behavior.
859 error.SuppressException();
860 aParams.SetBool(STATE_MIXED, false);
861 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
862 return NS_OK;
864 NS_WARNING("AlignStateAtSelection failed");
865 return error.StealNSResult();
867 nsCString alignment; // Don't use `nsAutoCString` to avoid copying string.
868 switch (state.AlignmentAtSelectionStart()) {
869 default:
870 case nsIHTMLEditor::eLeft:
871 alignment.AssignLiteral("left");
872 break;
873 case nsIHTMLEditor::eCenter:
874 alignment.AssignLiteral("center");
875 break;
876 case nsIHTMLEditor::eRight:
877 alignment.AssignLiteral("right");
878 break;
879 case nsIHTMLEditor::eJustify:
880 alignment.AssignLiteral("justify");
881 break;
883 aParams.SetBool(STATE_MIXED, false);
884 aParams.SetCString(STATE_ATTRIBUTE, alignment);
885 return NS_OK;
888 nsresult AlignCommand::SetState(HTMLEditor* aHTMLEditor,
889 const nsAString& aNewState,
890 nsIPrincipal* aPrincipal) const {
891 if (NS_WARN_IF(!aHTMLEditor)) {
892 return NS_ERROR_INVALID_ARG;
894 nsresult rv = aHTMLEditor->AlignAsAction(aNewState, aPrincipal);
895 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::AlignAsAction() failed");
896 return rv;
899 /*****************************************************************************
900 * mozilla::AbsolutePositioningCommand
901 *****************************************************************************/
903 StaticRefPtr<AbsolutePositioningCommand> AbsolutePositioningCommand::sInstance;
905 nsresult AbsolutePositioningCommand::GetCurrentState(
906 nsAtom* aTagName, HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
907 if (NS_WARN_IF(!aHTMLEditor)) {
908 return NS_ERROR_INVALID_ARG;
911 if (!aHTMLEditor->IsAbsolutePositionEditorEnabled()) {
912 aParams.SetBool(STATE_MIXED, false);
913 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
914 return NS_OK;
917 RefPtr<Element> container =
918 aHTMLEditor->GetAbsolutelyPositionedSelectionContainer();
919 aParams.SetBool(STATE_MIXED, false);
920 aParams.SetCString(STATE_ATTRIBUTE, container ? "absolute"_ns : ""_ns);
921 return NS_OK;
924 nsresult AbsolutePositioningCommand::ToggleState(
925 nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
926 nsIPrincipal* aPrincipal) const {
927 RefPtr<Element> container =
928 aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
929 nsresult rv = aHTMLEditor.SetSelectionToAbsoluteOrStaticAsAction(!container,
930 aPrincipal);
931 NS_WARNING_ASSERTION(
932 NS_SUCCEEDED(rv),
933 "HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction() failed");
934 return rv;
937 /*****************************************************************************
938 * mozilla::DecreaseZIndexCommand
939 *****************************************************************************/
941 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
943 bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
944 TextEditor* aTextEditor) const {
945 if (!aTextEditor) {
946 return false;
948 RefPtr<HTMLEditor> htmlEditor = aTextEditor->AsHTMLEditor();
949 if (!htmlEditor) {
950 return false;
952 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
953 return false;
955 RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
956 if (!positionedElement) {
957 return false;
959 return htmlEditor->GetZIndex(*positionedElement) > 0;
962 nsresult DecreaseZIndexCommand::DoCommand(Command aCommand,
963 TextEditor& aTextEditor,
964 nsIPrincipal* aPrincipal) const {
965 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
966 if (NS_WARN_IF(!htmlEditor)) {
967 return NS_ERROR_FAILURE;
969 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(-1, aPrincipal);
970 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
971 "HTMLEditor::AddZIndexAsAction(-1) failed");
972 return rv;
975 nsresult DecreaseZIndexCommand::GetCommandStateParams(
976 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
977 nsIEditingSession* aEditingSession) const {
978 return aParams.SetBool(STATE_ENABLED,
979 IsCommandEnabled(aCommand, aTextEditor));
982 /*****************************************************************************
983 * mozilla::IncreaseZIndexCommand
984 *****************************************************************************/
986 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
988 bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
989 TextEditor* aTextEditor) const {
990 if (!aTextEditor) {
991 return false;
993 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
994 if (!htmlEditor) {
995 return false;
997 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
998 return false;
1000 return !!htmlEditor->GetPositionedElement();
1003 nsresult IncreaseZIndexCommand::DoCommand(Command aCommand,
1004 TextEditor& aTextEditor,
1005 nsIPrincipal* aPrincipal) const {
1006 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1007 if (NS_WARN_IF(!htmlEditor)) {
1008 return NS_ERROR_FAILURE;
1010 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(1, aPrincipal);
1011 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1012 "HTMLEditor::AddZIndexAsAction(1) failed");
1013 return rv;
1016 nsresult IncreaseZIndexCommand::GetCommandStateParams(
1017 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
1018 nsIEditingSession* aEditingSession) const {
1019 return aParams.SetBool(STATE_ENABLED,
1020 IsCommandEnabled(aCommand, aTextEditor));
1023 /*****************************************************************************
1024 * mozilla::RemoveStylesCommand
1025 *****************************************************************************/
1027 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
1029 bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
1030 TextEditor* aTextEditor) const {
1031 if (!aTextEditor) {
1032 return false;
1034 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
1035 if (!htmlEditor) {
1036 return false;
1038 // test if we have any styles?
1039 return htmlEditor->IsSelectionEditable();
1042 nsresult RemoveStylesCommand::DoCommand(Command aCommand,
1043 TextEditor& aTextEditor,
1044 nsIPrincipal* aPrincipal) const {
1045 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1046 if (NS_WARN_IF(!htmlEditor)) {
1047 return NS_OK;
1049 nsresult rv =
1050 MOZ_KnownLive(htmlEditor)->RemoveAllInlinePropertiesAsAction(aPrincipal);
1051 NS_WARNING_ASSERTION(
1052 NS_SUCCEEDED(rv),
1053 "HTMLEditor::RemoveAllInlinePropertiesAsAction() failed");
1054 return rv;
1057 nsresult RemoveStylesCommand::GetCommandStateParams(
1058 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
1059 nsIEditingSession* aEditingSession) const {
1060 return aParams.SetBool(STATE_ENABLED,
1061 IsCommandEnabled(aCommand, aTextEditor));
1064 /*****************************************************************************
1065 * mozilla::IncreaseFontSizeCommand
1066 *****************************************************************************/
1068 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
1070 bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1071 TextEditor* aTextEditor) const {
1072 if (!aTextEditor) {
1073 return false;
1075 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
1076 if (!htmlEditor) {
1077 return false;
1079 // test if we are at max size?
1080 return htmlEditor->IsSelectionEditable();
1083 nsresult IncreaseFontSizeCommand::DoCommand(Command aCommand,
1084 TextEditor& aTextEditor,
1085 nsIPrincipal* aPrincipal) const {
1086 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1087 if (NS_WARN_IF(!htmlEditor)) {
1088 return NS_OK;
1090 nsresult rv = MOZ_KnownLive(htmlEditor)->IncreaseFontSizeAsAction(aPrincipal);
1091 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1092 "HTMLEditor::IncreaseFontSizeAsAction() failed");
1093 return rv;
1096 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
1097 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
1098 nsIEditingSession* aEditingSession) const {
1099 return aParams.SetBool(STATE_ENABLED,
1100 IsCommandEnabled(aCommand, aTextEditor));
1103 /*****************************************************************************
1104 * mozilla::DecreaseFontSizeCommand
1105 *****************************************************************************/
1107 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
1109 bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1110 TextEditor* aTextEditor) const {
1111 if (!aTextEditor) {
1112 return false;
1114 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
1115 if (!htmlEditor) {
1116 return false;
1118 // test if we are at min size?
1119 return htmlEditor->IsSelectionEditable();
1122 nsresult DecreaseFontSizeCommand::DoCommand(Command aCommand,
1123 TextEditor& aTextEditor,
1124 nsIPrincipal* aPrincipal) const {
1125 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1126 if (NS_WARN_IF(!htmlEditor)) {
1127 return NS_OK;
1129 nsresult rv = MOZ_KnownLive(htmlEditor)->DecreaseFontSizeAsAction(aPrincipal);
1130 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1131 "HTMLEditor::DecreaseFontSizeAsAction() failed");
1132 return rv;
1135 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
1136 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
1137 nsIEditingSession* aEditingSession) const {
1138 return aParams.SetBool(STATE_ENABLED,
1139 IsCommandEnabled(aCommand, aTextEditor));
1142 /*****************************************************************************
1143 * mozilla::InsertHTMLCommand
1144 *****************************************************************************/
1146 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
1148 bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
1149 TextEditor* aTextEditor) const {
1150 if (!aTextEditor) {
1151 return false;
1153 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
1154 if (!htmlEditor) {
1155 return false;
1157 return htmlEditor->IsSelectionEditable();
1160 nsresult InsertHTMLCommand::DoCommand(Command aCommand, TextEditor& aTextEditor,
1161 nsIPrincipal* aPrincipal) const {
1162 // If InsertHTMLCommand is called with no parameters, it was probably called
1163 // with an empty string parameter ''. In this case, it should act the same as
1164 // the delete command
1165 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1166 if (NS_WARN_IF(!htmlEditor)) {
1167 return NS_ERROR_FAILURE;
1169 nsresult rv =
1170 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(u""_ns, aPrincipal);
1171 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1172 "HTMLEditor::InsertHTMLAsAction() failed");
1173 return rv;
1176 nsresult InsertHTMLCommand::DoCommandParam(Command aCommand,
1177 const nsAString& aStringParam,
1178 TextEditor& aTextEditor,
1179 nsIPrincipal* aPrincipal) const {
1180 if (NS_WARN_IF(aStringParam.IsVoid())) {
1181 return NS_ERROR_INVALID_ARG;
1184 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1185 if (NS_WARN_IF(!htmlEditor)) {
1186 return NS_ERROR_FAILURE;
1188 nsresult rv =
1189 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(aStringParam, aPrincipal);
1190 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1191 "HTMLEditor::InsertHTMLAsAction() failed");
1192 return rv;
1195 nsresult InsertHTMLCommand::GetCommandStateParams(
1196 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
1197 nsIEditingSession* aEditingSession) const {
1198 return aParams.SetBool(STATE_ENABLED,
1199 IsCommandEnabled(aCommand, aTextEditor));
1202 /*****************************************************************************
1203 * mozilla::InsertTagCommand
1204 *****************************************************************************/
1206 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
1208 bool InsertTagCommand::IsCommandEnabled(Command aCommand,
1209 TextEditor* aTextEditor) const {
1210 if (!aTextEditor) {
1211 return false;
1213 HTMLEditor* htmlEditor = aTextEditor->AsHTMLEditor();
1214 if (!htmlEditor) {
1215 return false;
1217 return htmlEditor->IsSelectionEditable();
1220 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
1221 nsresult InsertTagCommand::DoCommand(Command aCommand, TextEditor& aTextEditor,
1222 nsIPrincipal* aPrincipal) const {
1223 nsAtom* tagName = GetTagName(aCommand);
1224 if (NS_WARN_IF(tagName != nsGkAtoms::hr)) {
1225 return NS_ERROR_NOT_IMPLEMENTED;
1228 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1229 if (NS_WARN_IF(!htmlEditor)) {
1230 return NS_ERROR_FAILURE;
1233 RefPtr<Element> newElement =
1234 MOZ_KnownLive(htmlEditor)
1235 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1236 if (NS_WARN_IF(!newElement)) {
1237 return NS_ERROR_FAILURE;
1239 nsresult rv =
1240 MOZ_KnownLive(htmlEditor)
1241 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1242 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1243 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1244 return rv;
1247 nsresult InsertTagCommand::DoCommandParam(Command aCommand,
1248 const nsAString& aStringParam,
1249 TextEditor& aTextEditor,
1250 nsIPrincipal* aPrincipal) const {
1251 MOZ_ASSERT(aCommand != Command::InsertHorizontalRule);
1253 if (NS_WARN_IF(aStringParam.IsEmpty())) {
1254 return NS_ERROR_INVALID_ARG;
1256 nsAtom* tagName = GetTagName(aCommand);
1257 if (NS_WARN_IF(!tagName)) {
1258 return NS_ERROR_UNEXPECTED;
1261 HTMLEditor* htmlEditor = aTextEditor.AsHTMLEditor();
1262 if (NS_WARN_IF(!htmlEditor)) {
1263 return NS_ERROR_FAILURE;
1266 // filter out tags we don't know how to insert
1267 nsAtom* attribute = nullptr;
1268 if (tagName == nsGkAtoms::a) {
1269 attribute = nsGkAtoms::href;
1270 } else if (tagName == nsGkAtoms::img) {
1271 attribute = nsGkAtoms::src;
1272 } else {
1273 return NS_ERROR_NOT_IMPLEMENTED;
1276 RefPtr<Element> newElement =
1277 MOZ_KnownLive(htmlEditor)
1278 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1279 if (!newElement) {
1280 NS_WARNING("HTMLEditor::CreateElementWithDefaults() failed");
1281 return NS_ERROR_FAILURE;
1284 ErrorResult error;
1285 newElement->SetAttr(attribute, aStringParam, error);
1286 if (error.Failed()) {
1287 NS_WARNING("Element::SetAttr() failed");
1288 return error.StealNSResult();
1291 // do actual insertion
1292 if (tagName == nsGkAtoms::a) {
1293 nsresult rv =
1294 MOZ_KnownLive(htmlEditor)
1295 ->InsertLinkAroundSelectionAsAction(newElement, aPrincipal);
1296 NS_WARNING_ASSERTION(
1297 NS_SUCCEEDED(rv),
1298 "HTMLEditor::InsertLinkAroundSelectionAsAction() failed");
1299 return rv;
1302 nsresult rv =
1303 MOZ_KnownLive(htmlEditor)
1304 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1305 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1306 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1307 return rv;
1310 nsresult InsertTagCommand::GetCommandStateParams(
1311 Command aCommand, nsCommandParams& aParams, TextEditor* aTextEditor,
1312 nsIEditingSession* aEditingSession) const {
1313 return aParams.SetBool(STATE_ENABLED,
1314 IsCommandEnabled(aCommand, aTextEditor));
1317 /*****************************************************************************
1318 * Helper methods
1319 *****************************************************************************/
1321 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
1322 nsAString& aLocalName) {
1323 MOZ_ASSERT(aHTMLEditor);
1324 MOZ_ASSERT(aMixed);
1326 *aMixed = false;
1327 aLocalName.Truncate();
1329 ErrorResult error;
1330 ListElementSelectionState state(*aHTMLEditor, error);
1331 if (error.Failed()) {
1332 NS_WARNING("ListElementSelectionState failed");
1333 return error.StealNSResult();
1335 if (state.IsNotOneTypeListElementSelected()) {
1336 *aMixed = true;
1337 return NS_OK;
1340 if (state.IsOLElementSelected()) {
1341 aLocalName.AssignLiteral("ol");
1342 } else if (state.IsULElementSelected()) {
1343 aLocalName.AssignLiteral("ul");
1344 } else if (state.IsDLElementSelected()) {
1345 aLocalName.AssignLiteral("dl");
1347 return NS_OK;
1350 } // namespace mozilla