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