Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / editor / libeditor / HTMLEditorCommands.cpp
blobecccc7c491cfeceaa2db694870b4bb98465fbc9d
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->IsModifiable() || !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(
132 nsIClipboard::kGlobalClipboard,
133 EditorBase::DispatchPasteEvent::Yes, aPrincipal);
134 NS_WARNING_ASSERTION(
135 NS_SUCCEEDED(rv),
136 "HTMLEditor::PasteNoFormattingAsAction(DispatchPasteEvent::Yes) failed");
137 return rv;
140 nsresult PasteNoFormattingCommand::GetCommandStateParams(
141 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
142 nsIEditingSession* aEditingSession) const {
143 return aParams.SetBool(STATE_ENABLED,
144 IsCommandEnabled(aCommand, aEditorBase));
147 /*****************************************************************************
148 * mozilla::StyleUpdatingCommand
149 *****************************************************************************/
151 StaticRefPtr<StyleUpdatingCommand> StyleUpdatingCommand::sInstance;
153 nsresult StyleUpdatingCommand::GetCurrentState(nsStaticAtom& aTagName,
154 HTMLEditor& aHTMLEditor,
155 nsCommandParams& aParams) const {
156 bool firstOfSelectionHasProp = false;
157 bool anyOfSelectionHasProp = false;
158 bool allOfSelectionHasProp = false;
160 nsresult rv = aHTMLEditor.GetInlineProperty(
161 aTagName, nullptr, u""_ns, &firstOfSelectionHasProp,
162 &anyOfSelectionHasProp, &allOfSelectionHasProp);
163 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
164 "HTMLEditor::GetInlineProperty() failed");
166 aParams.SetBool(STATE_ENABLED, NS_SUCCEEDED(rv));
167 aParams.SetBool(STATE_ALL, allOfSelectionHasProp);
168 aParams.SetBool(STATE_ANY, anyOfSelectionHasProp);
169 aParams.SetBool(STATE_MIXED, anyOfSelectionHasProp && !allOfSelectionHasProp);
170 aParams.SetBool(STATE_BEGIN, firstOfSelectionHasProp);
171 aParams.SetBool(STATE_END, allOfSelectionHasProp); // not completely accurate
172 return NS_OK;
175 nsresult StyleUpdatingCommand::ToggleState(nsStaticAtom& aTagName,
176 HTMLEditor& aHTMLEditor,
177 nsIPrincipal* aPrincipal) const {
178 RefPtr<nsCommandParams> params = new nsCommandParams();
180 // tags "href" and "name" are special cases in the core editor
181 // they are used to remove named anchor/link and shouldn't be used for
182 // insertion
183 bool doTagRemoval;
184 if (&aTagName == nsGkAtoms::href || &aTagName == nsGkAtoms::name) {
185 doTagRemoval = true;
186 } else {
187 // check current selection; set doTagRemoval if formatting should be removed
188 nsresult rv = GetCurrentState(aTagName, aHTMLEditor, *params);
189 if (NS_FAILED(rv)) {
190 NS_WARNING("StyleUpdatingCommand::GetCurrentState() failed");
191 return rv;
193 ErrorResult error;
194 doTagRemoval = params->GetBool(STATE_ALL, error);
195 if (NS_WARN_IF(error.Failed())) {
196 return error.StealNSResult();
200 if (doTagRemoval) {
201 nsresult rv =
202 aHTMLEditor.RemoveInlinePropertyAsAction(aTagName, nullptr, aPrincipal);
203 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
204 "HTMLEditor::RemoveInlinePropertyAsAction() failed");
205 return rv;
208 nsresult rv = aHTMLEditor.SetInlinePropertyAsAction(aTagName, nullptr, u""_ns,
209 aPrincipal);
210 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
211 "HTMLEditor::SetInlinePropertyAsAction() failed");
212 return rv;
215 /*****************************************************************************
216 * mozilla::ListCommand
217 *****************************************************************************/
219 StaticRefPtr<ListCommand> ListCommand::sInstance;
221 nsresult ListCommand::GetCurrentState(nsStaticAtom& aTagName,
222 HTMLEditor& aHTMLEditor,
223 nsCommandParams& aParams) const {
224 bool bMixed;
225 nsAutoString localName;
226 nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
227 if (NS_FAILED(rv)) {
228 NS_WARNING("GetListState() failed");
229 return rv;
232 bool inList = aTagName.Equals(localName);
233 aParams.SetBool(STATE_ALL, !bMixed && inList);
234 aParams.SetBool(STATE_MIXED, bMixed);
235 aParams.SetBool(STATE_ENABLED, true);
236 return NS_OK;
239 nsresult ListCommand::ToggleState(nsStaticAtom& aTagName,
240 HTMLEditor& aHTMLEditor,
241 nsIPrincipal* aPrincipal) const {
242 RefPtr<nsCommandParams> params = new nsCommandParams();
243 nsresult rv = GetCurrentState(aTagName, aHTMLEditor, *params);
244 if (NS_FAILED(rv)) {
245 NS_WARNING("ListCommand::GetCurrentState() failed");
246 return rv;
249 ErrorResult error;
250 bool inList = params->GetBool(STATE_ALL, error);
251 if (NS_WARN_IF(error.Failed())) {
252 return error.StealNSResult();
255 nsDependentAtomString listType(&aTagName);
256 if (inList) {
257 nsresult rv = aHTMLEditor.RemoveListAsAction(listType, aPrincipal);
258 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
259 "HTMLEditor::RemoveListAsAction() failed");
260 return rv;
263 rv = aHTMLEditor.MakeOrChangeListAsAction(
264 aTagName, u""_ns, HTMLEditor::SelectAllOfCurrentList::No, aPrincipal);
265 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
266 "HTMLEditor::MakeOrChangeListAsAction() failed");
267 return rv;
270 /*****************************************************************************
271 * mozilla::ListItemCommand
272 *****************************************************************************/
274 StaticRefPtr<ListItemCommand> ListItemCommand::sInstance;
276 nsresult ListItemCommand::GetCurrentState(nsStaticAtom& aTagName,
277 HTMLEditor& aHTMLEditor,
278 nsCommandParams& aParams) const {
279 ErrorResult error;
280 ListItemElementSelectionState state(aHTMLEditor, error);
281 if (error.Failed()) {
282 NS_WARNING("ListItemElementSelectionState failed");
283 return error.StealNSResult();
286 if (state.IsNotOneTypeDefinitionListItemElementSelected()) {
287 aParams.SetBool(STATE_ALL, false);
288 aParams.SetBool(STATE_MIXED, true);
289 return NS_OK;
292 nsStaticAtom* selectedListItemTagName = nullptr;
293 if (state.IsLIElementSelected()) {
294 selectedListItemTagName = nsGkAtoms::li;
295 } else if (state.IsDTElementSelected()) {
296 selectedListItemTagName = nsGkAtoms::dt;
297 } else if (state.IsDDElementSelected()) {
298 selectedListItemTagName = nsGkAtoms::dd;
300 aParams.SetBool(STATE_ALL, &aTagName == selectedListItemTagName);
301 aParams.SetBool(STATE_MIXED, false);
302 return NS_OK;
305 nsresult ListItemCommand::ToggleState(nsStaticAtom& aTagName,
306 HTMLEditor& aHTMLEditor,
307 nsIPrincipal* aPrincipal) const {
308 // Need to use aTagName????
309 RefPtr<nsCommandParams> params = new nsCommandParams();
310 GetCurrentState(aTagName, aHTMLEditor, *params);
311 ErrorResult error;
312 bool inList = params->GetBool(STATE_ALL, error);
313 if (NS_WARN_IF(error.Failed())) {
314 return error.StealNSResult();
317 if (inList) {
318 // To remove a list, first get what kind of list we're in
319 bool bMixed;
320 nsAutoString localName;
321 nsresult rv = GetListState(&aHTMLEditor, &bMixed, localName);
322 if (NS_FAILED(rv)) {
323 NS_WARNING("GetListState() failed");
324 return rv;
326 if (localName.IsEmpty() || bMixed) {
327 return NS_OK;
329 rv = aHTMLEditor.RemoveListAsAction(localName, aPrincipal);
330 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
331 "HTMLEditor::RemoveListAsAction() failed");
332 return rv;
335 // Set to the requested paragraph type
336 // XXX Note: This actually doesn't work for "LI",
337 // but we currently don't use this for non DL lists anyway.
338 // Problem: won't this replace any current block paragraph style?
339 nsresult rv = aHTMLEditor.SetParagraphStateAsAction(
340 nsDependentAtomString(&aTagName), aPrincipal);
341 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
342 "HTMLEditor::SetParagraphFormatAsAction() failed");
343 return rv;
346 /*****************************************************************************
347 * mozilla::RemoveListCommand
348 *****************************************************************************/
350 StaticRefPtr<RemoveListCommand> RemoveListCommand::sInstance;
352 bool RemoveListCommand::IsCommandEnabled(Command aCommand,
353 EditorBase* aEditorBase) const {
354 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
355 if (!htmlEditor) {
356 return false;
358 if (!htmlEditor->IsModifiable() || !htmlEditor->IsSelectionEditable()) {
359 return false;
362 // It is enabled if we are in any list type
363 bool bMixed;
364 nsAutoString localName;
365 nsresult rv = GetListState(MOZ_KnownLive(htmlEditor), &bMixed, localName);
366 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "GetListState() failed");
367 return NS_SUCCEEDED(rv) && (bMixed || !localName.IsEmpty());
370 nsresult RemoveListCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
371 nsIPrincipal* aPrincipal) const {
372 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
373 if (NS_WARN_IF(!htmlEditor)) {
374 return NS_OK;
376 // This removes any list type
377 nsresult rv =
378 MOZ_KnownLive(htmlEditor)->RemoveListAsAction(u""_ns, aPrincipal);
379 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
380 "HTMLEditor::RemoveListAsAction() failed");
381 return rv;
384 nsresult RemoveListCommand::GetCommandStateParams(
385 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
386 nsIEditingSession* aEditingSession) const {
387 return aParams.SetBool(STATE_ENABLED,
388 IsCommandEnabled(aCommand, aEditorBase));
391 /*****************************************************************************
392 * mozilla::IndentCommand
393 *****************************************************************************/
395 StaticRefPtr<IndentCommand> IndentCommand::sInstance;
397 bool IndentCommand::IsCommandEnabled(Command aCommand,
398 EditorBase* aEditorBase) const {
399 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
400 if (!htmlEditor) {
401 return false;
403 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
406 nsresult IndentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
407 nsIPrincipal* aPrincipal) const {
408 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
409 if (NS_WARN_IF(!htmlEditor)) {
410 return NS_OK;
412 nsresult rv = MOZ_KnownLive(htmlEditor)->IndentAsAction(aPrincipal);
413 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::IndentAsAction() failed");
414 return rv;
417 nsresult IndentCommand::GetCommandStateParams(
418 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
419 nsIEditingSession* aEditingSession) const {
420 return aParams.SetBool(STATE_ENABLED,
421 IsCommandEnabled(aCommand, aEditorBase));
424 /*****************************************************************************
425 * mozilla::OutdentCommand
426 *****************************************************************************/
428 StaticRefPtr<OutdentCommand> OutdentCommand::sInstance;
430 bool OutdentCommand::IsCommandEnabled(Command aCommand,
431 EditorBase* aEditorBase) const {
432 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
433 if (!htmlEditor) {
434 return false;
436 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
439 nsresult OutdentCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
440 nsIPrincipal* aPrincipal) const {
441 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
442 if (NS_WARN_IF(!htmlEditor)) {
443 return NS_OK;
445 nsresult rv = MOZ_KnownLive(htmlEditor)->OutdentAsAction(aPrincipal);
446 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
447 "HTMLEditor::OutdentAsAction() failed");
448 return rv;
451 nsresult OutdentCommand::GetCommandStateParams(
452 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
453 nsIEditingSession* aEditingSession) const {
454 return aParams.SetBool(STATE_ENABLED,
455 IsCommandEnabled(aCommand, aEditorBase));
458 /*****************************************************************************
459 * mozilla::MultiStateCommandBase
460 *****************************************************************************/
462 bool MultiStateCommandBase::IsCommandEnabled(Command aCommand,
463 EditorBase* aEditorBase) const {
464 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
465 if (!htmlEditor) {
466 return false;
468 // should be disabled sometimes, like if the current selection is an image
469 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
472 nsresult MultiStateCommandBase::DoCommand(Command aCommand,
473 EditorBase& aEditorBase,
474 nsIPrincipal* aPrincipal) const {
475 NS_WARNING(
476 "who is calling MultiStateCommandBase::DoCommand (no implementation)?");
477 return NS_OK;
480 nsresult MultiStateCommandBase::DoCommandParam(Command aCommand,
481 const nsAString& aStringParam,
482 EditorBase& aEditorBase,
483 nsIPrincipal* aPrincipal) const {
484 NS_WARNING_ASSERTION(aCommand != Command::FormatJustify,
485 "Command::FormatJustify should be used only for "
486 "IsCommandEnabled() and GetCommandStateParams()");
487 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
488 if (NS_WARN_IF(!htmlEditor)) {
489 return NS_ERROR_FAILURE;
491 nsresult rv = SetState(MOZ_KnownLive(htmlEditor), aStringParam, aPrincipal);
492 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
493 "MultiStateCommandBase::SetState() failed");
494 return rv;
497 nsresult MultiStateCommandBase::GetCommandStateParams(
498 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
499 nsIEditingSession* aEditingSession) const {
500 if (!aEditorBase) {
501 return NS_OK;
503 HTMLEditor* htmlEditor = aEditorBase->GetAsHTMLEditor();
504 if (NS_WARN_IF(!htmlEditor)) {
505 return NS_ERROR_FAILURE;
507 nsresult rv = GetCurrentState(MOZ_KnownLive(htmlEditor), aParams);
508 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
509 "MultiStateCommandBase::GetCurrentState() failed");
510 return rv;
513 /*****************************************************************************
514 * mozilla::FormatBlockStateCommand
515 *****************************************************************************/
517 StaticRefPtr<FormatBlockStateCommand> FormatBlockStateCommand::sInstance;
519 nsresult FormatBlockStateCommand::GetCurrentState(
520 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
521 if (NS_WARN_IF(!aHTMLEditor)) {
522 return NS_ERROR_INVALID_ARG;
525 ErrorResult error;
526 ParagraphStateAtSelection state(
527 *aHTMLEditor,
528 ParagraphStateAtSelection::FormatBlockMode::HTMLFormatBlockCommand,
529 error);
530 if (error.Failed()) {
531 NS_WARNING("ParagraphStateAtSelection failed");
532 return error.StealNSResult();
534 aParams.SetBool(STATE_MIXED, state.IsMixed());
535 if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
536 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
537 } else {
538 nsCString paragraphState; // Don't use `nsAutoCString` for avoiding copy.
539 state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
540 aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
542 return NS_OK;
545 nsresult FormatBlockStateCommand::SetState(HTMLEditor* aHTMLEditor,
546 const nsAString& aNewState,
547 nsIPrincipal* aPrincipal) const {
548 if (NS_WARN_IF(!aHTMLEditor) || NS_WARN_IF(aNewState.IsEmpty())) {
549 return NS_ERROR_INVALID_ARG;
551 nsresult rv = aHTMLEditor->FormatBlockAsAction(aNewState, aPrincipal);
552 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
553 "HTMLEditor::FormatBlockAsAction() failed");
554 return rv;
557 /*****************************************************************************
558 * mozilla::ParagraphStateCommand
559 *****************************************************************************/
561 StaticRefPtr<ParagraphStateCommand> ParagraphStateCommand::sInstance;
563 nsresult ParagraphStateCommand::GetCurrentState(
564 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
565 if (NS_WARN_IF(!aHTMLEditor)) {
566 return NS_ERROR_INVALID_ARG;
569 ErrorResult error;
570 ParagraphStateAtSelection state(
571 *aHTMLEditor,
572 ParagraphStateAtSelection::FormatBlockMode::XULParagraphStateCommand,
573 error);
574 if (error.Failed()) {
575 NS_WARNING("ParagraphStateAtSelection failed");
576 return error.StealNSResult();
578 aParams.SetBool(STATE_MIXED, state.IsMixed());
579 if (NS_WARN_IF(!state.GetFirstParagraphStateAtSelection())) {
580 // XXX This is odd behavior, we should fix this later.
581 aParams.SetCString(STATE_ATTRIBUTE, "x"_ns);
582 } else {
583 nsCString paragraphState; // Don't use `nsAutoCString` for avoiding copy.
584 state.GetFirstParagraphStateAtSelection()->ToUTF8String(paragraphState);
585 aParams.SetCString(STATE_ATTRIBUTE, paragraphState);
587 return NS_OK;
590 nsresult ParagraphStateCommand::SetState(HTMLEditor* aHTMLEditor,
591 const nsAString& aNewState,
592 nsIPrincipal* aPrincipal) const {
593 if (NS_WARN_IF(!aHTMLEditor)) {
594 return NS_ERROR_INVALID_ARG;
596 nsresult rv = aHTMLEditor->SetParagraphStateAsAction(aNewState, aPrincipal);
597 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
598 "HTMLEditor::SetParagraphStateAsAction() failed");
599 return rv;
602 /*****************************************************************************
603 * mozilla::FontFaceStateCommand
604 *****************************************************************************/
606 StaticRefPtr<FontFaceStateCommand> FontFaceStateCommand::sInstance;
608 nsresult FontFaceStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
609 nsCommandParams& aParams) const {
610 if (NS_WARN_IF(!aHTMLEditor)) {
611 return NS_ERROR_INVALID_ARG;
614 nsAutoString outStateString;
615 bool outMixed;
616 nsresult rv = aHTMLEditor->GetFontFaceState(&outMixed, outStateString);
617 if (NS_FAILED(rv)) {
618 NS_WARNING("HTMLEditor::GetFontFaceState() failed");
619 return rv;
621 aParams.SetBool(STATE_MIXED, outMixed);
622 aParams.SetCString(STATE_ATTRIBUTE, NS_ConvertUTF16toUTF8(outStateString));
623 return NS_OK;
626 nsresult FontFaceStateCommand::SetState(HTMLEditor* aHTMLEditor,
627 const nsAString& aNewState,
628 nsIPrincipal* aPrincipal) const {
629 if (NS_WARN_IF(!aHTMLEditor)) {
630 return NS_ERROR_INVALID_ARG;
633 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
634 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
635 *nsGkAtoms::font, nsGkAtoms::face, aPrincipal);
636 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
637 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
638 "font, nsGkAtoms::face) failed");
639 return rv;
642 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
643 *nsGkAtoms::font, nsGkAtoms::face, aNewState, aPrincipal);
644 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
645 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
646 "nsGkAtoms::face) failed");
647 return rv;
650 /*****************************************************************************
651 * mozilla::FontSizeStateCommand
652 *****************************************************************************/
654 StaticRefPtr<FontSizeStateCommand> FontSizeStateCommand::sInstance;
656 nsresult FontSizeStateCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
657 nsCommandParams& aParams) const {
658 if (NS_WARN_IF(!aHTMLEditor)) {
659 return NS_ERROR_INVALID_ARG;
662 nsAutoString outStateString;
663 bool firstHas, anyHas, allHas;
664 nsresult rv = aHTMLEditor->GetInlinePropertyWithAttrValue(
665 *nsGkAtoms::font, nsGkAtoms::size, u""_ns, &firstHas, &anyHas, &allHas,
666 outStateString);
667 if (NS_FAILED(rv)) {
668 NS_WARNING(
669 "HTMLEditor::GetInlinePropertyWithAttrValue(nsGkAtoms::font, "
670 "nsGkAtoms::size) failed");
671 return rv;
674 nsAutoCString tOutStateString;
675 LossyCopyUTF16toASCII(outStateString, tOutStateString);
676 aParams.SetBool(STATE_MIXED, anyHas && !allHas);
677 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
678 aParams.SetBool(STATE_ENABLED, true);
680 return NS_OK;
683 // acceptable values for "aNewState" are:
684 // -2
685 // -1
686 // 0
687 // +1
688 // +2
689 // +3
690 // medium
691 // normal
692 nsresult FontSizeStateCommand::SetState(HTMLEditor* aHTMLEditor,
693 const nsAString& aNewState,
694 nsIPrincipal* aPrincipal) const {
695 if (NS_WARN_IF(!aHTMLEditor)) {
696 return NS_ERROR_INVALID_ARG;
699 if (!aNewState.IsEmpty() && !aNewState.EqualsLiteral("normal") &&
700 !aNewState.EqualsLiteral("medium")) {
701 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
702 *nsGkAtoms::font, nsGkAtoms::size, aNewState, aPrincipal);
703 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
704 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::"
705 "font, nsGkAtoms::size) failed");
706 return rv;
709 // remove any existing font size, big or small
710 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
711 *nsGkAtoms::font, nsGkAtoms::size, aPrincipal);
712 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
713 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
714 "font, nsGkAtoms::size) failed");
715 return rv;
718 /*****************************************************************************
719 * mozilla::FontColorStateCommand
720 *****************************************************************************/
722 StaticRefPtr<FontColorStateCommand> FontColorStateCommand::sInstance;
724 nsresult FontColorStateCommand::GetCurrentState(
725 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
726 if (NS_WARN_IF(!aHTMLEditor)) {
727 return NS_ERROR_INVALID_ARG;
730 bool outMixed;
731 nsAutoString outStateString;
732 nsresult rv = aHTMLEditor->GetFontColorState(&outMixed, outStateString);
733 if (NS_FAILED(rv)) {
734 NS_WARNING("HTMLEditor::GetFontColorState() failed");
735 return rv;
738 nsAutoCString tOutStateString;
739 LossyCopyUTF16toASCII(outStateString, tOutStateString);
740 aParams.SetBool(STATE_MIXED, outMixed);
741 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
742 return NS_OK;
745 nsresult FontColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
746 const nsAString& aNewState,
747 nsIPrincipal* aPrincipal) const {
748 if (NS_WARN_IF(!aHTMLEditor)) {
749 return NS_ERROR_INVALID_ARG;
752 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
753 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
754 *nsGkAtoms::font, nsGkAtoms::color, aPrincipal);
755 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
756 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
757 "font, nsGkAtoms::color) failed");
758 return rv;
761 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
762 *nsGkAtoms::font, nsGkAtoms::color, aNewState, aPrincipal);
763 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
764 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
765 "nsGkAtoms::color) failed");
766 return rv;
769 /*****************************************************************************
770 * mozilla::HighlightColorStateCommand
771 *****************************************************************************/
773 StaticRefPtr<HighlightColorStateCommand> HighlightColorStateCommand::sInstance;
775 nsresult HighlightColorStateCommand::GetCurrentState(
776 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
777 if (NS_WARN_IF(!aHTMLEditor)) {
778 return NS_ERROR_INVALID_ARG;
781 bool outMixed;
782 nsAutoString outStateString;
783 nsresult rv = aHTMLEditor->GetHighlightColorState(&outMixed, outStateString);
784 if (NS_FAILED(rv)) {
785 NS_WARNING("HTMLEditor::GetHighlightColorState() failed");
786 return rv;
789 nsAutoCString tOutStateString;
790 LossyCopyUTF16toASCII(outStateString, tOutStateString);
791 aParams.SetBool(STATE_MIXED, outMixed);
792 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
793 return NS_OK;
796 nsresult HighlightColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
797 const nsAString& aNewState,
798 nsIPrincipal* aPrincipal) const {
799 if (NS_WARN_IF(!aHTMLEditor)) {
800 return NS_ERROR_INVALID_ARG;
803 if (aNewState.IsEmpty() || aNewState.EqualsLiteral("normal")) {
804 nsresult rv = aHTMLEditor->RemoveInlinePropertyAsAction(
805 *nsGkAtoms::font, nsGkAtoms::bgcolor, aPrincipal);
806 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
807 "HTMLEditor::RemoveInlinePropertyAsAction(nsGkAtoms::"
808 "font, nsGkAtoms::bgcolor) failed");
809 return rv;
812 nsresult rv = aHTMLEditor->SetInlinePropertyAsAction(
813 *nsGkAtoms::font, nsGkAtoms::bgcolor, aNewState, aPrincipal);
814 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
815 "HTMLEditor::SetInlinePropertyAsAction(nsGkAtoms::font, "
816 "nsGkAtoms::bgcolor) failed");
817 return rv;
820 /*****************************************************************************
821 * mozilla::BackgroundColorStateCommand
822 *****************************************************************************/
824 StaticRefPtr<BackgroundColorStateCommand>
825 BackgroundColorStateCommand::sInstance;
827 nsresult BackgroundColorStateCommand::GetCurrentState(
828 HTMLEditor* aHTMLEditor, nsCommandParams& aParams) const {
829 if (NS_WARN_IF(!aHTMLEditor)) {
830 return NS_ERROR_INVALID_ARG;
833 bool outMixed;
834 nsAutoString outStateString;
835 nsresult rv = aHTMLEditor->GetBackgroundColorState(&outMixed, outStateString);
836 if (NS_FAILED(rv)) {
837 NS_WARNING("HTMLEditor::GetBackgroundColorState() failed");
838 return rv;
841 nsAutoCString tOutStateString;
842 LossyCopyUTF16toASCII(outStateString, tOutStateString);
843 aParams.SetBool(STATE_MIXED, outMixed);
844 aParams.SetCString(STATE_ATTRIBUTE, tOutStateString);
845 return NS_OK;
848 nsresult BackgroundColorStateCommand::SetState(HTMLEditor* aHTMLEditor,
849 const nsAString& aNewState,
850 nsIPrincipal* aPrincipal) const {
851 if (NS_WARN_IF(!aHTMLEditor)) {
852 return NS_ERROR_INVALID_ARG;
854 nsresult rv = aHTMLEditor->SetBackgroundColorAsAction(aNewState, aPrincipal);
855 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
856 "HTMLEditor::SetBackgroundColorAsAction() failed");
857 return rv;
860 /*****************************************************************************
861 * mozilla::AlignCommand
862 *****************************************************************************/
864 StaticRefPtr<AlignCommand> AlignCommand::sInstance;
866 nsresult AlignCommand::GetCurrentState(HTMLEditor* aHTMLEditor,
867 nsCommandParams& aParams) const {
868 if (NS_WARN_IF(!aHTMLEditor)) {
869 return NS_ERROR_INVALID_ARG;
872 ErrorResult error;
873 AlignStateAtSelection state(*aHTMLEditor, error);
874 if (error.Failed()) {
875 if (!state.IsSelectionRangesFound()) {
876 // If there was no selection ranges, we shouldn't throw exception for
877 // compatibility with the other browsers, but I have no better idea
878 // than returning empty string in this case. Oddly, Blink/WebKit returns
879 // "true" or "false", but it's different from us and the value does not
880 // make sense. Additionally, WPT loves our behavior.
881 error.SuppressException();
882 aParams.SetBool(STATE_MIXED, false);
883 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
884 return NS_OK;
886 NS_WARNING("AlignStateAtSelection failed");
887 return error.StealNSResult();
889 nsCString alignment; // Don't use `nsAutoCString` to avoid copying string.
890 switch (state.AlignmentAtSelectionStart()) {
891 default:
892 case nsIHTMLEditor::eLeft:
893 alignment.AssignLiteral("left");
894 break;
895 case nsIHTMLEditor::eCenter:
896 alignment.AssignLiteral("center");
897 break;
898 case nsIHTMLEditor::eRight:
899 alignment.AssignLiteral("right");
900 break;
901 case nsIHTMLEditor::eJustify:
902 alignment.AssignLiteral("justify");
903 break;
905 aParams.SetBool(STATE_MIXED, false);
906 aParams.SetCString(STATE_ATTRIBUTE, alignment);
907 return NS_OK;
910 nsresult AlignCommand::SetState(HTMLEditor* aHTMLEditor,
911 const nsAString& aNewState,
912 nsIPrincipal* aPrincipal) const {
913 if (NS_WARN_IF(!aHTMLEditor)) {
914 return NS_ERROR_INVALID_ARG;
916 nsresult rv = aHTMLEditor->AlignAsAction(aNewState, aPrincipal);
917 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "HTMLEditor::AlignAsAction() failed");
918 return rv;
921 /*****************************************************************************
922 * mozilla::AbsolutePositioningCommand
923 *****************************************************************************/
925 StaticRefPtr<AbsolutePositioningCommand> AbsolutePositioningCommand::sInstance;
927 nsresult AbsolutePositioningCommand::GetCurrentState(
928 nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
929 nsCommandParams& aParams) const {
930 if (!aHTMLEditor.IsAbsolutePositionEditorEnabled()) {
931 aParams.SetBool(STATE_MIXED, false);
932 aParams.SetCString(STATE_ATTRIBUTE, ""_ns);
933 return NS_OK;
936 RefPtr<Element> container =
937 aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
938 aParams.SetBool(STATE_MIXED, false);
939 aParams.SetCString(STATE_ATTRIBUTE, container ? "absolute"_ns : ""_ns);
940 return NS_OK;
943 nsresult AbsolutePositioningCommand::ToggleState(
944 nsStaticAtom& aTagName, HTMLEditor& aHTMLEditor,
945 nsIPrincipal* aPrincipal) const {
946 RefPtr<Element> container =
947 aHTMLEditor.GetAbsolutelyPositionedSelectionContainer();
948 nsresult rv = aHTMLEditor.SetSelectionToAbsoluteOrStaticAsAction(!container,
949 aPrincipal);
950 NS_WARNING_ASSERTION(
951 NS_SUCCEEDED(rv),
952 "HTMLEditor::SetSelectionToAbsoluteOrStaticAsAction() failed");
953 return rv;
956 /*****************************************************************************
957 * mozilla::DecreaseZIndexCommand
958 *****************************************************************************/
960 StaticRefPtr<DecreaseZIndexCommand> DecreaseZIndexCommand::sInstance;
962 bool DecreaseZIndexCommand::IsCommandEnabled(Command aCommand,
963 EditorBase* aEditorBase) const {
964 RefPtr<HTMLEditor> htmlEditor = HTMLEditor::GetFrom(aEditorBase);
965 if (!htmlEditor) {
966 return false;
968 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
969 return false;
971 RefPtr<Element> positionedElement = htmlEditor->GetPositionedElement();
972 if (!positionedElement) {
973 return false;
975 return htmlEditor->GetZIndex(*positionedElement) > 0;
978 nsresult DecreaseZIndexCommand::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 DecreaseZIndexCommand::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::IncreaseZIndexCommand
1000 *****************************************************************************/
1002 StaticRefPtr<IncreaseZIndexCommand> IncreaseZIndexCommand::sInstance;
1004 bool IncreaseZIndexCommand::IsCommandEnabled(Command aCommand,
1005 EditorBase* aEditorBase) const {
1006 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1007 if (!htmlEditor) {
1008 return false;
1010 if (!htmlEditor->IsAbsolutePositionEditorEnabled()) {
1011 return false;
1013 return !!htmlEditor->GetPositionedElement();
1016 nsresult IncreaseZIndexCommand::DoCommand(Command aCommand,
1017 EditorBase& aEditorBase,
1018 nsIPrincipal* aPrincipal) const {
1019 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1020 if (NS_WARN_IF(!htmlEditor)) {
1021 return NS_ERROR_FAILURE;
1023 nsresult rv = MOZ_KnownLive(htmlEditor)->AddZIndexAsAction(1, aPrincipal);
1024 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1025 "HTMLEditor::AddZIndexAsAction(1) failed");
1026 return rv;
1029 nsresult IncreaseZIndexCommand::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::RemoveStylesCommand
1038 *****************************************************************************/
1040 StaticRefPtr<RemoveStylesCommand> RemoveStylesCommand::sInstance;
1042 bool RemoveStylesCommand::IsCommandEnabled(Command aCommand,
1043 EditorBase* aEditorBase) const {
1044 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1045 if (!htmlEditor) {
1046 return false;
1048 // test if we have any styles?
1049 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
1052 nsresult RemoveStylesCommand::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 =
1060 MOZ_KnownLive(htmlEditor)->RemoveAllInlinePropertiesAsAction(aPrincipal);
1061 NS_WARNING_ASSERTION(
1062 NS_SUCCEEDED(rv),
1063 "HTMLEditor::RemoveAllInlinePropertiesAsAction() failed");
1064 return rv;
1067 nsresult RemoveStylesCommand::GetCommandStateParams(
1068 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1069 nsIEditingSession* aEditingSession) const {
1070 return aParams.SetBool(STATE_ENABLED,
1071 IsCommandEnabled(aCommand, aEditorBase));
1074 /*****************************************************************************
1075 * mozilla::IncreaseFontSizeCommand
1076 *****************************************************************************/
1078 StaticRefPtr<IncreaseFontSizeCommand> IncreaseFontSizeCommand::sInstance;
1080 bool IncreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1081 EditorBase* aEditorBase) const {
1082 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1083 if (!htmlEditor) {
1084 return false;
1086 // test if we are at max size?
1087 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
1090 nsresult IncreaseFontSizeCommand::DoCommand(Command aCommand,
1091 EditorBase& aEditorBase,
1092 nsIPrincipal* aPrincipal) const {
1093 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1094 if (NS_WARN_IF(!htmlEditor)) {
1095 return NS_OK;
1097 nsresult rv = MOZ_KnownLive(htmlEditor)->IncreaseFontSizeAsAction(aPrincipal);
1098 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1099 "HTMLEditor::IncreaseFontSizeAsAction() failed");
1100 return rv;
1103 nsresult IncreaseFontSizeCommand::GetCommandStateParams(
1104 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1105 nsIEditingSession* aEditingSession) const {
1106 return aParams.SetBool(STATE_ENABLED,
1107 IsCommandEnabled(aCommand, aEditorBase));
1110 /*****************************************************************************
1111 * mozilla::DecreaseFontSizeCommand
1112 *****************************************************************************/
1114 StaticRefPtr<DecreaseFontSizeCommand> DecreaseFontSizeCommand::sInstance;
1116 bool DecreaseFontSizeCommand::IsCommandEnabled(Command aCommand,
1117 EditorBase* aEditorBase) const {
1118 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1119 if (!htmlEditor) {
1120 return false;
1122 // test if we are at min size?
1123 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
1126 nsresult DecreaseFontSizeCommand::DoCommand(Command aCommand,
1127 EditorBase& aEditorBase,
1128 nsIPrincipal* aPrincipal) const {
1129 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1130 if (NS_WARN_IF(!htmlEditor)) {
1131 return NS_OK;
1133 nsresult rv = MOZ_KnownLive(htmlEditor)->DecreaseFontSizeAsAction(aPrincipal);
1134 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1135 "HTMLEditor::DecreaseFontSizeAsAction() failed");
1136 return rv;
1139 nsresult DecreaseFontSizeCommand::GetCommandStateParams(
1140 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1141 nsIEditingSession* aEditingSession) const {
1142 return aParams.SetBool(STATE_ENABLED,
1143 IsCommandEnabled(aCommand, aEditorBase));
1146 /*****************************************************************************
1147 * mozilla::InsertHTMLCommand
1148 *****************************************************************************/
1150 StaticRefPtr<InsertHTMLCommand> InsertHTMLCommand::sInstance;
1152 bool InsertHTMLCommand::IsCommandEnabled(Command aCommand,
1153 EditorBase* aEditorBase) const {
1154 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1155 if (!htmlEditor) {
1156 return false;
1158 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
1161 nsresult InsertHTMLCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
1162 nsIPrincipal* aPrincipal) const {
1163 // If InsertHTMLCommand is called with no parameters, it was probably called
1164 // with an empty string parameter ''. In this case, it should act the same as
1165 // the delete command
1166 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1167 if (NS_WARN_IF(!htmlEditor)) {
1168 return NS_ERROR_FAILURE;
1170 nsresult rv =
1171 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(u""_ns, aPrincipal);
1172 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1173 "HTMLEditor::InsertHTMLAsAction() failed");
1174 return rv;
1177 nsresult InsertHTMLCommand::DoCommandParam(Command aCommand,
1178 const nsAString& aStringParam,
1179 EditorBase& aEditorBase,
1180 nsIPrincipal* aPrincipal) const {
1181 if (NS_WARN_IF(aStringParam.IsVoid())) {
1182 return NS_ERROR_INVALID_ARG;
1185 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1186 if (NS_WARN_IF(!htmlEditor)) {
1187 return NS_ERROR_FAILURE;
1189 nsresult rv =
1190 MOZ_KnownLive(htmlEditor)->InsertHTMLAsAction(aStringParam, aPrincipal);
1191 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1192 "HTMLEditor::InsertHTMLAsAction() failed");
1193 return rv;
1196 nsresult InsertHTMLCommand::GetCommandStateParams(
1197 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1198 nsIEditingSession* aEditingSession) const {
1199 return aParams.SetBool(STATE_ENABLED,
1200 IsCommandEnabled(aCommand, aEditorBase));
1203 /*****************************************************************************
1204 * mozilla::InsertTagCommand
1205 *****************************************************************************/
1207 StaticRefPtr<InsertTagCommand> InsertTagCommand::sInstance;
1209 bool InsertTagCommand::IsCommandEnabled(Command aCommand,
1210 EditorBase* aEditorBase) const {
1211 HTMLEditor* htmlEditor = HTMLEditor::GetFrom(aEditorBase);
1212 if (!htmlEditor) {
1213 return false;
1215 return htmlEditor->IsModifiable() && htmlEditor->IsSelectionEditable();
1218 // corresponding STATE_ATTRIBUTE is: src (img) and href (a)
1219 nsresult InsertTagCommand::DoCommand(Command aCommand, EditorBase& aEditorBase,
1220 nsIPrincipal* aPrincipal) const {
1221 nsAtom* tagName = GetTagName(aCommand);
1222 if (NS_WARN_IF(tagName != nsGkAtoms::hr)) {
1223 return NS_ERROR_NOT_IMPLEMENTED;
1226 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1227 if (NS_WARN_IF(!htmlEditor)) {
1228 return NS_ERROR_FAILURE;
1231 RefPtr<Element> newElement =
1232 MOZ_KnownLive(htmlEditor)
1233 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1234 if (NS_WARN_IF(!newElement)) {
1235 return NS_ERROR_FAILURE;
1237 nsresult rv =
1238 MOZ_KnownLive(htmlEditor)
1239 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1240 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1241 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1242 return rv;
1245 nsresult InsertTagCommand::DoCommandParam(Command aCommand,
1246 const nsAString& aStringParam,
1247 EditorBase& aEditorBase,
1248 nsIPrincipal* aPrincipal) const {
1249 MOZ_ASSERT(aCommand != Command::InsertHorizontalRule);
1251 if (NS_WARN_IF(aStringParam.IsEmpty())) {
1252 return NS_ERROR_INVALID_ARG;
1254 nsAtom* tagName = GetTagName(aCommand);
1255 if (NS_WARN_IF(!tagName)) {
1256 return NS_ERROR_UNEXPECTED;
1259 HTMLEditor* htmlEditor = aEditorBase.GetAsHTMLEditor();
1260 if (NS_WARN_IF(!htmlEditor)) {
1261 return NS_ERROR_FAILURE;
1264 // filter out tags we don't know how to insert
1265 nsAtom* attribute = nullptr;
1266 if (tagName == nsGkAtoms::a) {
1267 attribute = nsGkAtoms::href;
1268 } else if (tagName == nsGkAtoms::img) {
1269 attribute = nsGkAtoms::src;
1270 } else {
1271 return NS_ERROR_NOT_IMPLEMENTED;
1274 RefPtr<Element> newElement =
1275 MOZ_KnownLive(htmlEditor)
1276 ->CreateElementWithDefaults(MOZ_KnownLive(*tagName));
1277 if (!newElement) {
1278 NS_WARNING("HTMLEditor::CreateElementWithDefaults() failed");
1279 return NS_ERROR_FAILURE;
1282 ErrorResult error;
1283 newElement->SetAttr(attribute, aStringParam, error);
1284 if (error.Failed()) {
1285 NS_WARNING("Element::SetAttr() failed");
1286 return error.StealNSResult();
1289 // do actual insertion
1290 if (tagName == nsGkAtoms::a) {
1291 nsresult rv =
1292 MOZ_KnownLive(htmlEditor)
1293 ->InsertLinkAroundSelectionAsAction(newElement, aPrincipal);
1294 NS_WARNING_ASSERTION(
1295 NS_SUCCEEDED(rv),
1296 "HTMLEditor::InsertLinkAroundSelectionAsAction() failed");
1297 return rv;
1300 nsresult rv =
1301 MOZ_KnownLive(htmlEditor)
1302 ->InsertElementAtSelectionAsAction(newElement, true, aPrincipal);
1303 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
1304 "HTMLEditor::InsertElementAtSelectionAsAction() failed");
1305 return rv;
1308 nsresult InsertTagCommand::GetCommandStateParams(
1309 Command aCommand, nsCommandParams& aParams, EditorBase* aEditorBase,
1310 nsIEditingSession* aEditingSession) const {
1311 return aParams.SetBool(STATE_ENABLED,
1312 IsCommandEnabled(aCommand, aEditorBase));
1315 /*****************************************************************************
1316 * Helper methods
1317 *****************************************************************************/
1319 static nsresult GetListState(HTMLEditor* aHTMLEditor, bool* aMixed,
1320 nsAString& aLocalName) {
1321 MOZ_ASSERT(aHTMLEditor);
1322 MOZ_ASSERT(aMixed);
1324 *aMixed = false;
1325 aLocalName.Truncate();
1327 ErrorResult error;
1328 ListElementSelectionState state(*aHTMLEditor, error);
1329 if (error.Failed()) {
1330 NS_WARNING("ListElementSelectionState failed");
1331 return error.StealNSResult();
1333 if (state.IsNotOneTypeListElementSelected()) {
1334 *aMixed = true;
1335 return NS_OK;
1338 if (state.IsOLElementSelected()) {
1339 aLocalName.AssignLiteral("ol");
1340 } else if (state.IsULElementSelected()) {
1341 aLocalName.AssignLiteral("ul");
1342 } else if (state.IsDLElementSelected()) {
1343 aLocalName.AssignLiteral("dl");
1345 return NS_OK;
1348 } // namespace mozilla