Bug 1772588 [wpt PR 34302] - [wpt] Add test for block-in-inline offsetParent., a...
[gecko.git] / editor / libeditor / HTMLEditorCommands.cpp
blob98db475c7f242a8daf18b253100a1c9430628c21
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 nsAtom* tagName = GetTagName(aCommand);
93 if (NS_WARN_IF(!tagName)) {
94 return NS_ERROR_UNEXPECTED;
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;
103 /*****************************************************************************
104 * mozilla::PasteNoFormattingCommand
105 *****************************************************************************/
107 StaticRefPtr<PasteNoFormattingCommand> PasteNoFormattingCommand::sInstance;
109 bool PasteNoFormattingCommand::IsCommandEnabled(Command aCommand,
110 EditorBase* aEditorBase) const {
111 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
112 if (!htmlEditor) {
113 return false;
115 return htmlEditor->CanPaste(nsIClipboard::kGlobalClipboard);
118 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;
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;
134 nsresult PasteNoFormattingCommand::GetCommandStateParams(
135 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
136 nsIEditingSession* aEditingSession) const {
137 return aParams.SetBool(STATE_ENABLED,
138 IsCommandEnabled(aCommand, aEditorBase));
141 /*****************************************************************************
142 * mozilla::StyleUpdatingCommand
143 *****************************************************************************/
145 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
147 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;
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(nsAtom* aTagName, HTMLEditor* aHTMLEditor,
220 nsCommandParams& aParams) const {
221 if (NS_WARN_IF(!aTagName) || NS_WARN_IF(!aHTMLEditor)) {
222 return NS_ERROR_INVALID_ARG;
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;
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;
240 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;
250 ErrorResult error;
251 bool inList = params->GetBool(STATE_ALL, error);
252 if (NS_WARN_IF(error.Failed())) {
253 return error.StealNSResult();
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;
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;
271 /*****************************************************************************
272 * mozilla::ListItemCommand
273 *****************************************************************************/
275 StaticRefPtr<ListItemCommand> ListItemCommand::sInstance;
277 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;
284 ErrorResult error;
285 ListItemElementSelectionState state(*aHTMLEditor, error);
286 if (error.Failed()) {
287 NS_WARNING("ListItemElementSelectionState failed");
288 return error.StealNSResult();
291 if (state.IsNotOneTypeDefinitionListItemElementSelected()) {
292 aParams.SetBool(STATE_ALL, false);
293 aParams.SetBool(STATE_MIXED, true);
294 return NS_OK;
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;
305 aParams.SetBool(STATE_ALL, aTagName == selectedListItemTagName);
306 aParams.SetBool(STATE_MIXED, false);
307 return NS_OK;
310 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();
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;
331 if (localName.IsEmpty() || bMixed) {
332 return NS_OK;
334 rv = aHTMLEditor.RemoveListAsAction(localName, aPrincipal);
335 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
336 "HTMLEditor::RemoveListAsAction() failed");
337 return rv;
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;
351 /*****************************************************************************
352 * mozilla::RemoveListCommand
353 *****************************************************************************/
355 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
357 bool RemoveListCommand::IsCommandEnabled(Command aCommand,
358 EditorBase* aEditorBase) const {
359 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
360 if (!htmlEditor) {
361 return false;
364 if (!htmlEditor->IsSelectionEditable()) {
365 return false;
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());
376 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;
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;
390 nsresult RemoveListCommand::GetCommandStateParams(
391 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
392 nsIEditingSession* aEditingSession) const {
393 return aParams.SetBool(STATE_ENABLED,
394 IsCommandEnabled(aCommand, aEditorBase));
397 /*****************************************************************************
398 * mozilla::IndentCommand
399 *****************************************************************************/
401 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
403 bool IndentCommand::IsCommandEnabled(Command aCommand,
404 EditorBase* aEditorBase) const {
405 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
406 if (!htmlEditor) {
407 return false;
409 return htmlEditor->IsSelectionEditable();
412 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;
418 nsresult rv = MOZ_KnownLive(htmlEditor)->IndentAsAction(aPrincipal);
419 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::IndentAsAction() failed");
420 return rv;
423 nsresult IndentCommand::GetCommandStateParams(
424 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
425 nsIEditingSession* aEditingSession) const {
426 return aParams.SetBool(STATE_ENABLED,
427 IsCommandEnabled(aCommand, aEditorBase));
430 /*****************************************************************************
431 * mozilla::OutdentCommand
432 *****************************************************************************/
434 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
436 bool OutdentCommand::IsCommandEnabled(Command aCommand,
437 EditorBase* aEditorBase) const {
438 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
439 if (!htmlEditor) {
440 return false;
442 return htmlEditor->IsSelectionEditable();
445 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;
451 nsresult rv = MOZ_KnownLive(htmlEditor)->OutdentAsAction(aPrincipal);
452 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
453 "HTMLEditor::OutdentAsAction() failed");
454 return rv;
457 nsresult OutdentCommand::GetCommandStateParams(
458 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
459 nsIEditingSession* aEditingSession) const {
460 return aParams.SetBool(STATE_ENABLED,
461 IsCommandEnabled(aCommand, aEditorBase));
464 /*****************************************************************************
465 * mozilla::MultiStateCommandBase
466 *****************************************************************************/
468 bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
469 EditorBase* aEditorBase) const {
470 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
471 if (!htmlEditor) {
472 return false;
474 // should be disabled sometimes, like if the current selection is an image
475 return htmlEditor->IsSelectionEditable();
478 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;
486 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;
497 nsresult rv = SetState(MOZ_KnownLive(htmlEditor), aStringParam, aPrincipal);
498 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
499 "MultiStateCommandBase::SetState() failed");
500 return rv;
503 nsresult MultiStateCommandBase::GetCommandStateParams(
504 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
505 nsIEditingSession* aEditingSession) const {
506 if (!aEditorBase) {
507 return NS_OK;
509 HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
510 if (NS_WARN_IF(!htmlEditor)) {
511 return NS_ERROR_FAILURE;
513 nsresult rv = GetCurrentState(MOZ_KnownLive(htmlEditor), aParams);
514 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
515 "MultiStateCommandBase::GetCurrentState() failed");
516 return rv;
519 /*****************************************************************************
520 * mozilla::ParagraphStateCommand
521 *****************************************************************************/
523 StaticRefPtr<ParagraphStateCommand> ParagraphStateCommand::sInstance;
525 nsresult ParagraphStateCommand::GetCurrentState(
526 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
527 if (NS_WARN_IF(!aHTMLEditor)) {
528 return NS_ERROR_INVALID_ARG;
531 ErrorResult error;
532 ParagraphStateAtSelection state(*aHTMLEditor, error);
533 if (error.Failed()) {
534 NS_WARNING("ParagraphStateAtSelection failed");
535 return error.StealNSResult();
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);
546 return NS_OK;
549 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;
555 nsresult rv = aHTMLEditor->SetParagraphFormatAsAction(aNewState, aPrincipal);
556 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
557 "HTMLEditor::SetParagraphFormatAsAction() failed");
558 return rv;
561 /*****************************************************************************
562 * mozilla::FontFaceStateCommand
563 *****************************************************************************/
565 StaticRefPtr<FontFaceStateCommand> FontFaceStateCommand::sInstance;
567 nsresult FontFaceStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
568 nsCommandParams& aParams) const {
569 if (NS_WARN_IF(!aHTMLEditor)) {
570 return NS_ERROR_INVALID_ARG;
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;
580 aParams.SetBool(STATE_MIXED, outMixed);
581 aParams.SetCString(STATE_ATTRIBUTE, NS_ConvertUTF16toUTF8(outStateString));
582 return NS_OK;
585 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;
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;
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;
609 /*****************************************************************************
610 * mozilla::FontSizeStateCommand
611 *****************************************************************************/
613 StaticRefPtr<FontSizeStateCommand> FontSizeStateCommand::sInstance;
615 nsresult FontSizeStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
616 nsCommandParams& aParams) const {
617 if (NS_WARN_IF(!aHTMLEditor)) {
618 return NS_ERROR_INVALID_ARG;
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;
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);
639 return NS_OK;
642 // acceptable values for "aNewState" are:
643 // -2
644 // -1
645 // 0
646 // +1
647 // +2
648 // +3
649 // medium
650 // normal
651 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;
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;
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;
677 /*****************************************************************************
678 * mozilla::FontColorStateCommand
679 *****************************************************************************/
681 StaticRefPtr<FontColorStateCommand> FontColorStateCommand::sInstance;
683 nsresult FontColorStateCommand::GetCurrentState(
684 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
685 if (NS_WARN_IF(!aHTMLEditor)) {
686 return NS_ERROR_INVALID_ARG;
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;
697 nsAutoCString tOutStateString;
698 LossyCopyUTF16toASCII(outStateString, tOutStateString);
699 aParams.SetBool(STATE_MIXED, outMixed);
700 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
701 return NS_OK;
704 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;
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;
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;
728 /*****************************************************************************
729 * mozilla::HighlightColorStateCommand
730 *****************************************************************************/
732 StaticRefPtr<HighlightColorStateCommand> HighlightColorStateCommand::sInstance;
734 nsresult HighlightColorStateCommand::GetCurrentState(
735 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
736 if (NS_WARN_IF(!aHTMLEditor)) {
737 return NS_ERROR_INVALID_ARG;
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;
748 nsAutoCString tOutStateString;
749 LossyCopyUTF16toASCII(outStateString, tOutStateString);
750 aParams.SetBool(STATE_MIXED, outMixed);
751 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
752 return NS_OK;
755 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;
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;
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;
779 /*****************************************************************************
780 * mozilla::BackgroundColorStateCommand
781 *****************************************************************************/
783 StaticRefPtr<BackgroundColorStateCommand>
784 BackgroundColorStateCommand::sInstance;
786 nsresult BackgroundColorStateCommand::GetCurrentState(
787 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
788 if (NS_WARN_IF(!aHTMLEditor)) {
789 return NS_ERROR_INVALID_ARG;
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;
800 nsAutoCString tOutStateString;
801 LossyCopyUTF16toASCII(outStateString, tOutStateString);
802 aParams.SetBool(STATE_MIXED, outMixed);
803 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
804 return NS_OK;
807 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;
813 nsresult rv = aHTMLEditor->SetBackgroundColorAsAction(aNewState, aPrincipal);
814 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
815 "HTMLEditor::SetBackgroundColorAsAction() failed");
816 return rv;
819 /*****************************************************************************
820 * mozilla::AlignCommand
821 *****************************************************************************/
823 StaticRefPtr<AlignCommand> AlignCommand::sInstance;
825 nsresult AlignCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
826 nsCommandParams& aParams) const {
827 if (NS_WARN_IF(!aHTMLEditor)) {
828 return NS_ERROR_INVALID_ARG;
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;
845 NS_WARNING("AlignStateAtSelection failed");
846 return error.StealNSResult();
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;
864 aParams.SetBool(STATE_MIXED, false);
865 aParams.SetCString(STATE_ATTRIBUTE, alignment);
866 return NS_OK;
869 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;
875 nsresult rv = aHTMLEditor->AlignAsAction(aNewState, aPrincipal);
876 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::AlignAsAction() failed");
877 return rv;
880 /*****************************************************************************
881 * mozilla::AbsolutePositioningCommand
882 *****************************************************************************/
884 StaticRefPtr<AbsolutePositioningCommand> AbsolutePositioningCommand::sInstance;
886 nsresult AbsolutePositioningCommand::GetCurrentState(
887 nsAtom* aTagName, HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
888 if (NS_WARN_IF(!aHTMLEditor)) {
889 return NS_ERROR_INVALID_ARG;
892 if (!aHTMLEditor->IsAbsolutePositionEditorEnabled()) {
893 aParams.SetBool(STATE_MIXED, false);
894 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
895 return NS_OK;
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;
905 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;
918 /*****************************************************************************
919 * mozilla::DecreaseZIndexCommand
920 *****************************************************************************/
922 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
924 bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
925 EditorBase* aEditorBase) const {
926 RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(aEditorBase);
927 if (!htmlEditor) {
928 return false;
930 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
931 return false;
933 RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
934 if (!positionedElement) {
935 return false;
937 return htmlEditor->GetZIndex(*positionedElement) > 0;
940 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;
947 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(-1, aPrincipal);
948 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
949 "HTMLEditor::AddZIndexAsAction(-1) failed");
950 return rv;
953 nsresult DecreaseZIndexCommand::GetCommandStateParams(
954 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
955 nsIEditingSession* aEditingSession) const {
956 return aParams.SetBool(STATE_ENABLED,
957 IsCommandEnabled(aCommand, aEditorBase));
960 /*****************************************************************************
961 * mozilla::IncreaseZIndexCommand
962 *****************************************************************************/
964 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
966 bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
967 EditorBase* aEditorBase) const {
968 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
969 if (!htmlEditor) {
970 return false;
972 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
973 return false;
975 return !!htmlEditor->GetPositionedElement();
978 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;
985 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(1, aPrincipal);
986 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
987 "HTMLEditor::AddZIndexAsAction(1) failed");
988 return rv;
991 nsresult IncreaseZIndexCommand::GetCommandStateParams(
992 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
993 nsIEditingSession* aEditingSession) const {
994 return aParams.SetBool(STATE_ENABLED,
995 IsCommandEnabled(aCommand, aEditorBase));
998 /*****************************************************************************
999 * mozilla::RemoveStylesCommand
1000 *****************************************************************************/
1002 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
1004 bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
1005 EditorBase* aEditorBase) const {
1006 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1007 if (!htmlEditor) {
1008 return false;
1010 // test if we have any styles?
1011 return htmlEditor->IsSelectionEditable();
1014 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;
1021 nsresult rv =
1022 MOZ_KnownLive(htmlEditor)->RemoveAllInlinePropertiesAsAction(aPrincipal);
1023 NS_WARNING_ASSERTION(
1024 NS_SUCCEEDED(rv),
1025 "HTMLEditor::RemoveAllInlinePropertiesAsAction() failed");
1026 return rv;
1029 nsresult RemoveStylesCommand::GetCommandStateParams(
1030 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1031 nsIEditingSession* aEditingSession) const {
1032 return aParams.SetBool(STATE_ENABLED,
1033 IsCommandEnabled(aCommand, aEditorBase));
1036 /*****************************************************************************
1037 * mozilla::IncreaseFontSizeCommand
1038 *****************************************************************************/
1040 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
1042 bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1043 EditorBase* aEditorBase) const {
1044 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1045 if (!htmlEditor) {
1046 return false;
1048 // test if we are at max size?
1049 return htmlEditor->IsSelectionEditable();
1052 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;
1059 nsresult rv = MOZ_KnownLive(htmlEditor)->IncreaseFontSizeAsAction(aPrincipal);
1060 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1061 "HTMLEditor::IncreaseFontSizeAsAction() failed");
1062 return rv;
1065 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
1066 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1067 nsIEditingSession* aEditingSession) const {
1068 return aParams.SetBool(STATE_ENABLED,
1069 IsCommandEnabled(aCommand, aEditorBase));
1072 /*****************************************************************************
1073 * mozilla::DecreaseFontSizeCommand
1074 *****************************************************************************/
1076 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
1078 bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1079 EditorBase* aEditorBase) const {
1080 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1081 if (!htmlEditor) {
1082 return false;
1084 // test if we are at min size?
1085 return htmlEditor->IsSelectionEditable();
1088 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;
1095 nsresult rv = MOZ_KnownLive(htmlEditor)->DecreaseFontSizeAsAction(aPrincipal);
1096 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1097 "HTMLEditor::DecreaseFontSizeAsAction() failed");
1098 return rv;
1101 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
1102 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1103 nsIEditingSession* aEditingSession) const {
1104 return aParams.SetBool(STATE_ENABLED,
1105 IsCommandEnabled(aCommand, aEditorBase));
1108 /*****************************************************************************
1109 * mozilla::InsertHTMLCommand
1110 *****************************************************************************/
1112 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
1114 bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
1115 EditorBase* aEditorBase) const {
1116 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1117 if (!htmlEditor) {
1118 return false;
1120 return htmlEditor->IsSelectionEditable();
1123 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;
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;
1139 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;
1147 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1148 if (NS_WARN_IF(!htmlEditor)) {
1149 return NS_ERROR_FAILURE;
1151 nsresult rv =
1152 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(aStringParam, aPrincipal);
1153 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1154 "HTMLEditor::InsertHTMLAsAction() failed");
1155 return rv;
1158 nsresult InsertHTMLCommand::GetCommandStateParams(
1159 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1160 nsIEditingSession* aEditingSession) const {
1161 return aParams.SetBool(STATE_ENABLED,
1162 IsCommandEnabled(aCommand, aEditorBase));
1165 /*****************************************************************************
1166 * mozilla::InsertTagCommand
1167 *****************************************************************************/
1169 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
1171 bool InsertTagCommand::IsCommandEnabled(Command aCommand,
1172 EditorBase* aEditorBase) const {
1173 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1174 if (!htmlEditor) {
1175 return false;
1177 return htmlEditor->IsSelectionEditable();
1180 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
1181 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;
1188 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1189 if (NS_WARN_IF(!htmlEditor)) {
1190 return NS_ERROR_FAILURE;
1193 RefPtr<Element> newElement =
1194 MOZ_KnownLive(htmlEditor)
1195 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1196 if (NS_WARN_IF(!newElement)) {
1197 return NS_ERROR_FAILURE;
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;
1207 nsresult InsertTagCommand::DoCommandParam(Command aCommand,
1208 const nsAString& aStringParam,
1209 EditorBase& aEditorBase,
1210 nsIPrincipal* aPrincipal) const {
1211 MOZ_ASSERT(aCommand != Command::InsertHorizontalRule);
1213 if (NS_WARN_IF(aStringParam.IsEmpty())) {
1214 return NS_ERROR_INVALID_ARG;
1216 nsAtom* tagName = GetTagName(aCommand);
1217 if (NS_WARN_IF(!tagName)) {
1218 return NS_ERROR_UNEXPECTED;
1221 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1222 if (NS_WARN_IF(!htmlEditor)) {
1223 return NS_ERROR_FAILURE;
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;
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;
1244 ErrorResult error;
1245 newElement->SetAttr(attribute, aStringParam, error);
1246 if (error.Failed()) {
1247 NS_WARNING("Element::SetAttr() failed");
1248 return error.StealNSResult();
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;
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;
1270 nsresult InsertTagCommand::GetCommandStateParams(
1271 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1272 nsIEditingSession* aEditingSession) const {
1273 return aParams.SetBool(STATE_ENABLED,
1274 IsCommandEnabled(aCommand, aEditorBase));
1277 /*****************************************************************************
1278 * Helper methods
1279 *****************************************************************************/
1281 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
1282 nsAString& aLocalName) {
1283 MOZ_ASSERT(aHTMLEditor);
1284 MOZ_ASSERT(aMixed);
1286 *aMixed = false;
1287 aLocalName.Truncate();
1289 ErrorResult error;
1290 ListElementSelectionState state(*aHTMLEditor, error);
1291 if (error.Failed()) {
1292 NS_WARNING("ListElementSelectionState failed");
1293 return error.StealNSResult();
1295 if (state.IsNotOneTypeListElementSelected()) {
1296 *aMixed = true;
1297 return NS_OK;
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");
1307 return NS_OK;
1310 } // namespace mozilla