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 #ifndef mozilla_HTMLEditor_h
7 #define mozilla_HTMLEditor_h
9 #include "mozilla/Attributes.h"
10 #include "mozilla/ComposerCommandsUpdater.h"
11 #include "mozilla/EditorBase.h"
12 #include "mozilla/EditorForwards.h"
13 #include "mozilla/ErrorResult.h"
14 #include "mozilla/ManualNAC.h"
15 #include "mozilla/Result.h"
16 #include "mozilla/dom/BlobImpl.h"
17 #include "mozilla/dom/Element.h"
18 #include "mozilla/dom/File.h"
20 #include "nsAttrName.h"
22 #include "nsIDocumentObserver.h"
23 #include "nsIDOMEventListener.h"
24 #include "nsIEditorMailSupport.h"
25 #include "nsIHTMLAbsPosEditor.h"
26 #include "nsIHTMLEditor.h"
27 #include "nsIHTMLInlineTableEditor.h"
28 #include "nsIHTMLObjectResizer.h"
29 #include "nsIPrincipal.h"
30 #include "nsITableEditor.h"
32 #include "nsStubMutationObserver.h"
36 class nsDocumentFragment
;
37 class nsFrameSelection
;
39 class nsITransferable
;
43 class nsStyledElement
;
44 class nsTableCellFrame
;
45 class nsTableWrapperFrame
;
50 class AlignStateAtSelection
;
51 class AutoSelectionSetterAfterTableEdit
;
52 class AutoSetTemporaryAncestorLimiter
;
53 class EmptyEditableFunctor
;
54 class ListElementSelectionState
;
55 class ListItemElementSelectionState
;
56 class ParagraphStateAtSelection
;
57 class ResizerSelectionListener
;
64 class DocumentFragment
;
74 enum class ParagraphSeparator
{ div
, p
, br
};
77 * The HTML editor implementation.<br>
78 * Use to edit HTML document represented as a DOM tree.
80 class HTMLEditor final
: public EditorBase
,
82 public nsIHTMLObjectResizer
,
83 public nsIHTMLAbsPosEditor
,
84 public nsITableEditor
,
85 public nsIHTMLInlineTableEditor
,
86 public nsStubMutationObserver
,
87 public nsIEditorMailSupport
{
89 /****************************************************************************
90 * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
91 * classes under libeditor except EditorEventListener and
92 * HTMLEditorEventListener because each public method which may fire
93 * eEditorInput event will need to instantiate new stack class for
94 * managing input type value of eEditorInput and cache some objects
95 * for smarter handling. In other words, when you add new root
96 * method to edit the DOM tree, you can make your new method public.
97 ****************************************************************************/
99 NS_DECL_ISUPPORTS_INHERITED
100 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor
, EditorBase
)
102 // nsStubMutationObserver overrides
103 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
104 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
105 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
106 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
108 // nsIHTMLEditor methods
109 NS_DECL_NSIHTMLEDITOR
111 // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
112 NS_DECL_NSIHTMLOBJECTRESIZER
114 // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
115 NS_DECL_NSIHTMLABSPOSEDITOR
117 // nsIHTMLInlineTableEditor methods (implemented in HTMLInlineTableEditor.cpp)
118 NS_DECL_NSIHTMLINLINETABLEEDITOR
120 // nsIEditorMailSupport methods
121 NS_DECL_NSIEDITORMAILSUPPORT
123 // nsITableEditor methods
124 NS_DECL_NSITABLEEDITOR
126 // nsISelectionListener overrides
127 NS_DECL_NSISELECTIONLISTENER
130 * @param aDocument The document whose content will be editable.
132 explicit HTMLEditor(const Document
& aDocument
);
135 * @param aDocument The document whose content will be editable.
136 * @param aComposerCommandsUpdater The composer command updater.
137 * @param aFlags Some of nsIEditor::eEditor*Mask flags.
139 MOZ_CAN_RUN_SCRIPT nsresult
140 Init(Document
& aDocument
, ComposerCommandsUpdater
& aComposerCommandsUpdater
,
144 * PostCreate() should be called after Init, and is the time that the editor
145 * tells its documentStateObservers that the document has been created.
147 MOZ_CAN_RUN_SCRIPT nsresult
PostCreate();
150 * PreDestroy() is called before the editor goes away, and gives the editor a
151 * chance to tell its documentStateObservers that the document is going away.
153 MOZ_CAN_RUN_SCRIPT
void PreDestroy();
155 static HTMLEditor
* GetFrom(nsIEditor
* aEditor
) {
156 return aEditor
? aEditor
->GetAsHTMLEditor() : nullptr;
158 static const HTMLEditor
* GetFrom(const nsIEditor
* aEditor
) {
159 return aEditor
? aEditor
->GetAsHTMLEditor() : nullptr;
162 [[nodiscard
]] bool GetReturnInParagraphCreatesNewParagraph() const;
164 // EditorBase overrides
165 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
BeginningOfDocument() final
;
166 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
EndOfDocument() final
;
168 NS_IMETHOD
GetDocumentCharacterSet(nsACString
& aCharacterSet
) final
;
169 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
170 SetDocumentCharacterSet(const nsACString
& aCharacterSet
) final
;
172 bool IsEmpty() const final
;
174 bool CanPaste(int32_t aClipboardType
) const final
;
175 using EditorBase::CanPaste
;
177 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
DeleteNode(nsINode
* aNode
,
178 bool aPreseveSelection
,
179 uint8_t aOptionalArgCount
) final
;
181 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
InsertLineBreak() final
;
184 * PreHandleMouseDown() and PreHandleMouseUp() are called before
185 * HTMLEditorEventListener handles them. The coming event may be
186 * non-acceptable event.
188 void PreHandleMouseDown(const dom::MouseEvent
& aMouseDownEvent
);
189 void PreHandleMouseUp(const dom::MouseEvent
& aMouseUpEvent
);
192 * PreHandleSelectionChangeCommand() and PostHandleSelectionChangeCommand()
193 * are called before or after handling a command which may change selection
194 * and/or scroll position.
196 void PreHandleSelectionChangeCommand(Command aCommand
);
197 void PostHandleSelectionChangeCommand(Command aCommand
);
199 MOZ_CAN_RUN_SCRIPT nsresult
200 HandleKeyPressEvent(WidgetKeyboardEvent
* aKeyboardEvent
) final
;
201 Element
* GetFocusedElement() const final
;
202 bool IsActiveInDOMWindow() const final
;
203 dom::EventTarget
* GetDOMEventTarget() const final
;
204 [[nodiscard
]] Element
* FindSelectionRoot(const nsINode
& aNode
) const final
;
205 bool IsAcceptableInputEvent(WidgetGUIEvent
* aGUIEvent
) const final
;
206 nsresult
GetPreferredIMEState(widget::IMEState
* aState
) final
;
207 MOZ_CAN_RUN_SCRIPT nsresult
208 OnFocus(const nsINode
& aOriginalEventTargetNode
) final
;
209 nsresult
OnBlur(const dom::EventTarget
* aEventTarget
) final
;
212 * Called when aDocument or aElement becomes editable without focus change.
213 * E.g., when the design mode is enabled or the contenteditable attribute
214 * is set to the focused element.
216 MOZ_CAN_RUN_SCRIPT nsresult
FocusedElementOrDocumentBecomesEditable(
217 Document
& aDocument
, Element
* aElement
);
220 * Called when aDocument or aElement becomes not editable without focus
221 * change. E.g., when the design mode ends or the contenteditable attribute is
222 * removed or set to "false".
224 MOZ_CAN_RUN_SCRIPT
static nsresult
FocusedElementOrDocumentBecomesNotEditable(
225 HTMLEditor
* aHTMLEditor
, Document
& aDocument
, Element
* aElement
);
228 * GetBackgroundColorState() returns what the background color of the
231 * @param aMixed true if there is more than one font color
232 * @param aOutColor Color string. "" is returned for none.
234 MOZ_CAN_RUN_SCRIPT nsresult
GetBackgroundColorState(bool* aMixed
,
235 nsAString
& aOutColor
);
238 * PasteNoFormattingAsAction() pastes content in clipboard without any style
241 * @param aClipboardType nsIClipboard::kGlobalClipboard or
242 * nsIClipboard::kSelectionClipboard.
243 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
244 * before pasting. Otherwise, No.
245 * @param aPrincipal Set subject principal if it may be called by
246 * JS. If set to nullptr, will be treated as
249 MOZ_CAN_RUN_SCRIPT nsresult
PasteNoFormattingAsAction(
250 int32_t aClipboardType
, DispatchPasteEvent aDispatchPasteEvent
,
251 nsIPrincipal
* aPrincipal
= nullptr);
253 bool CanPasteTransferable(nsITransferable
* aTransferable
) final
;
255 MOZ_CAN_RUN_SCRIPT nsresult
256 InsertLineBreakAsAction(nsIPrincipal
* aPrincipal
= nullptr) final
;
259 * InsertParagraphSeparatorAsAction() is called when user tries to separate
260 * current paragraph with Enter key press in HTMLEditor or something.
262 * @param aPrincipal Set subject principal if it may be called by
263 * JS. If set to nullptr, will be treated as
266 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
267 InsertParagraphSeparatorAsAction(nsIPrincipal
* aPrincipal
= nullptr);
269 MOZ_CAN_RUN_SCRIPT nsresult
270 InsertElementAtSelectionAsAction(Element
* aElement
, bool aDeleteSelection
,
271 nsIPrincipal
* aPrincipal
= nullptr);
273 MOZ_CAN_RUN_SCRIPT nsresult
InsertLinkAroundSelectionAsAction(
274 Element
* aAnchorElement
, nsIPrincipal
* aPrincipal
= nullptr);
277 * CreateElementWithDefaults() creates new element whose name is
278 * aTagName with some default attributes are set. Note that this is a
279 * public utility method. I.e., just creates element, not insert it
281 * NOTE: This is available for internal use too since this does not change
282 * the DOM tree nor undo transactions, and does not refer Selection,
285 * @param aTagName The new element's tag name. If the name is
286 * one of "href", "anchor" or "namedanchor",
287 * this creates an <a> element.
288 * @return Newly created element.
290 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Element
> CreateElementWithDefaults(
291 const nsAtom
& aTagName
);
294 * Indent or outdent content around Selection.
296 * @param aPrincipal Set subject principal if it may be called by
297 * JS. If set to nullptr, will be treated as
300 MOZ_CAN_RUN_SCRIPT nsresult
301 IndentAsAction(nsIPrincipal
* aPrincipal
= nullptr);
302 MOZ_CAN_RUN_SCRIPT nsresult
303 OutdentAsAction(nsIPrincipal
* aPrincipal
= nullptr);
306 * The Document.execCommand("formatBlock") handler.
308 * @param aParagraphFormat Must not be an empty string, and the value must
309 * be one of address, article, aside, blockquote,
310 * div, footer, h1, h2, h3, h4, h5, h6, header,
311 * hgroup, main, nav, p, pre, selection, dt or dd.
313 MOZ_CAN_RUN_SCRIPT nsresult
FormatBlockAsAction(
314 const nsAString
& aParagraphFormat
, nsIPrincipal
* aPrincipal
= nullptr);
317 * The cmd_paragraphState command handler.
319 * @param aParagraphFormat Can be empty string. If this is empty string,
320 * this removes ancestor format elements.
321 * Otherwise, the value must be one of p, pre,
322 * h1, h2, h3, h4, h5, h6, address, dt or dl.
324 MOZ_CAN_RUN_SCRIPT nsresult
SetParagraphStateAsAction(
325 const nsAString
& aParagraphFormat
, nsIPrincipal
* aPrincipal
= nullptr);
327 MOZ_CAN_RUN_SCRIPT nsresult
AlignAsAction(const nsAString
& aAlignType
,
328 nsIPrincipal
* aPrincipal
= nullptr);
330 MOZ_CAN_RUN_SCRIPT nsresult
RemoveListAsAction(
331 const nsAString
& aListType
, nsIPrincipal
* aPrincipal
= nullptr);
334 * MakeOrChangeListAsAction() makes selected hard lines list element(s).
336 * @param aListElementTagName The new list element tag name. Must be
337 * nsGkAtoms::ul, nsGkAtoms::ol or
339 * @param aBulletType If this is not empty string, it's set
340 * to `type` attribute of new list item
341 * elements. Otherwise, existing `type`
342 * attributes will be removed.
343 * @param aSelectAllOfCurrentList Yes if this should treat all of
344 * ancestor list element at selection.
346 enum class SelectAllOfCurrentList
{ Yes
, No
};
347 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
MakeOrChangeListAsAction(
348 const nsStaticAtom
& aListElementTagName
, const nsAString
& aBulletType
,
349 SelectAllOfCurrentList aSelectAllOfCurrentList
,
350 nsIPrincipal
* aPrincipal
= nullptr);
353 * If aTargetElement is a resizer, start to drag the resizer. Otherwise, if
354 * aTargetElement is the grabber, start to handle drag gester on it.
356 * @param aMouseDownEvent A `mousedown` event fired on aTargetElement.
357 * @param aEventTargetElement The target element being pressed. This must
358 * be same as explicit original event target of
361 MOZ_CAN_RUN_SCRIPT nsresult
StartToDragResizerOrHandleDragGestureOnGrabber(
362 dom::MouseEvent
& aMouseDownEvent
, Element
& aEventTargetElement
);
365 * If the editor is handling dragging a resizer, handling drag gesture on
366 * the grabber or dragging the grabber, this finalize it. Otherwise,
369 * @param aClientPoint The final point of the drag.
371 MOZ_CAN_RUN_SCRIPT nsresult
372 StopDraggingResizerOrGrabberAt(const CSSIntPoint
& aClientPoint
);
375 * If the editor is handling dragging a resizer, handling drag gesture to
376 * start dragging the grabber or dragging the grabber, this method updates
379 * @param aClientPoint The new point of the drag.
381 MOZ_CAN_RUN_SCRIPT nsresult
382 UpdateResizerOrGrabberPositionTo(const CSSIntPoint
& aClientPoint
);
385 * IsCSSEnabled() returns true if this editor treats styles with style
386 * attribute of HTML elements. Otherwise, if this editor treats all styles
387 * with "font style elements" like <b>, <i>, etc, and <blockquote> to indent,
388 * align attribute to align contents, returns false.
390 bool IsCSSEnabled() const { return mIsCSSPrefChecked
; }
393 * Enable/disable object resizers for <img> elements, <table> elements,
394 * absolute positioned elements (required absolute position editor enabled).
396 MOZ_CAN_RUN_SCRIPT
void EnableObjectResizer(bool aEnable
) {
397 if (mIsObjectResizingEnabled
== aEnable
) {
401 AutoEditActionDataSetter
editActionData(
402 *this, EditAction::eEnableOrDisableResizer
);
403 if (NS_WARN_IF(!editActionData
.CanHandle())) {
407 mIsObjectResizingEnabled
= aEnable
;
410 bool IsObjectResizerEnabled() const { return mIsObjectResizingEnabled
; }
412 Element
* GetResizerTarget() const { return mResizedObject
; }
415 * Enable/disable inline table editor, e.g., adding new row or column,
416 * removing existing row or column.
418 MOZ_CAN_RUN_SCRIPT
void EnableInlineTableEditor(bool aEnable
) {
419 if (mIsInlineTableEditingEnabled
== aEnable
) {
423 AutoEditActionDataSetter
editActionData(
424 *this, EditAction::eEnableOrDisableInlineTableEditingUI
);
425 if (NS_WARN_IF(!editActionData
.CanHandle())) {
429 mIsInlineTableEditingEnabled
= aEnable
;
432 bool IsInlineTableEditorEnabled() const {
433 return mIsInlineTableEditingEnabled
;
437 * Enable/disable absolute position editor, resizing absolute positioned
438 * elements (required object resizers enabled) or positioning them with
441 MOZ_CAN_RUN_SCRIPT
void EnableAbsolutePositionEditor(bool aEnable
) {
442 if (mIsAbsolutelyPositioningEnabled
== aEnable
) {
446 AutoEditActionDataSetter
editActionData(
447 *this, EditAction::eEnableOrDisableAbsolutePositionEditor
);
448 if (NS_WARN_IF(!editActionData
.CanHandle())) {
452 mIsAbsolutelyPositioningEnabled
= aEnable
;
455 bool IsAbsolutePositionEditorEnabled() const {
456 return mIsAbsolutelyPositioningEnabled
;
460 * returns the deepest absolutely positioned container of the selection
461 * if it exists or null.
463 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Element
>
464 GetAbsolutelyPositionedSelectionContainer() const;
466 Element
* GetPositionedElement() const { return mAbsolutelyPositionedObject
; }
469 * extracts the selection from the normal flow of the document and
472 * @param aEnabled [IN] true to absolutely position the selection,
473 * false to put it back in the normal flow
474 * @param aPrincipal Set subject principal if it may be called by
475 * JS. If set to nullptr, will be treated as
478 MOZ_CAN_RUN_SCRIPT nsresult
SetSelectionToAbsoluteOrStaticAsAction(
479 bool aEnabled
, nsIPrincipal
* aPrincipal
= nullptr);
482 * returns the absolute z-index of a positioned element. Never returns 'auto'
483 * @return the z-index of the element
484 * @param aElement [IN] the element.
486 MOZ_CAN_RUN_SCRIPT
int32_t GetZIndex(Element
& aElement
);
489 * adds aChange to the z-index of the currently positioned element.
491 * @param aChange [IN] relative change to apply to current z-index
492 * @param aPrincipal Set subject principal if it may be called by
493 * JS. If set to nullptr, will be treated as
496 MOZ_CAN_RUN_SCRIPT nsresult
497 AddZIndexAsAction(int32_t aChange
, nsIPrincipal
* aPrincipal
= nullptr);
499 MOZ_CAN_RUN_SCRIPT nsresult
SetBackgroundColorAsAction(
500 const nsAString
& aColor
, nsIPrincipal
* aPrincipal
= nullptr);
503 * SetInlinePropertyAsAction() sets a property which changes inline style of
504 * text. E.g., bold, italic, super and sub.
505 * This automatically removes exclusive style, however, treats all changes
508 * @param aPrincipal Set subject principal if it may be called by
509 * JS. If set to nullptr, will be treated as
512 MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertyAsAction(
513 nsStaticAtom
& aProperty
, nsStaticAtom
* aAttribute
,
514 const nsAString
& aValue
, nsIPrincipal
* aPrincipal
= nullptr);
517 * GetInlineProperty() gets aggregate properties of the current selection.
518 * All object in the current selection are scanned and their attributes are
519 * represented in a list of Property object.
520 * TODO: Make this return Result<Something> instead of bool out arguments.
522 * @param aHTMLProperty the property to get on the selection
523 * @param aAttribute the attribute of the property, if applicable.
525 * Example: aHTMLProperty=nsGkAtoms::font,
526 * aAttribute=nsGkAtoms::color
527 * @param aValue if aAttribute is not null, the value of the
528 * attribute. May be null.
529 * Example: aHTMLProperty=nsGkAtoms::font,
530 * aAttribute=nsGkAtoms::color,
532 * @param aFirst [OUT] true if the first text node in the
533 * selection has the property
534 * @param aAny [OUT] true if any of the text nodes in the
535 * selection have the property
536 * @param aAll [OUT] true if all of the text nodes in the
537 * selection have the property
539 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlineProperty(
540 nsStaticAtom
& aHTMLProperty
, nsAtom
* aAttribute
, const nsAString
& aValue
,
541 bool* aFirst
, bool* aAny
, bool* aAll
) const;
543 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlinePropertyWithAttrValue(
544 nsStaticAtom
& aHTMLProperty
, nsAtom
* aAttribute
, const nsAString
& aValue
,
545 bool* aFirst
, bool* aAny
, bool* aAll
, nsAString
& outValue
);
548 * RemoveInlinePropertyAsAction() removes a property which changes inline
549 * style of text. E.g., bold, italic, super and sub.
551 * @param aHTMLProperty Tag name whcih represents the inline style you want
552 * to remove. E.g., nsGkAtoms::strong, nsGkAtoms::b,
553 * etc. If nsGkAtoms::href, <a> element which has
554 * href attribute will be removed.
555 * If nsGkAtoms::name, <a> element which has non-empty
556 * name attribute will be removed.
557 * @param aAttribute If aHTMLProperty is nsGkAtoms::font, aAttribute should
558 * be nsGkAtoms::fase, nsGkAtoms::size, nsGkAtoms::color
559 * or nsGkAtoms::bgcolor. Otherwise, set nullptr.
560 * Must not use nsGkAtoms::_empty here.
561 * @param aPrincipal Set subject principal if it may be called by JS. If
562 * set to nullptr, will be treated as called by system.
564 MOZ_CAN_RUN_SCRIPT nsresult
RemoveInlinePropertyAsAction(
565 nsStaticAtom
& aHTMLProperty
, nsStaticAtom
* aAttribute
,
566 nsIPrincipal
* aPrincipal
= nullptr);
568 MOZ_CAN_RUN_SCRIPT nsresult
569 RemoveAllInlinePropertiesAsAction(nsIPrincipal
* aPrincipal
= nullptr);
571 MOZ_CAN_RUN_SCRIPT nsresult
572 IncreaseFontSizeAsAction(nsIPrincipal
* aPrincipal
= nullptr);
574 MOZ_CAN_RUN_SCRIPT nsresult
575 DecreaseFontSizeAsAction(nsIPrincipal
* aPrincipal
= nullptr);
578 * GetFontColorState() returns foreground color information in first
579 * range of Selection.
580 * If first range of Selection is collapsed and there is a cache of style for
581 * new text, aIsMixed is set to false and aColor is set to the cached color.
582 * If first range of Selection is collapsed and there is no cached color,
583 * this returns the color of the node, aIsMixed is set to false and aColor is
585 * If first range of Selection is not collapsed, this collects colors of
586 * each node in the range. If there are two or more colors, aIsMixed is set
587 * to true and aColor is truncated. If only one color is set to all of the
588 * range, aIsMixed is set to false and aColor is set to the color.
589 * If there is no Selection ranges, aIsMixed is set to false and aColor is
592 * @param aIsMixed Must not be nullptr. This is set to true
593 * if there is two or more colors in first
594 * range of Selection.
595 * @param aColor Returns the color if only one color is set to
596 * all of first range in Selection. Otherwise,
597 * returns empty string.
598 * @return Returns error only when illegal cases, e.g.,
599 * Selection instance has gone, first range
600 * Selection is broken.
602 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
603 GetFontColorState(bool* aIsMixed
, nsAString
& aColor
);
606 * Detach aComposerCommandsUpdater from this.
608 void Detach(const ComposerCommandsUpdater
& aComposerCommandsUpdater
);
610 nsStaticAtom
& DefaultParagraphSeparatorTagName() const {
611 return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator
);
613 ParagraphSeparator
GetDefaultParagraphSeparator() const {
614 return mDefaultParagraphSeparator
;
616 void SetDefaultParagraphSeparator(ParagraphSeparator aSep
) {
617 mDefaultParagraphSeparator
= aSep
;
619 static nsStaticAtom
& ToParagraphSeparatorTagName(
620 ParagraphSeparator aSeparator
) {
621 switch (aSeparator
) {
622 case ParagraphSeparator::div
:
623 return *nsGkAtoms::div
;
624 case ParagraphSeparator::p
:
625 return *nsGkAtoms::p
;
626 case ParagraphSeparator::br
:
627 return *nsGkAtoms::br
;
629 MOZ_ASSERT_UNREACHABLE("New paragraph separator isn't handled here");
630 return *nsGkAtoms::div
;
635 * Modifies the table containing the selection according to the
636 * activation of an inline table editing UI element
637 * @param aUIAnonymousElement [IN] the inline table editing UI element
639 MOZ_CAN_RUN_SCRIPT nsresult
640 DoInlineTableEditingAction(const Element
& aUIAnonymousElement
);
643 * GetInclusiveAncestorByTagName() looks for an element node whose name
644 * matches aTagName from aNode or anchor node of Selection to <body> element.
646 * @param aTagName The tag name which you want to look for.
647 * Must not be nsGkAtoms::_empty.
648 * If nsGkAtoms::list, the result may be <ul>, <ol> or
650 * If nsGkAtoms::td, the result may be <td> or <th>.
651 * If nsGkAtoms::href, the result may be <a> element
652 * which has "href" attribute with non-empty value.
653 * If nsGkAtoms::anchor, the result may be <a> which
654 * has "name" attribute with non-empty value.
655 * @param aContent Start node to look for the result.
656 * @return If an element which matches aTagName, returns
657 * an Element. Otherwise, nullptr.
659 Element
* GetInclusiveAncestorByTagName(const nsStaticAtom
& aTagName
,
660 nsIContent
& aContent
) const;
663 * Compute editing host for aContent. If this editor isn't active in the DOM
664 * window, this returns nullptr.
666 enum class LimitInBodyElement
{ No
, Yes
};
667 [[nodiscard
]] Element
* ComputeEditingHost(
668 const nsIContent
& aContent
,
669 LimitInBodyElement aLimitInBodyElement
= LimitInBodyElement::Yes
) const {
670 return ComputeEditingHostInternal(&aContent
, aLimitInBodyElement
);
674 * Compute editing host for the focus node of the Selection. If this editor
675 * isn't active in the DOM window, this returns nullptr.
677 [[nodiscard
]] Element
* ComputeEditingHost(
678 LimitInBodyElement aLimitInBodyElement
= LimitInBodyElement::Yes
) const {
679 return ComputeEditingHostInternal(nullptr, aLimitInBodyElement
);
683 * Return true if we're in designMode.
685 bool IsInDesignMode() const;
688 * Return true if entire the document is editable (although the document
689 * may have non-editable nodes, e.g.,
690 * <body contenteditable><div contenteditable="false"></div></body>
692 bool EntireDocumentIsEditable() const;
695 * Basically, this always returns true if we're for `contenteditable` or
696 * `designMode` editor in web apps. However, e.g., Composer of SeaMonkey
697 * can make the editor not tabbable.
699 bool IsTabbable() const { return IsInteractionAllowed(); }
702 * NotifyEditingHostMaybeChanged() is called when new element becomes
703 * contenteditable when the document already had contenteditable elements.
705 void NotifyEditingHostMaybeChanged();
707 /** Insert a string as quoted text
708 * (whose representation is dependant on the editor type),
709 * replacing the selected text (if any).
711 * @param aQuotedText The actual text to be quoted
712 * @parem aNodeInserted Return the node which was inserted.
714 MOZ_CAN_RUN_SCRIPT
// USED_BY_COMM_CENTRAL
716 InsertAsQuotation(const nsAString
& aQuotedText
, nsINode
** aNodeInserted
);
718 MOZ_CAN_RUN_SCRIPT nsresult
InsertHTMLAsAction(
719 const nsAString
& aInString
, nsIPrincipal
* aPrincipal
= nullptr);
722 * Refresh positions of resizers. If you change size of target of resizers,
723 * you need to refresh position of resizers with calling this.
725 MOZ_CAN_RUN_SCRIPT nsresult
RefreshResizers();
727 bool IsWrapHackEnabled() const {
728 return (mFlags
& nsIEditor::eEditorEnableWrapHackMask
) != 0;
732 * Return true if this is in the plaintext mail composer mode of
733 * Thunderbird or something.
734 * NOTE: This is different from contenteditable="plaintext-only"
736 bool IsPlaintextMailComposer() const {
737 const bool isPlaintextMode
=
738 (mFlags
& nsIEditor::eEditorPlaintextMask
) != 0;
739 MOZ_ASSERT_IF(IsTextEditor(), isPlaintextMode
);
740 return isPlaintextMode
;
743 protected: // May be called by friends.
744 /****************************************************************************
745 * Some friend classes are allowed to call the following protected methods.
746 * However, those methods won't prepare caches of some objects which are
747 * necessary for them. So, if you call them from friend classes, you need
748 * to make sure that AutoEditActionDataSetter is created.
749 ****************************************************************************/
752 * InsertBRElement() creates a <br> element and inserts it before
755 * @param aWithTransaction Whether the inserting is new element is undoable
756 * or not. WithTransaction::No is useful only when
757 * the new element is inserted into a new element
758 * which has not been connected yet.
759 * @param aPointToInsert The DOM point where should be <br> node inserted
761 * @param aSelect If eNone, returns a point to put caret which is
762 * suggested by InsertNodeTransaction.
763 * If eNext, returns a point after the new <br>
765 * If ePrevious, returns a point at the new <br>
767 * @return The new <br> node and suggesting point to put
768 * caret which respects aSelect.
770 MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
> InsertBRElement(
771 WithTransaction aWithTransaction
, const EditorDOMPoint
& aPointToInsert
,
772 EDirection aSelect
= eNone
);
775 * Delete text in the range in aTextNode. If aTextNode is not editable, this
778 * @param aTextNode The text node which should be modified.
779 * @param aOffset Start offset of removing text in aTextNode.
780 * @param aLength Length of removing text.
782 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
783 DeleteTextWithTransaction(dom::Text
& aTextNode
, uint32_t aOffset
,
787 * Replace text in the range with aStringToInsert. If there is a DOM range
788 * exactly same as the replacing range, it'll be collapsed to
789 * {aTextNode, aOffset} because of the order of deletion and insertion.
790 * Therefore, the callers may need to handle `Selection` even when callers
791 * do not want to update `Selection`.
793 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertTextResult
, nsresult
>
794 ReplaceTextWithTransaction(dom::Text
& aTextNode
, uint32_t aOffset
,
796 const nsAString
& aStringToInsert
);
799 * Insert aStringToInsert to aPointToInsert. If the point is not editable,
800 * this returns error.
802 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertTextResult
, nsresult
>
803 InsertTextWithTransaction(Document
& aDocument
,
804 const nsAString
& aStringToInsert
,
805 const EditorDOMPoint
& aPointToInsert
) final
;
808 * CopyLastEditableChildStyles() clones inline container elements into
809 * aPreviousBlock to aNewBlock to keep using same style in it.
811 * @param aPreviousBlock The previous block element. All inline
812 * elements which are last sibling of each level
813 * are cloned to aNewBlock.
814 * @param aNewBlock New block container element. All children of
815 * this is deleted first.
816 * @param aEditingHost The editing host.
817 * @return If succeeded, returns a suggesting point to put
820 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
821 CopyLastEditableChildStylesWithTransaction(Element
& aPreviousBlock
,
823 const Element
& aEditingHost
);
826 * RemoveBlockContainerWithTransaction() removes aElement from the DOM tree
827 * but moves its all children to its parent node and if its parent needs <br>
828 * element to have at least one line-height, this inserts <br> element
831 * @param aElement Block element to be removed.
832 * @return If succeeded, returns a suggesting point to put
835 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
836 RemoveBlockContainerWithTransaction(Element
& aElement
);
838 MOZ_CAN_RUN_SCRIPT nsresult
RemoveAttributeOrEquivalent(
839 Element
* aElement
, nsAtom
* aAttribute
, bool aSuppressTransaction
) final
;
840 MOZ_CAN_RUN_SCRIPT nsresult
SetAttributeOrEquivalent(
841 Element
* aElement
, nsAtom
* aAttribute
, const nsAString
& aValue
,
842 bool aSuppressTransaction
) final
;
843 using EditorBase::RemoveAttributeOrEquivalent
;
844 using EditorBase::SetAttributeOrEquivalent
;
847 * Returns container element of ranges in Selection. If Selection is
848 * collapsed, returns focus container node (or its parent element).
849 * If Selection selects only one element node, returns the element node.
850 * If Selection is only one range, returns common ancestor of the range.
851 * XXX If there are two or more Selection ranges, this returns parent node
852 * of start container of a range which starts with different node from
853 * start container of the first range.
855 Element
* GetSelectionContainerElement() const;
858 * DeleteTableCellContentsWithTransaction() removes any contents in cell
859 * elements. If two or more cell elements are selected, this removes
860 * all selected cells' contents. Otherwise, this removes contents of
861 * a cell which contains first selection range. This does not return
862 * error even if selection is not in cell element, just does nothing.
864 MOZ_CAN_RUN_SCRIPT nsresult
DeleteTableCellContentsWithTransaction();
867 * extracts an element from the normal flow of the document and
868 * positions it, and puts it back in the normal flow.
869 * @param aElement [IN] the element
870 * @param aEnabled [IN] true to absolutely position the element,
871 * false to put it back in the normal flow
873 MOZ_CAN_RUN_SCRIPT nsresult
SetPositionToAbsoluteOrStatic(Element
& aElement
,
877 * adds aChange to the z-index of an arbitrary element.
878 * @param aElement [IN] the element
879 * @param aChange [IN] relative change to apply to current z-index of
881 * @return The new z-index of the element
883 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<int32_t, nsresult
>
884 AddZIndexWithTransaction(nsStyledElement
& aStyledElement
, int32_t aChange
);
887 * Join together any adjacent editable text nodes in the range.
889 MOZ_CAN_RUN_SCRIPT nsresult
CollapseAdjacentTextNodes(nsRange
& aRange
);
891 static dom::Element
* GetLinkElement(nsINode
* aNode
);
894 * Helper routines for font size changing.
896 enum class FontSize
{ incr
, decr
};
897 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
898 SetFontSizeOnTextNode(Text
& aTextNode
, uint32_t aStartOffset
,
899 uint32_t aEndOffset
, FontSize aIncrementOrDecrement
);
901 enum class SplitAtEdges
{
902 // SplitNodeDeepWithTransaction() won't split container element
903 // nodes at their edges. I.e., when split point is start or end of
904 // container, it won't be split.
905 eDoNotCreateEmptyContainer
,
906 // SplitNodeDeepWithTransaction() always splits containers even
907 // if the split point is at edge of a container. E.g., if split point is
908 // start of an inline element, empty inline element is created as a new left
910 eAllowToCreateEmptyContainer
,
914 * SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
915 * elements in the block at aRange if given style matches with some of them.
917 * @param aRange Ancestor inline elements of the start and end
918 * boundaries will be split.
919 * @param aStyle The style which you want to split.
920 * RemoveAllStyles instance is allowed to split any
922 * @param aSplitAtEdges Whether this should split elements at start or
923 * end of inline elements or not.
925 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffResult
, nsresult
>
926 SplitAncestorStyledInlineElementsAtRangeEdges(const EditorDOMRange
& aRange
,
927 const EditorInlineStyle
& aStyle
,
928 SplitAtEdges aSplitAtEdges
);
931 * SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
932 * aPointToSplit if specified style matches with them.
934 * @param aPointToSplit The point to split style at.
935 * @param aStyle The style which you want to split.
936 * RemoveAllStyles instance is allowed to split any
938 * @param aSplitAtEdges Whether this should split elements at start or
939 * end of inline elements or not.
940 * @return The result of SplitNodeDeepWithTransaction()
941 * with topmost split element. If this didn't
942 * find inline elements to be split, Handled()
945 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
946 SplitAncestorStyledInlineElementsAt(const EditorDOMPoint
& aPointToSplit
,
947 const EditorInlineStyle
& aStyle
,
948 SplitAtEdges aSplitAtEdges
);
950 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlinePropertyBase(
951 const EditorInlineStyle
& aStyle
, const nsAString
* aValue
, bool* aFirst
,
952 bool* aAny
, bool* aAll
, nsAString
* outValue
) const;
955 * ClearStyleAt() splits parent elements to remove the specified style.
956 * If this splits some parent elements at near their start or end, such
957 * empty elements will be removed. Then, remove the specified style
958 * from the point and returns DOM point to put caret.
960 * @param aPoint The point to clear style at.
961 * @param aStyleToRemove The style which you want to clear.
962 * @param aSpecifiedStyle Whether the class and style attributes should
963 * be preserved or discarded.
964 * @return A candidate position to put caret. If there is
965 * AutoTransactionsConserveSelection instances, this stops
966 * suggesting caret point only in some cases.
968 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
969 ClearStyleAt(const EditorDOMPoint
& aPoint
,
970 const EditorInlineStyle
& aStyleToRemove
,
971 SpecifiedStyle aSpecifiedStyle
);
973 MOZ_CAN_RUN_SCRIPT nsresult
SetPositionToAbsolute(Element
& aElement
);
974 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
975 SetPositionToStatic(Element
& aElement
);
978 * OnModifyDocument() is called when the editor is changed. This should
979 * be called only by runnable in HTMLEditor::OnDocumentModified() to call
980 * HTMLEditor::OnModifyDocument() with AutoEditActionDataSetter instance.
982 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
OnModifyDocument();
985 * DoSplitNode() inserts aNewNode and moves all content before or after
986 * aStartOfRightNode to aNewNode.
988 * @param aStartOfRightNode The point to split. The container will keep
989 * having following or previous content of this.
990 * @param aNewNode The new node called. The previous or following
991 * content of aStartOfRightNode will be moved into
994 MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
> DoSplitNode(
995 const EditorDOMPoint
& aStartOfRightNode
, nsIContent
& aNewNode
);
998 * DoJoinNodes() merges contents in aContentToRemove to aContentToKeep and
999 * remove aContentToRemove from the DOM tree. aContentToRemove and
1000 * aContentToKeep must have same parent. Additionally, if one of
1001 * aContentToRemove or aContentToKeep is a text node, the other must be a
1004 * @param aContentToKeep The node that will remain after the join.
1005 * @param aContentToRemove The node that will be joined with aContentToKeep.
1006 * There is no requirement that the two nodes be of
1009 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1010 DoJoinNodes(nsIContent
& aContentToKeep
, nsIContent
& aContentToRemove
);
1013 * Routines for managing the preservation of selection across
1014 * various editor actions.
1016 bool ArePreservingSelection() const;
1017 void PreserveSelectionAcrossActions();
1018 MOZ_CAN_RUN_SCRIPT nsresult
RestorePreservedSelection();
1019 void StopPreservingSelection();
1022 * Called when JoinNodesTransaction::DoTransaction() did its transaction.
1023 * Note that this is not called when undoing nor redoing.
1025 * @param aTransaction The transaction which did join nodes.
1026 * @param aDoJoinNodesResult Result of the doing join nodes.
1028 MOZ_CAN_RUN_SCRIPT
void DidJoinNodesTransaction(
1029 const JoinNodesTransaction
& aTransaction
, nsresult aDoJoinNodesResult
);
1031 protected: // edit sub-action handler
1033 * CanHandleHTMLEditSubAction() checks whether there is at least one
1034 * selection range or not, and whether the first range is editable.
1035 * If it's not editable, `Canceled()` of the result returns true.
1036 * If `Selection` is in odd situation, returns an error.
1038 * XXX I think that `IsSelectionEditable()` is better name, but it's already
1039 * in `EditorBase`...
1041 enum class CheckSelectionInReplacedElement
{ Yes
, OnlyWhenNotInSameNode
};
1042 Result
<EditActionResult
, nsresult
> CanHandleHTMLEditSubAction(
1043 CheckSelectionInReplacedElement aCheckSelectionInReplacedElement
=
1044 CheckSelectionInReplacedElement::Yes
) const;
1047 * EnsureCaretNotAfterInvisibleBRElement() makes sure that caret is NOT after
1048 * padding `<br>` element for preventing insertion after padding `<br>`
1049 * element at empty last line.
1050 * NOTE: This method should be called only when `Selection` is collapsed
1051 * because `Selection` is a pain to work with when not collapsed.
1052 * (no good way to extend start or end of selection), so we need to
1053 * ignore those types of selections.
1055 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1056 EnsureCaretNotAfterInvisibleBRElement();
1059 * MaybeCreatePaddingBRElementForEmptyEditor() creates padding <br> element
1060 * for empty editor if there is no children.
1062 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1063 MaybeCreatePaddingBRElementForEmptyEditor();
1066 * EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
1067 * for empty editor if there is.
1069 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1070 EnsureNoPaddingBRElementForEmptyEditor();
1073 * ReflectPaddingBRElementForEmptyEditor() scans the tree from the root
1074 * element and sets mPaddingBRElementForEmptyEditor if exists, or otherwise
1075 * nullptr. Can be used to manage undo/redo.
1077 [[nodiscard
]] nsresult
ReflectPaddingBRElementForEmptyEditor();
1080 * PrepareInlineStylesForCaret() consider inline styles from top level edit
1081 * sub-action and setting it to `mPendingStylesToApplyToNewContent` and clear
1082 * inline style cache if necessary.
1083 * NOTE: This method should be called only when `Selection` is collapsed.
1085 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
PrepareInlineStylesForCaret();
1087 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
1088 HandleInsertText(EditSubAction aEditSubAction
,
1089 const nsAString
& aInsertionString
,
1090 SelectionHandling aSelectionHandling
) final
;
1092 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertDroppedDataTransferAsAction(
1093 AutoEditActionDataSetter
& aEditActionData
,
1094 dom::DataTransfer
& aDataTransfer
, const EditorDOMPoint
& aDroppedAt
,
1095 nsIPrincipal
* aSourcePrincipal
) final
;
1098 * GetInlineStyles() retrieves the style of aElement and modifies each item of
1099 * aPendingStyleCacheArray. This might cause flushing layout at retrieving
1100 * computed values of CSS properties.
1102 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlineStyles(
1103 Element
& aElement
, AutoPendingStyleCacheArray
& aPendingStyleCacheArray
);
1106 * CacheInlineStyles() caches style of aElement into mCachedPendingStyles of
1107 * TopLevelEditSubAction. This may cause flushing layout at retrieving
1108 * computed value of CSS properties.
1110 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1111 CacheInlineStyles(Element
& aElement
);
1114 * ReapplyCachedStyles() restores some styles which are disappeared during
1115 * handling edit action and it should be restored. This may cause flushing
1116 * layout at retrieving computed value of CSS properties.
1118 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
ReapplyCachedStyles();
1121 * CreateStyleForInsertText() sets CSS properties which are stored in
1122 * PendingStyles to proper element node.
1124 * @param aPointToInsertText The point to insert text.
1125 * @param aEditingHost The editing host.
1126 * @return A suggest point to put caret or unset point.
1128 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1129 CreateStyleForInsertText(const EditorDOMPoint
& aPointToInsertText
,
1130 const Element
& aEditingHost
);
1133 * GetMostDistantAncestorMailCiteElement() returns most-ancestor mail cite
1134 * element. "mail cite element" is <pre> element when it's in plaintext editor
1135 * mode or an element with which calling HTMLEditUtils::IsMailCite() returns
1138 * @param aNode The start node to look for parent mail cite elements.
1140 Element
* GetMostDistantAncestorMailCiteElement(const nsINode
& aNode
) const;
1143 * HandleInsertParagraphInMailCiteElement() splits aMailCiteElement at
1146 * @param aMailCiteElement The mail-cite element which should be split.
1147 * @param aPointToSplit The point to split.
1148 * @param aEditingHost The editing host.
1149 * @return Candidate caret position where is at inserted
1150 * <br> element into the split point.
1152 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1153 HandleInsertParagraphInMailCiteElement(Element
& aMailCiteElement
,
1154 const EditorDOMPoint
& aPointToSplit
,
1155 const Element
& aEditingHost
);
1158 * HandleInsertBRElement() inserts a <br> element into aPointToBreak.
1159 * This may split container elements at the point and/or may move following
1160 * <br> element to immediately after the new <br> element if necessary.
1162 * @param aPointToBreak The point where new <br> element will be
1164 * @param aEditingHost Current active editing host.
1165 * @return If succeeded, returns new <br> element and
1166 * candidate caret point.
1168 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1169 HandleInsertBRElement(const EditorDOMPoint
& aPointToBreak
,
1170 const Element
& aEditingHost
);
1173 * HandleInsertLinefeed() inserts a linefeed character into aInsertToBreak.
1175 * @param aInsertToBreak The point where new linefeed character will be
1177 * @param aEditingHost Current active editing host.
1178 * @return A suggest point to put caret.
1180 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1181 HandleInsertLinefeed(const EditorDOMPoint
& aInsertToBreak
,
1182 const Element
& aEditingHost
);
1185 * Splits inclusive inline ancestors at both start and end of aRangeItem. If
1186 * this splits at every point, this modifies aRangeItem to point each split
1187 * point (typically, at right node).
1189 * @param aRangeItem [in/out] One or two DOM points where should be
1190 * split. Will be modified to split point if
1192 * @param aBlockInlineCheck [in] Whether this method considers block vs.
1193 * inline with computed style or the default style.
1194 * @param aEditingHost [in] The editing host.
1195 * @param aAncestorLimiter [in/optional] If specified, this stops splitting
1196 * ancestors when meets this node.
1197 * @return A suggest point to put caret if succeeded, but
1200 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1201 SplitInlineAncestorsAtRangeBoundaries(
1202 RangeItem
& aRangeItem
, BlockInlineCheck aBlockInlineCheck
,
1203 const Element
& aEditingHost
,
1204 const nsIContent
* aAncestorLimiter
= nullptr);
1207 * SplitElementsAtEveryBRElement() splits before all <br> elements in
1208 * aMostAncestorToBeSplit. All <br> nodes will be moved before right node
1209 * at splitting its parent. Finally, this returns left node, first <br>
1210 * element, next left node, second <br> element... and right-most node.
1212 * @param aMostAncestorToBeSplit Most-ancestor element which should
1214 * @param aOutArrayOfNodes First left node, first <br> element,
1215 * Second left node, second <br> element,
1216 * ...right-most node. So, all nodes
1217 * in this list should be siblings (may be
1218 * broken the relation by mutation event
1219 * listener though). If first <br> element
1220 * is first leaf node of
1221 * aMostAncestorToBeSplit, starting from
1222 * the first <br> element.
1223 * @return A suggest point to put caret if
1224 * succeeded, but it may unset.
1226 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1227 SplitElementsAtEveryBRElement(
1228 nsIContent
& aMostAncestorToBeSplit
,
1229 nsTArray
<OwningNonNull
<nsIContent
>>& aOutArrayOfContents
);
1232 * MaybeSplitElementsAtEveryBRElement() calls SplitElementsAtEveryBRElement()
1233 * for each given node when this needs to do that for aEditSubAction.
1234 * If split a node, it in aArrayOfContents is replaced with split nodes and
1237 * @return A suggest point to put caret if
1238 * succeeded, but it may unset.
1240 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1241 MaybeSplitElementsAtEveryBRElement(
1242 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1243 EditSubAction aEditSubAction
);
1246 * CreateRangeIncludingAdjuscentWhiteSpaces() creates an nsRange instance
1247 * which may be expanded from the given range to include adjuscent
1248 * white-spaces. If this fails handling something, returns nullptr.
1250 template <typename EditorDOMRangeType
>
1251 already_AddRefed
<nsRange
> CreateRangeIncludingAdjuscentWhiteSpaces(
1252 const EditorDOMRangeType
& aRange
);
1253 template <typename EditorDOMPointType1
, typename EditorDOMPointType2
>
1254 already_AddRefed
<nsRange
> CreateRangeIncludingAdjuscentWhiteSpaces(
1255 const EditorDOMPointType1
& aStartPoint
,
1256 const EditorDOMPointType2
& aEndPoint
);
1259 * GetRangeExtendedToHardLineEdgesForBlockEditAction() returns an extended
1260 * range if aRange should be extended before handling a block level editing.
1261 * If aRange start and/or end point <br> or something non-editable point, they
1262 * should be moved to nearest text node or something where the other methods
1263 * easier to handle edit action.
1265 [[nodiscard
]] Result
<EditorRawDOMRange
, nsresult
>
1266 GetRangeExtendedToHardLineEdgesForBlockEditAction(
1267 const nsRange
* aRange
, const Element
& aEditingHost
) const;
1270 * InitializeInsertingElement is a callback type of methods which inserts
1271 * an element into the DOM tree. This is called immediately before inserting
1272 * aNewElement into the DOM tree.
1274 * @param aHTMLEditor The HTML editor which modifies the DOM tree.
1275 * @param aNewElement The new element which will be or was inserted into
1277 * @param aPointToInsert The position aNewElement will be or was inserted.
1279 using InitializeInsertingElement
=
1280 std::function
<nsresult(HTMLEditor
& aHTMLEditor
, Element
& aNewElement
,
1281 const EditorDOMPoint
& aPointToInsert
)>;
1282 static InitializeInsertingElement DoNothingForNewElement
;
1283 static InitializeInsertingElement InsertNewBRElement
;
1286 * Helper methods to implement InitializeInsertingElement.
1288 MOZ_CAN_RUN_SCRIPT
static Result
<CreateElementResult
, nsresult
>
1289 AppendNewElementToInsertingElement(
1290 HTMLEditor
& aHTMLEditor
, const nsStaticAtom
& aTagName
,
1291 Element
& aNewElement
,
1292 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1293 MOZ_CAN_RUN_SCRIPT
static Result
<CreateElementResult
, nsresult
>
1294 AppendNewElementWithBRToInsertingElement(HTMLEditor
& aHTMLEditor
,
1295 const nsStaticAtom
& aTagName
,
1296 Element
& aNewElement
);
1299 * Create an element node whose name is aTag at before aPointToInsert. When
1300 * this succeed to create an element node, this inserts the element to
1303 * @param aWithTransaction Whether the inserting is new element is undoable
1304 * or not. WithTransaction::No is useful only when
1305 * the new element is inserted into a new element
1306 * which has not been connected yet.
1307 * @param aTagName The element name to create.
1308 * @param aPointToInsert The insertion point of new element.
1309 * If this refers end of the container or after,
1310 * the transaction will append the element to the
1312 * Otherwise, will insert the element before the
1313 * child node referred by this.
1314 * Note that this point will be invalid once this
1315 * method inserts the new element.
1316 * @param aInitializer A function to initialize the new element before
1317 * connecting the element into the DOM tree. Note
1318 * that this should not touch outside given element
1319 * because doing it would break range updater's
1321 * @return The created new element node and candidate caret
1324 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1325 CreateAndInsertElement(
1326 WithTransaction aWithTransaction
, const nsAtom
& aTagName
,
1327 const EditorDOMPoint
& aPointToInsert
,
1328 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1331 * Callback of CopyAttributes().
1333 * @param aHTMLEditor The HTML editor.
1334 * @param aSrcElement The element which have the attribute.
1335 * @param aDestElement The element which will have the attribute.
1336 * @param aAttr [in] The attribute which will be copied.
1337 * @param aValue [in/out] The attribute value which will be copied.
1338 * Once updated, the new value is used.
1339 * @return true if the attribute should be copied, otherwise,
1342 using AttributeFilter
= std::function
<bool(
1343 HTMLEditor
& aHTMLEditor
, Element
& aSrcElement
, Element
& aDestElement
,
1344 const dom::Attr
& aAttr
, nsString
& aValue
)>;
1345 static AttributeFilter CopyAllAttributes
;
1346 static AttributeFilter CopyAllAttributesExceptId
;
1347 static AttributeFilter CopyAllAttributesExceptDir
;
1348 static AttributeFilter CopyAllAttributesExceptIdAndDir
;
1351 * Copy all attributes of aSrcElement to aDestElement as-is. Different from
1352 * EditorBase::CloneAttributesWithTransaction(), this does not use
1353 * SetAttributeOrEquivalent() nor does not clear existing attributes of
1356 * @param aWithTransaction Whether recoding with transactions or not.
1357 * @param aDestElement The element will have attributes.
1358 * @param aSrcElement The element whose attributes will be copied.
1360 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
CopyAttributes(
1361 WithTransaction aWithTransaction
, Element
& aDestElement
,
1362 Element
& aSrcElement
, const AttributeFilter
& = CopyAllAttributes
);
1365 * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
1366 * aStartOfDeepestRightNode can have an element whose tag name is aTag.
1367 * Otherwise, looks for an ancestor node which is or is in active editing
1368 * host and can have an element whose name is aTag. If there is such
1369 * ancestor, its descendants are split.
1371 * Note that this may create empty elements while splitting ancestors.
1373 * @param aTag The name of element to be inserted
1374 * after calling this method.
1375 * @param aStartOfDeepestRightNode The start point of deepest right node.
1376 * This point must be in aEditingHost.
1377 * @param aEditingHost The editing host.
1378 * @return When succeeded, SplitPoint() returns
1379 * the point to insert the element.
1381 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
1382 MaybeSplitAncestorsForInsertWithTransaction(
1383 const nsAtom
& aTag
, const EditorDOMPoint
& aStartOfDeepestRightNode
,
1384 const Element
& aEditingHost
);
1387 * InsertElementWithSplittingAncestorsWithTransaction() is a wrapper of
1388 * MaybeSplitAncestorsForInsertWithTransaction() and CreateAndInsertElement().
1389 * I.e., will create an element whose tag name is aTagName and split ancestors
1390 * if it's necessary, then, insert it.
1392 * @param aTagName The tag name which you want to insert new
1393 * element at aPointToInsert.
1394 * @param aPointToInsert The insertion point. New element will be
1395 * inserted before here.
1396 * @param aBRElementNextToSplitPoint
1397 * Whether <br> element should be deleted or
1398 * kept if and only if a <br> element follows
1400 * @param aEditingHost The editing host with which we're handling it.
1401 * @param aInitializer A function to initialize the new element before
1402 * connecting the element into the DOM tree. Note
1403 * that this should not touch outside given element
1404 * because doing it would break range updater's
1406 * @return If succeeded, returns the new element node and
1407 * suggesting point to put caret.
1409 enum class BRElementNextToSplitPoint
{ Keep
, Delete
};
1410 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1411 InsertElementWithSplittingAncestorsWithTransaction(
1412 const nsAtom
& aTagName
, const EditorDOMPoint
& aPointToInsert
,
1413 BRElementNextToSplitPoint aBRElementNextToSplitPoint
,
1414 const Element
& aEditingHost
,
1415 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1418 * Split aElementToSplit at two points, before aStartOfMiddleElement and after
1419 * aEndOfMiddleElement. If they are very start or very end of aBlockElement,
1420 * this won't create empty block.
1422 * @param aElementToSplit An element which will be split.
1423 * @param aStartOfMiddleElement Start node of middle block element.
1424 * @param aEndOfMiddleElement End node of middle block element.
1426 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
1427 SplitRangeOffFromElement(Element
& aElementToSplit
,
1428 nsIContent
& aStartOfMiddleElement
,
1429 nsIContent
& aEndOfMiddleElement
);
1432 * RemoveBlockContainerElementWithTransactionBetween() splits the nodes
1433 * at aStartOfRange and aEndOfRange, then, removes the middle element which
1434 * was split off from aBlockContainerElement and moves the ex-children to
1435 * where the middle element was. I.e., all nodes between aStartOfRange and
1436 * aEndOfRange (including themselves) will be unwrapped from
1437 * aBlockContainerElement.
1439 * @param aBlockContainerElement The node which will be split.
1440 * @param aStartOfRange The first node which will be unwrapped
1441 * from aBlockContainerElement.
1442 * @param aEndOfRange The last node which will be unwrapped from
1443 * aBlockContainerElement.
1444 * @param aBlockInlineCheck Whether this method considers block vs.
1445 * inline with computed style or the default
1447 * @return The left content is new created left
1448 * element of aBlockContainerElement.
1449 * The right content is split element,
1450 * i.e., must be aBlockContainerElement.
1451 * The middle content is nullptr since
1452 * removing it is the job of this method.
1454 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
1455 RemoveBlockContainerElementWithTransactionBetween(
1456 Element
& aBlockContainerElement
, nsIContent
& aStartOfRange
,
1457 nsIContent
& aEndOfRange
, BlockInlineCheck aBlockInlineCheck
);
1460 * WrapContentsInBlockquoteElementsWithTransaction() inserts at least one
1461 * <blockquote> element and moves nodes in aArrayOfContents into new
1462 * <blockquote> elements. If aArrayOfContents includes a table related element
1463 * except <table>, this calls itself recursively to insert <blockquote> into
1466 * @param aArrayOfContents Nodes which will be moved into created
1467 * <blockquote> elements.
1468 * @param aEditingHost The editing host.
1469 * @return A blockquote element which is created at last
1470 * and a suggest of caret position if succeeded.
1471 * The caret suggestion may be unset if there is
1474 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1475 WrapContentsInBlockquoteElementsWithTransaction(
1476 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1477 const Element
& aEditingHost
);
1480 * Our traditional formatBlock was same as XUL cmd_paragraphState command.
1481 * However, the behavior is pretty different from the others and aligning
1482 * the XUL command behavior may break Thunderbird a lot because it handles
1483 * <blockquote> in a special path and <div> (generic block element) is not
1484 * treated as a format node and these things may be used for designing
1485 * current roles of the elements in the email composer of Thunderbird.
1486 * Therefore, we create a new mode for HTMLFormatBlockCommand to align
1487 * the behavior to the others but does not harm Thunderbird.
1489 enum class FormatBlockMode
{
1490 // Document.execCommand("formatBlock"). Cannot set new format to "normal"
1491 // nor "". So, the paths to handle these ones are not used in this mode.
1492 HTMLFormatBlockCommand
,
1493 // cmd_paragraphState. Can set new format to "normal" or "" to remove
1494 // ancestor format blocks.
1495 XULParagraphStateCommand
,
1499 * RemoveBlockContainerElementsWithTransaction() removes all format blocks,
1500 * table related element, etc in aArrayOfContents from the DOM tree. If
1501 * aArrayOfContents has a format node, it will be removed and its contents
1502 * will be moved to where it was.
1503 * If aArrayOfContents has a table related element, <li>, <blockquote> or
1504 * <div>, it will be removed and its contents will be moved to where it was.
1506 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1507 * paragraphState command.
1509 * @return A suggest point to put caret if succeeded, but it may be
1510 * unset if there is no suggestion.
1512 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1513 RemoveBlockContainerElementsWithTransaction(
1514 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1515 FormatBlockMode aFormatBlockMode
, BlockInlineCheck aBlockInlineCheck
);
1518 * CreateOrChangeFormatContainerElement() formats all nodes in
1519 * aArrayOfContents with block elements whose name is aNewFormatTagName.
1521 * If aArrayOfContents has an inline element, a block element is created and
1522 * the inline element and following inline elements are moved into the new
1524 * If aArrayOfContents has <br> elements, they'll be removed from the DOM tree
1525 * and new block element will be created when there are some remaining inline
1527 * If aArrayOfContents has a block element, this calls itself with children of
1528 * the block element. Then, new block element will be created when there are
1529 * some remaining inline elements.
1531 * @param aArrayOfContents Must be descendants of a node.
1532 * @param aNewFormatTagName The element name of new block elements.
1533 * @param aFormatBlockMode The replacing block element target type is for
1534 * whether HTML formatBLock command or XUL
1535 * paragraphState command.
1536 * @param aEditingHost The editing host.
1537 * @return The latest created new block element and a
1538 * suggest point to put caret.
1540 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1541 CreateOrChangeFormatContainerElement(
1542 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1543 const nsStaticAtom
& aNewFormatTagName
, FormatBlockMode aFormatBlockMode
,
1544 const Element
& aEditingHost
);
1547 * FormatBlockContainerWithTransaction() is implementation of "formatBlock"
1548 * command of `Document.execCommand()`. This applies block style or removes
1551 * @param aSelectionRanges The ranges which are cloned by selection or
1552 * updated from it with doing something before
1554 * @param aNewFormatTagName New block tag name.
1555 * If nsGkAtoms::normal or nsGkAtoms::_empty,
1556 * RemoveBlockContainerElementsWithTransaction()
1558 * If nsGkAtoms::blockquote,
1559 * WrapContentsInBlockquoteElementsWithTransaction()
1561 * Otherwise, CreateOrChangeBlockContainerElement()
1563 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1564 * paragraphState command.
1565 * @param aEditingHost The editing host.
1566 * @return If selection should be finally collapsed in a
1567 * created block element, this returns the element.
1569 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<RefPtr
<Element
>, nsresult
>
1570 FormatBlockContainerWithTransaction(AutoRangeArray
& aSelectionRanges
,
1571 const nsStaticAtom
& aNewFormatTagName
,
1572 FormatBlockMode aFormatBlockMode
,
1573 const Element
& aEditingHost
);
1576 * Determine if aPointToInsert is start of a hard line and end of the line
1577 * (i.e, in an empty line) and the line ends with block boundary, inserts a
1580 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
1581 InsertBRElementIfHardLineIsEmptyAndEndsWithBlockBoundary(
1582 const EditorDOMPoint
& aPointToInsert
);
1585 * Insert padding `<br>` element for empty last line into aElement if
1586 * aElement is a block element and empty.
1588 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1589 InsertPaddingBRElementForEmptyLastLineIfNeeded(Element
& aElement
);
1592 * This method inserts a padding `<br>` element for empty last line if
1593 * selection is collapsed and container of the range needs it.
1595 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1596 MaybeInsertPaddingBRElementForEmptyLastLineAtSelection();
1599 * SplitParagraphWithTransaction() splits the parent block, aParentDivOrP, at
1600 * aStartOfRightNode.
1602 * @param aParentDivOrP The parent block to be split. This must be <p>
1604 * @param aStartOfRightNode The point to be start of right node after
1605 * split. This must be descendant of
1607 * @param aMayBecomeVisibleBRElement
1608 * Next <br> element of the split point if there
1609 * is. Otherwise, nullptr. If this is not nullptr,
1610 * the <br> element may be removed if it becomes
1613 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
1614 SplitParagraphWithTransaction(Element
& aParentDivOrP
,
1615 const EditorDOMPoint
& aStartOfRightNode
,
1616 dom::HTMLBRElement
* aMayBecomeVisibleBRElement
);
1619 * HandleInsertParagraphInParagraph() does the right thing for Enter key
1620 * press or 'insertParagraph' command in aParentDivOrP. aParentDivOrP will
1621 * be split **around** aCandidatePointToSplit. If this thinks that it should
1622 * be handled to insert a <br> instead, this returns "not handled".
1624 * @param aParentDivOrP The parent block. This must be <p> or <div>
1626 * @param aCandidatePointToSplit
1627 * The point where the caller want to split
1628 * aParentDivOrP. However, in some cases, this is not
1629 * used as-is. E.g., this method avoids to create new
1630 * empty <a href> in the right paragraph. So this may
1631 * be adjusted to proper position around it.
1632 * @param aEditingHost The editing host.
1633 * @return If the caller should default to inserting <br>
1634 * element, returns "not handled".
1636 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
1637 HandleInsertParagraphInParagraph(Element
& aParentDivOrP
,
1638 const EditorDOMPoint
& aCandidatePointToSplit
,
1639 const Element
& aEditingHost
);
1642 * HandleInsertParagraphInHeadingElement() handles insertParagraph command
1643 * (i.e., handling Enter key press) in a heading element. This splits
1644 * aHeadingElement element at aPointToSplit. Then, if right heading element
1645 * is empty, it'll be removed and new paragraph is created (its type is
1646 * decided with default paragraph separator).
1648 * @param aHeadingElement The heading element to be split.
1649 * @param aPointToSplit The point to split aHeadingElement.
1650 * @return New paragraph element, meaning right heading
1651 * element if aHeadingElement is split, or newly
1652 * created or existing paragraph element.
1654 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertParagraphResult
, nsresult
>
1655 HandleInsertParagraphInHeadingElement(Element
& aHeadingElement
,
1656 const EditorDOMPoint
& aPointToSplit
);
1659 * HandleInsertParagraphInListItemElement() handles insertParagraph command
1660 * (i.e., handling Enter key press) in a list item element.
1662 * @param aListItemElement The list item which has the following point.
1663 * @param aPointToSplit The point to split aListItemElement.
1664 * @param aEditingHost The editing host.
1665 * @return New paragraph element, meaning right list item
1666 * element if aListItemElement is split, or newly
1667 * created paragraph element.
1669 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertParagraphResult
, nsresult
>
1670 HandleInsertParagraphInListItemElement(Element
& aListItemElement
,
1671 const EditorDOMPoint
& aPointToSplit
,
1672 const Element
& aEditingHost
);
1675 * InsertParagraphSeparatorAsSubAction() handles insertPargraph commad
1676 * (i.e., handling Enter key press) with the above helper methods.
1678 * @param aEditingHost The editing host.
1680 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
1681 InsertParagraphSeparatorAsSubAction(const Element
& aEditingHost
);
1684 * InsertLineBreakAsSubAction() inserts a new <br> element or a linefeed
1685 * character at selection. If there is non-collapsed selection ranges, the
1686 * selected ranges is deleted first.
1688 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertLineBreakAsSubAction();
1691 * ChangeListElementType() replaces child list items of aListElement with
1692 * new list item element whose tag name is aNewListItemTag.
1693 * Note that if there are other list elements as children of aListElement,
1694 * this calls itself recursively even though it's invalid structure.
1696 * @param aListElement The list element whose list items will be
1698 * @param aNewListTag New list tag name.
1699 * @param aNewListItemTag New list item tag name.
1700 * @return New list element or an error code if it fails.
1701 * New list element may be aListElement if its
1702 * tag name is same as aNewListTag.
1704 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1705 ChangeListElementType(Element
& aListElement
, nsAtom
& aListType
,
1708 class AutoListElementCreator
;
1710 [[nodiscard
]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode
,
1711 const nsIContent
& aContent
);
1714 * MakeOrChangeListAndListItemAsSubAction() handles create list commands with
1715 * current selection. If
1717 * @param aListElementOrListItemElementTagName
1718 * The new list element tag name or
1719 * new list item tag name.
1720 * If the former, list item tag name will
1721 * be computed automatically. Otherwise,
1722 * list tag name will be computed.
1723 * @param aBulletType If this is not empty string, it's set
1724 * to `type` attribute of new list item
1725 * elements. Otherwise, existing `type`
1726 * attributes will be removed.
1727 * @param aSelectAllOfCurrentList Yes if this should treat all of
1728 * ancestor list element at selection.
1730 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
1731 MakeOrChangeListAndListItemAsSubAction(
1732 const nsStaticAtom
& aListElementOrListItemElementTagName
,
1733 const nsAString
& aBulletType
,
1734 SelectAllOfCurrentList aSelectAllOfCurrentList
);
1737 * DeleteTextAndTextNodesWithTransaction() removes text or text nodes in
1740 enum class TreatEmptyTextNodes
{
1741 // KeepIfContainerOfRangeBoundaries:
1742 // Will remove empty text nodes middle of the range, but keep empty
1743 // text nodes which are containers of range boundaries.
1744 KeepIfContainerOfRangeBoundaries
,
1746 // Will remove all empty text nodes.
1748 // RemoveAllEmptyInlineAncestors:
1749 // Will remove all empty text nodes and its inline ancestors which
1750 // become empty due to removing empty text nodes.
1751 RemoveAllEmptyInlineAncestors
,
1753 template <typename EditorDOMPointType
>
1754 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
1755 DeleteTextAndTextNodesWithTransaction(
1756 const EditorDOMPointType
& aStartPoint
,
1757 const EditorDOMPointType
& aEndPoint
,
1758 TreatEmptyTextNodes aTreatEmptyTextNodes
);
1761 * JoinNodesWithTransaction() joins aLeftContent and aRightContent. Content
1762 * of aLeftContent will be merged into aRightContent. Actual implemenation of
1763 * this method is JoinNodesImpl(). So, see its explanation for the detail.
1765 * @param aLeftContent Will be removed from the DOM tree.
1766 * @param aRightContent The node which will be new container of the content
1769 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<JoinNodesResult
, nsresult
>
1770 JoinNodesWithTransaction(nsIContent
& aLeftContent
, nsIContent
& aRightContent
);
1773 * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
1774 * are themselves or the nearest editable node of aLeftNode and aRightNode.
1775 * XXX This method's behavior is odd. For example, if user types Backspace
1776 * key at the second editable paragraph in this case:
1777 * <div contenteditable>
1778 * <p>first editable paragraph</p>
1779 * <p contenteditable="false">non-editable paragraph</p>
1780 * <p>second editable paragraph</p>
1782 * The first editable paragraph's content will be moved into the second
1783 * editable paragraph and the non-editable paragraph becomes the first
1784 * paragraph of the editor. I don't think that it's expected behavior of
1787 * @param aLeftNode The node which will be removed.
1788 * @param aRightNode The node which will be inserted the content of
1790 * @param aNewFirstChildOfRightNode
1791 * [out] The point at the first child of aRightNode.
1793 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1794 JoinNearestEditableNodesWithTransaction(
1795 nsIContent
& aLeftNode
, nsIContent
& aRightNode
,
1796 EditorDOMPoint
* aNewFirstChildOfRightNode
);
1799 * ReplaceContainerAndCloneAttributesWithTransaction() creates new element
1800 * whose name is aTagName, copies all attributes from aOldContainer to the
1801 * new element, moves all children in aOldContainer to the new element, then,
1802 * removes aOldContainer from the DOM tree.
1804 * @param aOldContainer The element node which should be replaced
1806 * @param aTagName The name of new element node.
1808 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1809 ReplaceContainerAndCloneAttributesWithTransaction(Element
& aOldContainer
,
1810 const nsAtom
& aTagName
);
1813 * ReplaceContainerWithTransaction() creates new element whose name is
1814 * aTagName, sets aAttributes of the new element to aAttributeValue, moves
1815 * all children in aOldContainer to the new element, then, removes
1816 * aOldContainer from the DOM tree.
1818 * @param aOldContainer The element node which should be replaced
1820 * @param aTagName The name of new element node.
1821 * @param aAttribute Attribute name to be set to the new element.
1822 * @param aAttributeValue Attribute value to be set to aAttribute.
1824 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1825 ReplaceContainerWithTransaction(Element
& aOldContainer
,
1826 const nsAtom
& aTagName
,
1827 const nsAtom
& aAttribute
,
1828 const nsAString
& aAttributeValue
);
1831 * ReplaceContainerWithTransaction() creates new element whose name is
1832 * aTagName, moves all children in aOldContainer to the new element, then,
1833 * removes aOldContainer from the DOM tree.
1835 * @param aOldContainer The element node which should be replaced
1837 * @param aTagName The name of new element node.
1839 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1840 ReplaceContainerWithTransaction(Element
& aOldContainer
,
1841 const nsAtom
& aTagName
);
1844 * RemoveContainerWithTransaction() removes aElement from the DOM tree and
1845 * moves all its children to the parent of aElement.
1847 * @param aElement The element to be removed.
1848 * @return A suggestion point to put caret.
1850 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1851 RemoveContainerWithTransaction(Element
& aElement
);
1854 * InsertContainerWithTransaction() creates new element whose name is
1855 * aWrapperTagName, moves aContentToBeWrapped into the new element, then,
1856 * inserts the new element into where aContentToBeWrapped was.
1857 * NOTE: This method does not check if aContentToBeWrapped is valid child
1858 * of the new element. So, callers need to guarantee it.
1860 * @param aContentToBeWrapped The content which will be wrapped with new
1862 * @param aWrapperTagName Element name of new element which will wrap
1863 * aContent and be inserted into where aContent
1865 * @param aInitializer A callback to initialize new element before
1866 * inserting to the DOM tree.
1868 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1869 InsertContainerWithTransaction(
1870 nsIContent
& aContentToBeWrapped
, const nsAtom
& aWrapperTagName
,
1871 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1874 * MoveNodeWithTransaction() moves aContentToMove to aPointToInsert.
1876 * @param aContentToMove The node to be moved.
1877 * @param aPointToInsert The point where aContentToMove will be inserted.
1879 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
1880 MoveNodeWithTransaction(nsIContent
& aContentToMove
,
1881 const EditorDOMPoint
& aPointToInsert
);
1884 * MoveNodeToEndWithTransaction() moves aContentToMove to end of
1887 * @param aContentToMove The node to be moved.
1888 * @param aNewContainer The new container which will contain aContentToMove
1889 * as its last child.
1891 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
1892 MoveNodeToEndWithTransaction(nsIContent
& aContentToMove
,
1893 nsINode
& aNewContainer
);
1896 * MoveNodeOrChildrenWithTransaction() moves aContent to aPointToInsert. If
1897 * cannot insert aContent due to invalid relation, moves only its children
1898 * recursively and removes aContent from the DOM tree.
1900 * @param aContent Content which should be moved.
1901 * @param aPointToInsert The point to be inserted aContent or its
1903 * @param aPreserveWhiteSpaceStyle
1904 * If yes and if it's possible to keep white-space
1905 * style, this method will set `style` attribute to
1906 * moving node or creating new <span> element.
1907 * @param aRemoveIfCommentNode
1908 * If yes, this removes a comment node instead of
1909 * moving it to the destination. Note that this
1910 * does not remove comment nodes in moving nodes
1911 * because it requires additional scan.
1913 enum class PreserveWhiteSpaceStyle
{ No
, Yes
};
1914 friend std::ostream
& operator<<(
1915 std::ostream
& aStream
,
1916 const PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle
);
1917 enum class RemoveIfCommentNode
{ No
, Yes
};
1918 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
1919 MoveNodeOrChildrenWithTransaction(
1920 nsIContent
& aContentToMove
, const EditorDOMPoint
& aPointToInsert
,
1921 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle
,
1922 RemoveIfCommentNode aRemoveIfCommentNode
);
1925 * CanMoveNodeOrChildren() returns true if
1926 * `MoveNodeOrChildrenWithTransaction()` can move or delete at least a
1927 * descendant of aElement into aNewContainer. I.e., when this returns true,
1928 * `MoveNodeOrChildrenWithTransaction()` must return "handled".
1930 Result
<bool, nsresult
> CanMoveNodeOrChildren(
1931 const nsIContent
& aContent
, const nsINode
& aNewContainer
) const;
1934 * MoveChildrenWithTransaction() moves the children of aElement to
1935 * aPointToInsert. If cannot insert some children due to invalid relation,
1936 * calls MoveNodeOrChildrenWithTransaction() to remove the children but keep
1937 * moving its children.
1939 * @param aElement Container element whose children should be
1941 * @param aPointToInsert The point to be inserted children of aElement
1942 * or its descendants.
1943 * @param aPreserveWhiteSpaceStyle
1944 * If yes and if it's possible to keep white-space
1945 * style, this method will set `style` attribute to
1946 * moving node or creating new <span> element.
1947 * @param aRemoveIfCommentNode
1948 * If yes, this removes a comment node instead of
1949 * moving it to the destination. Note that this
1950 * does not remove comment nodes in moving nodes
1951 * because it requires additional scan.
1953 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
1954 MoveChildrenWithTransaction(Element
& aElement
,
1955 const EditorDOMPoint
& aPointToInsert
,
1956 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle
,
1957 RemoveIfCommentNode aRemoveIfCommentNode
);
1960 * CanMoveChildren() returns true if `MoveChildrenWithTransaction()` can move
1961 * at least a descendant of aElement into aNewContainer. I.e., when this
1962 * returns true, `MoveChildrenWithTransaction()` return "handled".
1964 Result
<bool, nsresult
> CanMoveChildren(const Element
& aElement
,
1965 const nsINode
& aNewContainer
) const;
1968 * MoveAllChildren() moves all children of aContainer to before
1969 * aPointToInsert.GetChild().
1970 * See explanation of MoveChildrenBetween() for the detail of the behavior.
1972 * @param aContainer The container node whose all children should
1974 * @param aPointToInsert The insertion point. The container must not
1975 * be a data node like a text node.
1977 [[nodiscard
]] nsresult
MoveAllChildren(
1978 nsINode
& aContainer
, const EditorRawDOMPoint
& aPointToInsert
);
1981 * MoveChildrenBetween() moves all children between aFirstChild and aLastChild
1982 * to before aPointToInsert.GetChild(). If some children are moved to
1983 * different container while this method moves other children, they are just
1984 * ignored. If the child node referred by aPointToInsert is moved to different
1985 * container while this method moves children, returns error.
1987 * @param aFirstChild The first child which should be moved to
1989 * @param aLastChild The last child which should be moved. This
1990 * must be a sibling of aFirstChild and it should
1991 * be positioned after aFirstChild in the DOM tree
1993 * @param aPointToInsert The insertion point. The container must not
1994 * be a data node like a text node.
1996 [[nodiscard
]] nsresult
MoveChildrenBetween(
1997 nsIContent
& aFirstChild
, nsIContent
& aLastChild
,
1998 const EditorRawDOMPoint
& aPointToInsert
);
2001 * MovePreviousSiblings() moves all siblings before aChild (i.e., aChild
2002 * won't be moved) to before aPointToInsert.GetChild().
2003 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2005 * @param aChild The node which is next sibling of the last
2007 * @param aPointToInsert The insertion point. The container must not
2008 * be a data node like a text node.
2010 [[nodiscard
]] nsresult
MovePreviousSiblings(
2011 nsIContent
& aChild
, const EditorRawDOMPoint
& aPointToInsert
);
2014 * MoveInclusiveNextSiblings() moves aChild and all siblings after it to
2015 * before aPointToInsert.GetChild().
2016 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2018 * @param aChild The node which is first node to be moved.
2019 * @param aPointToInsert The insertion point. The container must not
2020 * be a data node like a text node.
2022 [[nodiscard
]] nsresult
MoveInclusiveNextSiblings(
2023 nsIContent
& aChild
, const EditorRawDOMPoint
& aPointToInsert
);
2026 * SplitNodeWithTransaction() creates a transaction to create a new node
2027 * (left node) identical to an existing node (right node), and split the
2028 * contents between the same point in both nodes, then, execute the
2031 * @param aStartOfRightNode The point to split. Its container will be
2032 * the right node, i.e., become the new node's
2033 * next sibling. And the point will be start
2034 * of the right node.
2036 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
2037 SplitNodeWithTransaction(const EditorDOMPoint
& aStartOfRightNode
);
2040 * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
2042 * @param aMostAncestorToSplit The most ancestor node which should be
2044 * @param aStartOfDeepestRightNode The start point of deepest right node.
2045 * This point must be descendant of
2046 * aMostAncestorToSplit.
2047 * @param aSplitAtEdges Whether the caller allows this to
2048 * create empty container element when
2049 * split point is start or end of an
2051 * @return SplitPoint() returns split point in
2052 * aMostAncestorToSplit. The point must
2053 * be good to insert something if the
2054 * caller want to do it.
2056 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
2057 SplitNodeDeepWithTransaction(nsIContent
& aMostAncestorToSplit
,
2058 const EditorDOMPoint
& aDeepestStartOfRightNode
,
2059 SplitAtEdges aSplitAtEdges
);
2062 * RemoveEmptyInclusiveAncestorInlineElements() removes empty inclusive
2063 * ancestor inline elements in inclusive ancestor block element of aContent.
2065 * @param aContent Must be an empty content.
2067 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2068 RemoveEmptyInclusiveAncestorInlineElements(nsIContent
& aContent
);
2071 * DeleteTextAndNormalizeSurroundingWhiteSpaces() deletes text between
2072 * aStartToDelete and immediately before aEndToDelete and return new caret
2073 * position. If surrounding characters are white-spaces, this normalize them
2074 * too. Finally, inserts `<br>` element if it's required.
2075 * Note that if you wants only normalizing white-spaces, you can set same
2076 * point to both aStartToDelete and aEndToDelete. Then, this tries to
2077 * normalize white-space sequence containing previous character of
2080 enum class DeleteDirection
{
2084 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
2085 DeleteTextAndNormalizeSurroundingWhiteSpaces(
2086 const EditorDOMPointInText
& aStartToDelete
,
2087 const EditorDOMPointInText
& aEndToDelete
,
2088 TreatEmptyTextNodes aTreatEmptyTextNodes
,
2089 DeleteDirection aDeleteDirection
);
2092 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() is a helper method of
2093 * DeleteTextAndNormalizeSurroundingWhiteSpaces(). This expands
2094 * aStartToDelete and/or aEndToDelete if there are white-spaces which need
2097 * @param aStartToDelete [In/Out] Start to delete. If this point
2098 * follows white-spaces, this may be modified.
2099 * @param aEndToDelete [In/Out] Next point of last content to be
2100 * deleted. If this point is a white-space,
2101 * this may be modified.
2102 * @param aNormalizedWhiteSpacesInStartNode
2103 * [Out] If container text node of aStartToDelete
2104 * should be modified, this offers new string
2105 * in the range in the text node.
2106 * @param aNormalizedWhiteSpacesInEndNode
2107 * [Out] If container text node of aEndToDelete
2108 * is different from the container of
2109 * aStartToDelete and it should be modified, this
2110 * offers new string in the range in the text node.
2112 void ExtendRangeToDeleteWithNormalizingWhiteSpaces(
2113 EditorDOMPointInText
& aStartToDelete
, EditorDOMPointInText
& aEndToDelete
,
2114 nsAString
& aNormalizedWhiteSpacesInStartNode
,
2115 nsAString
& aNormalizedWhiteSpacesInEndNode
) const;
2118 * CharPointType let the following helper methods of
2119 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2120 * character will be previous or next char point after deletion.
2122 enum class CharPointType
{
2123 TextEnd
, // Start or end of the text (hardline break or replaced inline
2125 ASCIIWhiteSpace
, // One of ASCII white-spaces (collapsible white-space)
2126 NoBreakingSpace
, // NBSP
2127 VisibleChar
, // Non-white-space characters
2128 PreformattedChar
, // Any character except a linefeed in a preformatted
2130 PreformattedLineBreak
, // Preformatted linebreak
2134 * GetPreviousCharPointType() and GetCharPointType() get type of
2135 * previous/current char point from current DOM tree. In other words, if the
2136 * point will be deleted, you cannot use these methods.
2138 template <typename EditorDOMPointType
>
2139 static CharPointType
GetPreviousCharPointType(
2140 const EditorDOMPointType
& aPoint
);
2141 template <typename EditorDOMPointType
>
2142 static CharPointType
GetCharPointType(const EditorDOMPointType
& aPoint
);
2145 * CharPointData let the following helper methods of
2146 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2147 * character will be previous or next char point and the point is
2148 * in same or different text node after deletion.
2150 class MOZ_STACK_CLASS CharPointData final
{
2152 static CharPointData
InDifferentTextNode(CharPointType aCharPointType
) {
2153 CharPointData result
;
2154 result
.mIsInDifferentTextNode
= true;
2155 result
.mType
= aCharPointType
;
2158 static CharPointData
InSameTextNode(CharPointType aCharPointType
) {
2159 CharPointData result
;
2160 // Let's mark this as in different text node if given one indicates
2161 // that there is end of text because it means that adjacent content
2162 // from point of text node view is another element.
2163 result
.mIsInDifferentTextNode
= aCharPointType
== CharPointType::TextEnd
;
2164 result
.mType
= aCharPointType
;
2168 bool AcrossTextNodeBoundary() const { return mIsInDifferentTextNode
; }
2169 bool IsCollapsibleWhiteSpace() const {
2170 return mType
== CharPointType::ASCIIWhiteSpace
||
2171 mType
== CharPointType::NoBreakingSpace
;
2173 CharPointType
Type() const { return mType
; }
2176 CharPointData() = default;
2178 CharPointType mType
;
2179 bool mIsInDifferentTextNode
;
2183 * GetPreviousCharPointDataForNormalizingWhiteSpaces() and
2184 * GetInclusiveNextCharPointDataForNormalizingWhiteSpaces() is helper methods
2185 * of ExtendRangeToDeleteWithNormalizingWhiteSpaces(). This retrieves
2186 * previous or inclusive next editable char point and returns its data.
2188 CharPointData
GetPreviousCharPointDataForNormalizingWhiteSpaces(
2189 const EditorDOMPointInText
& aPoint
) const;
2190 CharPointData
GetInclusiveNextCharPointDataForNormalizingWhiteSpaces(
2191 const EditorDOMPointInText
& aPoint
) const;
2194 * GenerateWhiteSpaceSequence() generates white-space sequence which won't
2197 * @param aResult [out] White space sequence which won't be
2198 * collapsed, but wrapable.
2199 * @param aLength Length of generating white-space sequence.
2200 * Must be 1 or larger.
2201 * @param aPreviousCharPointData
2202 * Specify the previous char point where it'll be
2203 * inserted. Currently, for keepin this method
2204 * simple, does not support to generate a part
2205 * of white-space sequence in a text node. So,
2206 * if the type is white-space, it must indicate
2207 * different text nodes white-space.
2208 * @param aNextCharPointData Specify the next char point where it'll be
2209 * inserted. Same as aPreviousCharPointData,
2210 * this must node indidate white-space in same
2213 static void GenerateWhiteSpaceSequence(
2214 nsAString
& aResult
, uint32_t aLength
,
2215 const CharPointData
& aPreviousCharPointData
,
2216 const CharPointData
& aNextCharPointData
);
2219 * ComputeTargetRanges() computes actual delete ranges which will be deleted
2220 * unless the following `beforeinput` event is canceled.
2222 * @param aDirectionAndAmount The direction and amount of deletion.
2223 * @param aRangesToDelete [In/Out] The ranges to be deleted,
2224 * typically, initialized with the
2225 * selection ranges. This may be modified
2226 * if selection ranges should be extened.
2228 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2229 ComputeTargetRanges(nsIEditor::EDirection aDirectionAndAmount
,
2230 AutoRangeArray
& aRangesToDelete
) const;
2233 * This method handles "delete selection" commands.
2235 * @param aDirectionAndAmount Direction of the deletion.
2236 * @param aStripWrappers Must be eStrip or eNoStrip.
2238 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2239 HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount
,
2240 nsIEditor::EStripWrappers aStripWrappers
) final
;
2242 class AutoDeleteRangesHandler
;
2243 class AutoMoveOneLineHandler
;
2246 * DeleteMostAncestorMailCiteElementIfEmpty() deletes most ancestor
2247 * mail cite element (`<blockquote type="cite">` or
2248 * `<span _moz_quote="true">`, the former can be created with middle click
2249 * paste with `Control` or `Command` even in the web) of aContent if it
2252 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2253 DeleteMostAncestorMailCiteElementIfEmpty(nsIContent
& aContent
);
2256 * LiftUpListItemElement() moves aListItemElement outside its parent.
2257 * If it's in a middle of a list element, the parent list element is split
2258 * before aListItemElement. Then, moves aListItemElement to before its
2259 * parent list element. I.e., moves aListItemElement between the 2 list
2260 * elements if original parent was split. Then, if new parent becomes not a
2261 * list element, the list item element is removed and its contents are moved
2262 * to where the list item element was. If aListItemElement becomse not a
2263 * child of list element, its contents are unwrapped from aListItemElement.
2265 * @param aListItemElement Must be a <li>, <dt> or <dd> element.
2266 * @param aLiftUpFromAllParentListElements
2267 * If Yes, this method calls itself recursively
2268 * to unwrap the contents in aListItemElement
2269 * from any ancestor list elements.
2270 * XXX This checks only direct parent of list
2271 * elements. Therefore, if a parent list
2272 * element in a list item element, the
2273 * list item element and its list element
2274 * won't be unwrapped.
2276 enum class LiftUpFromAllParentListElements
{ Yes
, No
};
2277 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
LiftUpListItemElement(
2278 dom::Element
& aListItemElement
,
2279 LiftUpFromAllParentListElements aLiftUpFromAllParentListElements
);
2282 * DestroyListStructureRecursively() destroys the list structure of
2283 * aListElement recursively.
2284 * If aListElement has <li>, <dl> or <dt> as a child, the element is removed
2285 * but its descendants are moved to where the list item element was.
2286 * If aListElement has another <ul>, <ol> or <dl> as a child, this method is
2287 * called recursively.
2288 * If aListElement has other nodes as its child, they are just removed.
2289 * Finally, aListElement is removed. and its all children are moved to
2290 * where the aListElement was.
2292 * @param aListElement A <ul>, <ol> or <dl> element.
2294 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2295 DestroyListStructureRecursively(Element
& aListElement
);
2298 * RemoveListAtSelectionAsSubAction() removes list elements and list item
2299 * elements at Selection. And move contents in them where the removed list
2302 * @param aEditingHost The editing host.
2304 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2305 RemoveListAtSelectionAsSubAction(const Element
& aEditingHost
);
2308 * ChangeMarginStart() changes margin of aElement to indent or outdent.
2309 * If it's rtl text, margin-right will be changed. Otherwise, margin-left.
2310 * XXX This is not aware of vertical writing-mode.
2312 * @param aElement The element whose start margin should be
2314 * @param aChangeMargin Whether increase or decrease the margin.
2315 * @param aEditingHost The editing host.
2316 * @return May suggest a suggest point to put caret.
2318 enum class ChangeMargin
{ Increase
, Decrease
};
2319 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2320 ChangeMarginStart(Element
& aElement
, ChangeMargin aChangeMargin
,
2321 const Element
& aEditingHost
);
2324 * HandleCSSIndentAroundRanges() indents around aRanges with CSS.
2326 * @param aRanges The ranges where the content should be indented.
2327 * @param aEditingHost The editing host.
2329 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
HandleCSSIndentAroundRanges(
2330 AutoRangeArray
& aRanges
, const Element
& aEditingHost
);
2333 * HandleCSSIndentAroundRanges() indents around aRanges with HTML.
2335 * @param aRanges The ranges where the content should be indented.
2336 * @param aEditingHost The editing host.
2338 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
HandleHTMLIndentAroundRanges(
2339 AutoRangeArray
& aRanges
, const Element
& aEditingHost
);
2342 * HandleIndentAtSelection() indents around Selection with HTML or CSS.
2344 * @param aEditingHost The editing host.
2346 // TODO: Make this take AutoRangeArray instead of retrieving `Selection`
2347 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2348 HandleIndentAtSelection(const Element
& aEditingHost
);
2351 * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and
2352 * aEndOfOutdent. This splits the range off from aBlockElement first.
2353 * Then, removes the middle element if aIsBlockIndentedWithCSS is false.
2354 * Otherwise, decreases the margin of the middle element.
2356 * @param aBlockElement A block element which includes both
2357 * aStartOfOutdent and aEndOfOutdent.
2358 * @param aStartOfOutdent First node which is descendant of
2359 * aBlockElement will be outdented.
2360 * @param aEndOfOutdent Last node which is descandant of
2361 * aBlockElement will be outdented.
2362 * @param aBlockIndentedWith `CSS` if aBlockElement is indented with
2363 * CSS margin property.
2364 * `HTML` if aBlockElement is `<blockquote>`
2366 * @param aEditingHost The editing host.
2367 * @return The left content is new created element
2368 * splitting before aStartOfOutdent.
2369 * The right content is existing element.
2370 * The middle content is outdented element
2371 * if aBlockIndentedWith is `CSS`.
2372 * Otherwise, nullptr.
2374 enum class BlockIndentedWith
{ CSS
, HTML
};
2375 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
2376 OutdentPartOfBlock(Element
& aBlockElement
, nsIContent
& aStartOfOutdent
,
2377 nsIContent
& aEndOfOutdent
,
2378 BlockIndentedWith aBlockIndentedWith
,
2379 const Element
& aEditingHost
);
2382 * HandleOutdentAtSelectionInternal() outdents contents around Selection.
2383 * This method creates AutoSelectionRestorer. Therefore, each caller
2384 * needs to check if the editor is still available even if this returns
2386 * NOTE: Call `HandleOutdentAtSelection()` instead.
2388 * @param aEditingHost The editing host.
2389 * @return The left content is left content of last
2390 * outdented element.
2391 * The right content is right content of last
2392 * outdented element.
2393 * The middle content is middle content of last
2394 * outdented element.
2396 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
2397 HandleOutdentAtSelectionInternal(const Element
& aEditingHost
);
2400 * HandleOutdentAtSelection() outdents contents around Selection.
2402 * @param aEditingHost The editing host.
2404 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2405 HandleOutdentAtSelection(const Element
& aEditingHost
);
2408 * AlignBlockContentsWithDivElement() sets align attribute of <div> element
2409 * which is only child of aBlockElement to aAlignType. If aBlockElement
2410 * has 2 or more children or does not have a `<div>` element, inserts a
2411 * new `<div>` element into aBlockElement and move all children of
2412 * aBlockElement into the new `<div>` element.
2414 * @param aBlockElement The element node whose contents should be
2415 * aligned to aAlignType. This should be
2416 * an element which can have `<div>` element
2418 * @param aAlignType New value of align attribute of `<div>`
2420 * @return A candidate position to put caret.
2422 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2423 AlignBlockContentsWithDivElement(Element
& aBlockElement
,
2424 const nsAString
& aAlignType
);
2427 * AlignContentsInAllTableCellsAndListItems() calls
2428 * AlignBlockContentsWithDivElement() for aligning contents in every list
2429 * item element and table cell element in aElement.
2431 * @param aElement The node which is or whose descendants should
2432 * be aligned to aAlignType.
2433 * @param aAlignType New value of `align` attribute of `<div>`.
2434 * @return A candidate position to put caret.
2436 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2437 AlignContentsInAllTableCellsAndListItems(dom::Element
& aElement
,
2438 const nsAString
& aAlignType
);
2441 * MakeTransitionList() detects all the transitions in the array, where a
2442 * transition means that adjacent nodes in the array don't have the same
2445 static void MakeTransitionList(
2446 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
2447 nsTArray
<bool>& aTransitionArray
);
2450 * EnsureHardLineBeginsWithFirstChildOf() inserts `<br>` element before
2451 * first child of aRemovingContainerElement if it will not be start of a
2452 * hard line after removing aRemovingContainerElement.
2454 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2455 EnsureHardLineBeginsWithFirstChildOf(Element
& aRemovingContainerElement
);
2458 * EnsureHardLineEndsWithLastChildOf() inserts `<br>` element after last
2459 * child of aRemovingContainerElement if it will not be end of a hard line
2460 * after removing aRemovingContainerElement.
2462 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2463 EnsureHardLineEndsWithLastChildOf(Element
& aRemovingContainerElement
);
2466 * RemoveAlignFromDescendants() removes align attributes, text-align
2467 * properties and <center> elements in aElement.
2469 * @param aElement Alignment information of the node and/or its
2470 * descendants will be removed.
2471 * NOTE: aElement must not be a `<table>` element.
2472 * @param aAlignType New align value to be set only when it's in
2473 * CSS mode and this method meets <table> or <hr>.
2474 * XXX This is odd and not clear when you see caller of
2475 * this method. Do you have better idea?
2476 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2477 * descendants of aElement.
2478 * If `NodeAndDescendantsExceptTable`, modifies `aElement`
2479 * and its descendants.
2480 * @return A candidate point to put caret.
2482 enum class EditTarget
{
2483 OnlyDescendantsExceptTable
,
2484 NodeAndDescendantsExceptTable
2486 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2487 RemoveAlignFromDescendants(Element
& aElement
, const nsAString
& aAlignType
,
2488 EditTarget aEditTarget
);
2491 * SetBlockElementAlign() resets `align` attribute, `text-align` property
2492 * of descendants of aBlockOrHRElement except `<table>` element descendants.
2493 * Then, set `align` attribute or `text-align` property of aBlockOrHRElement.
2495 * @param aBlockOrHRElement The element whose contents will be aligned.
2496 * This must be a block element or `<hr>` element.
2497 * If we're not in CSS mode, this element has
2498 * to support `align` attribute (i.e.,
2499 * `HTMLEditUtils::SupportsAlignAttr()` must
2501 * @param aAlignType Boundary or "center" which contents should be
2503 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2504 * descendants of aBlockOrHRElement.
2505 * If `NodeAndDescendantsExceptTable`, modifies
2506 * aBlockOrHRElement and its descendants.
2507 * @return A candidate point to put caret.
2509 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2510 SetBlockElementAlign(Element
& aBlockOrHRElement
, const nsAString
& aAlignType
,
2511 EditTarget aEditTarget
);
2514 * InsertDivElementToAlignContents() inserts a new <div> element (which has
2515 * only a padding <br> element) to aPointToInsert for a placeholder whose
2516 * contents will be aligned.
2518 * @param aPointToInsert A point to insert new empty <div>.
2519 * @param aAlignType New align attribute value where the contents
2520 * should be aligned to.
2521 * @param aEditingHost The editing host.
2522 * @return New <div> element which has only a padding <br>
2523 * element and is styled to align contents.
2525 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2526 InsertDivElementToAlignContents(const EditorDOMPoint
& aPointToInsert
,
2527 const nsAString
& aAlignType
,
2528 const Element
& aEditingHost
);
2531 * AlignNodesAndDescendants() make contents of nodes in aArrayOfContents and
2532 * their descendants aligned to aAlignType.
2534 * @param aAlignType New align attribute value where the contents
2535 * should be aligned to.
2536 * @param aEditingHost The editing host.
2537 * @return Last created <div> element which should contain
2538 * caret and candidate position which may be
2539 * outside the <div> element.
2541 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2542 AlignNodesAndDescendants(
2543 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
2544 const nsAString
& aAlignType
, const Element
& aEditingHost
);
2547 * AlignContentsAtRanges() aligns contents around aRanges to aAlignType.
2549 * @param aRanges The ranges where should be aligned.
2550 * @param aAlignType New align attribute value where the contents
2551 * should be aligned to.
2552 * @param aEditingHost The editing host.
2554 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2555 AlignContentsAtRanges(AutoRangeArray
& aRanges
, const nsAString
& aAlignType
,
2556 const Element
& aEditingHost
);
2559 * AlignAsSubAction() handles "align" command with `Selection`.
2561 * @param aAlignType New align attribute value where the contents
2562 * should be aligned to.
2563 * @param aEditingHost The editing host.
2565 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2566 AlignAsSubAction(const nsAString
& aAlignType
, const Element
& aEditingHost
);
2569 * AdjustCaretPositionAndEnsurePaddingBRElement() may adjust caret
2570 * position to nearest editable content and if padding `<br>` element is
2571 * necessary at caret position, this creates it.
2573 * @param aDirectionAndAmount Direction of the edit action.
2575 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2576 AdjustCaretPositionAndEnsurePaddingBRElement(
2577 nsIEditor::EDirection aDirectionAndAmount
);
2580 * EnsureSelectionInBodyOrDocumentElement() collapse `Selection` to the
2581 * primary `<body>` element or document element when `Selection` crosses
2582 * `<body>` element's boundary.
2584 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2585 EnsureSelectionInBodyOrDocumentElement();
2588 * InsertBRElementToEmptyListItemsAndTableCellsInRange() inserts
2589 * `<br>` element into empty list item or table cell elements between
2590 * aStartRef and aEndRef.
2592 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2593 InsertBRElementToEmptyListItemsAndTableCellsInRange(
2594 const RawRangeBoundary
& aStartRef
, const RawRangeBoundary
& aEndRef
);
2597 * RemoveEmptyNodesIn() removes all empty nodes in aRange. However, if
2598 * mail-cite node has only a `<br>` element, the node will be removed
2599 * but <br> element is moved to where the mail-cite node was.
2600 * XXX This method is expensive if aRange is too wide and may remove
2601 * unexpected empty element, e.g., it was created by JS, but we haven't
2602 * touched it. Cannot we remove this method and make guarantee that
2603 * empty nodes won't be created?
2605 * @param aRange Must be positioned.
2607 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2608 RemoveEmptyNodesIn(const EditorDOMRange
& aRange
);
2611 * SetSelectionInterlinePosition() may set interline position if caret is
2612 * positioned around `<br>` or block boundary. Don't call this when
2613 * `Selection` is not collapsed.
2615 void SetSelectionInterlinePosition();
2618 * Called by `HTMLEditor::OnEndHandlingTopLevelEditSubAction()`. This may
2619 * adjust Selection, remove unnecessary empty nodes, create `<br>` elements
2622 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2623 OnEndHandlingTopLevelEditSubActionInternal();
2626 * MoveSelectedContentsToDivElementToMakeItAbsolutePosition() looks for
2627 * a `<div>` element in selection first. If not, creates new `<div>`
2628 * element. Then, move all selected contents into the target `<div>`
2630 * Note that this creates AutoSelectionRestorer. Therefore, callers need
2631 * to check whether we have been destroyed even when this returns NS_OK.
2633 * @param aTargetElement Returns target `<div>` element which should be
2634 * changed to absolute positioned.
2635 * @param aEditingHost The editing host.
2637 // TODO: Rewrite this with `Result<RefPtr<Element>, nsresult>`.
2638 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2639 MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
2640 RefPtr
<Element
>* aTargetElement
, const Element
& aEditingHost
);
2643 * SetSelectionToAbsoluteAsSubAction() move selected contents to first
2644 * selected `<div>` element or newly created `<div>` element and make
2645 * the `<div>` element positioned absolutely.
2647 * @param aEditingHost The editing host.
2649 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2650 SetSelectionToAbsoluteAsSubAction(const Element
& aEditingHost
);
2653 * SetSelectionToStaticAsSubAction() sets the `position` property of a
2654 * selection parent's block whose `position` is `absolute` to `static`.
2656 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2657 SetSelectionToStaticAsSubAction();
2660 * AddZIndexAsSubAction() adds aChange to `z-index` of nearest parent
2661 * absolute-positioned element from current selection.
2663 * @param aChange Amount to change `z-index`.
2665 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2666 AddZIndexAsSubAction(int32_t aChange
);
2669 * OnDocumentModified() is called when editor content is changed.
2671 MOZ_CAN_RUN_SCRIPT nsresult
OnDocumentModified();
2673 protected: // Called by helper classes.
2674 MOZ_CAN_RUN_SCRIPT
void OnStartToHandleTopLevelEditSubAction(
2675 EditSubAction aTopLevelEditSubAction
,
2676 nsIEditor::EDirection aDirectionOfTopLevelEditSubAction
,
2677 ErrorResult
& aRv
) final
;
2678 MOZ_CAN_RUN_SCRIPT nsresult
OnEndHandlingTopLevelEditSubAction() final
;
2680 protected: // Shouldn't be used by friend classes
2681 virtual ~HTMLEditor();
2684 * InitEditorContentAndSelection() may insert `<br>` elements and padding
2685 * `<br>` elements if they are required for `<body>` or document element.
2686 * And collapse selection at the end if there is no selection ranges.
2688 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InitEditorContentAndSelection();
2691 * Collapse `Selection` to the last leaf content of the <body> or the document
2694 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2695 CollapseSelectionToEndOfLastLeafNodeOfDocument() const;
2697 MOZ_CAN_RUN_SCRIPT nsresult
SelectAllInternal() final
;
2699 [[nodiscard
]] Element
* ComputeEditingHostInternal(
2700 const nsIContent
* aContent
, LimitInBodyElement aLimitInBodyElement
) const;
2703 * Creates a range with just the supplied node and appends that to the
2706 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2707 AppendContentToSelectionAsRange(nsIContent
& aContent
);
2710 * When you are using AppendContentToSelectionAsRange(), call this first to
2711 * start a new selection.
2713 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
ClearSelection();
2716 * SelectContentInternal() sets Selection to aContentToSelect to
2717 * aContentToSelect + 1 in parent of aContentToSelect.
2719 * @param aContentToSelect The content which should be selected.
2721 MOZ_CAN_RUN_SCRIPT nsresult
2722 SelectContentInternal(nsIContent
& aContentToSelect
);
2725 * GetInclusiveAncestorByTagNameAtSelection() looks for an element node whose
2726 * name matches aTagName from anchor node of Selection to <body> element.
2728 * @param aTagName The tag name which you want to look for.
2729 * Must not be nsGkAtoms::_empty.
2730 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2732 * If nsGkAtoms::td, the result may be <td> or <th>.
2733 * If nsGkAtoms::href, the result may be <a> element
2734 * which has "href" attribute with non-empty value.
2735 * If nsGkAtoms::anchor, the result may be <a> which
2736 * has "name" attribute with non-empty value.
2737 * @return If an element which matches aTagName, returns
2738 * an Element. Otherwise, nullptr.
2740 Element
* GetInclusiveAncestorByTagNameAtSelection(
2741 const nsStaticAtom
& aTagName
) const;
2744 * GetInclusiveAncestorByTagNameInternal() looks for an element node whose
2745 * name matches aTagName from aNode to <body> element.
2747 * @param aTagName The tag name which you want to look for.
2748 * Must not be nsGkAtoms::_empty.
2749 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2751 * If nsGkAtoms::td, the result may be <td> or <th>.
2752 * If nsGkAtoms::href, the result may be <a> element
2753 * which has "href" attribute with non-empty value.
2754 * If nsGkAtoms::anchor, the result may be <a> which
2755 * has "name" attribute with non-empty value.
2756 * @param aContent Start node to look for the element. This should
2757 * not be an orphan node.
2758 * @return If an element which matches aTagName, returns
2759 * an Element. Otherwise, nullptr.
2761 Element
* GetInclusiveAncestorByTagNameInternal(
2762 const nsStaticAtom
& aTagName
, const nsIContent
& aContent
) const;
2765 * GetSelectedElement() returns a "selected" element node. "selected" means:
2766 * - there is only one selection range
2767 * - the range starts from an element node or in an element
2768 * - the range ends at immediately after same element
2769 * - and the range does not include any other element nodes.
2770 * Additionally, only when aTagName is nsGkAtoms::href, this thinks that an
2771 * <a> element which has non-empty "href" attribute includes the range, the
2772 * <a> element is selected.
2774 * NOTE: This method is implementation of nsIHTMLEditor.getSelectedElement()
2775 * and comm-central depends on this behavior. Therefore, if you need to use
2776 * this method internally but you need to change, perhaps, you should create
2777 * another method for avoiding breakage of comm-central apps.
2779 * @param aTagName The atom of tag name in lower case. Set this to
2780 * result of EditorUtils::GetTagNameAtom() if you have a
2781 * tag name with nsString.
2782 * If nullptr, this returns any element node or nullptr.
2783 * If nsGkAtoms::href, this returns an <a> element which
2784 * has non-empty "href" attribute or nullptr.
2785 * If nsGkAtoms::anchor, this returns an <a> element which
2786 * has non-empty "name" attribute or nullptr.
2787 * Otherwise, returns an element node whose name is
2788 * same as aTagName or nullptr.
2789 * @param aRv Returns error code.
2790 * @return A "selected" element.
2792 already_AddRefed
<Element
> GetSelectedElement(const nsAtom
* aTagName
,
2796 * GetFirstTableRowElement() returns the first <tr> element in the most
2797 * nearest ancestor of aTableOrElementInTable or itself.
2798 * When aTableOrElementInTable is neither <table> nor in a <table> element,
2799 * returns NS_ERROR_FAILURE. However, if <table> does not have <tr> element,
2802 * @param aTableOrElementInTable <table> element or another element.
2803 * If this is a <table> element, returns
2804 * first <tr> element in it. Otherwise,
2805 * returns first <tr> element in nearest
2806 * ancestor <table> element.
2808 Result
<RefPtr
<Element
>, nsresult
> GetFirstTableRowElement(
2809 const Element
& aTableOrElementInTable
) const;
2812 * GetNextTableRowElement() returns next <tr> element of aTableRowElement.
2813 * This won't cross <table> element boundary but may cross table section
2814 * elements like <tbody>.
2815 * Note that if given element is <tr> but there is no next <tr> element, this
2816 * returns nullptr but does not return error.
2818 * @param aTableRowElement A <tr> element.
2820 Result
<RefPtr
<Element
>, nsresult
> GetNextTableRowElement(
2821 const Element
& aTableRowElement
) const;
2826 * CellIndexes store both row index and column index of a table cell.
2828 struct MOZ_STACK_CLASS CellIndexes final
{
2833 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2836 * @param aCellElement An <td> or <th> element.
2838 MOZ_CAN_RUN_SCRIPT
CellIndexes(Element
& aCellElement
, PresShell
* aPresShell
)
2839 : mRow(-1), mColumn(-1) {
2840 Update(aCellElement
, aPresShell
);
2844 * Update mRowIndex and mColumnIndex with indexes of aCellElement.
2848 MOZ_CAN_RUN_SCRIPT
void Update(Element
& aCellElement
,
2849 PresShell
* aPresShell
);
2852 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2853 * cell element which contains anchor of Selection.
2855 * @param aHTMLEditor The editor which creates the instance.
2856 * @param aSelection The Selection for the editor.
2858 MOZ_CAN_RUN_SCRIPT
CellIndexes(HTMLEditor
& aHTMLEditor
,
2859 Selection
& aSelection
)
2860 : mRow(-1), mColumn(-1) {
2861 Update(aHTMLEditor
, aSelection
);
2865 * Update mRowIndex and mColumnIndex with indexes of cell element which
2866 * contains anchor of Selection.
2870 MOZ_CAN_RUN_SCRIPT
void Update(HTMLEditor
& aHTMLEditor
,
2871 Selection
& aSelection
);
2873 bool operator==(const CellIndexes
& aOther
) const {
2874 return mRow
== aOther
.mRow
&& mColumn
== aOther
.mColumn
;
2876 bool operator!=(const CellIndexes
& aOther
) const {
2877 return mRow
!= aOther
.mRow
|| mColumn
!= aOther
.mColumn
;
2880 [[nodiscard
]] bool isErr() const { return mRow
< 0 || mColumn
< 0; }
2883 CellIndexes() : mRow(-1), mColumn(-1) {}
2884 CellIndexes(int32_t aRowIndex
, int32_t aColumnIndex
)
2885 : mRow(aRowIndex
), mColumn(aColumnIndex
) {}
2887 friend struct CellData
;
2890 struct MOZ_STACK_CLASS CellData final
{
2891 MOZ_KNOWN_LIVE RefPtr
<Element
> mElement
;
2892 // Current indexes which this is initialized with.
2893 CellIndexes mCurrent
;
2894 // First column/row indexes of the cell. When current position is spanned
2895 // from other column/row, this value becomes different from mCurrent.
2897 // Computed rowspan/colspan values which are specified to the cell.
2898 // Note that if the cell has larger rowspan/colspan value than actual
2899 // table size, these values are the larger values.
2900 int32_t mRowSpan
= -1;
2901 int32_t mColSpan
= -1;
2902 // Effective rowspan/colspan value at the index. For example, if first
2903 // cell element in first row has rowspan="3", then, if this is initialized
2904 // with 0-0 indexes, effective rowspan is 3. However, if this is
2905 // initialized with 1-0 indexes, effective rowspan is 2.
2906 int32_t mEffectiveRowSpan
= -1;
2907 int32_t mEffectiveColSpan
= -1;
2908 // mIsSelected is set to true if mElement itself or its parent <tr> or
2909 // <table> is selected. Otherwise, e.g., the cell just contains selection
2910 // range, this is set to false.
2911 bool mIsSelected
= false;
2913 CellData() = delete;
2916 * This returns an instance which is initialized with a <table> element and
2917 * both row and column index to specify a cell element.
2919 [[nodiscard
]] static CellData
AtIndexInTableElement(
2920 const HTMLEditor
& aHTMLEditor
, const Element
& aTableElement
,
2921 int32_t aRowIndex
, int32_t aColumnIndex
);
2922 [[nodiscard
]] static CellData
AtIndexInTableElement(
2923 const HTMLEditor
& aHTMLEditor
, const Element
& aTableElement
,
2924 const CellIndexes
& aIndexes
) {
2925 MOZ_ASSERT(!aIndexes
.isErr());
2926 return AtIndexInTableElement(aHTMLEditor
, aTableElement
, aIndexes
.mRow
,
2931 * Treated as error if fails to compute current index or first index of the
2932 * cell. Note that even if the cell is not found due to no corresponding
2933 * frame at current index, it's not an error situation.
2935 [[nodiscard
]] bool isOk() const { return !isErr(); }
2936 [[nodiscard
]] bool isErr() const { return mFirst
.isErr(); }
2939 * FailedOrNotFound() returns true if this failed to initialize/update
2940 * or succeeded but found no cell element.
2942 [[nodiscard
]] bool FailedOrNotFound() const { return isErr() || !mElement
; }
2945 * IsSpannedFromOtherRowOrColumn(), IsSpannedFromOtherColumn and
2946 * IsSpannedFromOtherRow() return true if there is no cell element
2947 * at the index because of spanning from other row and/or column.
2949 [[nodiscard
]] bool IsSpannedFromOtherRowOrColumn() const {
2950 return mElement
&& mCurrent
!= mFirst
;
2952 [[nodiscard
]] bool IsSpannedFromOtherColumn() const {
2953 return mElement
&& mCurrent
.mColumn
!= mFirst
.mColumn
;
2955 [[nodiscard
]] bool IsSpannedFromOtherRow() const {
2956 return mElement
&& mCurrent
.mRow
!= mFirst
.mRow
;
2958 [[nodiscard
]] bool IsNextColumnSpannedFromOtherColumn() const {
2959 return mElement
&& mCurrent
.mColumn
+ 1 < NextColumnIndex();
2963 * NextColumnIndex() and NextRowIndex() return column/row index of
2964 * next cell. Note that this does not check whether there is next
2965 * cell or not actually.
2967 [[nodiscard
]] int32_t NextColumnIndex() const {
2968 if (NS_WARN_IF(FailedOrNotFound())) {
2971 return mCurrent
.mColumn
+ mEffectiveColSpan
;
2973 [[nodiscard
]] int32_t NextRowIndex() const {
2974 if (NS_WARN_IF(FailedOrNotFound())) {
2977 return mCurrent
.mRow
+ mEffectiveRowSpan
;
2981 * LastColumnIndex() and LastRowIndex() return column/row index of
2982 * column/row which is spanned by the cell.
2984 [[nodiscard
]] int32_t LastColumnIndex() const {
2985 if (NS_WARN_IF(FailedOrNotFound())) {
2988 return NextColumnIndex() - 1;
2990 [[nodiscard
]] int32_t LastRowIndex() const {
2991 if (NS_WARN_IF(FailedOrNotFound())) {
2994 return NextRowIndex() - 1;
2998 * NumberOfPrecedingColmuns() and NumberOfPrecedingRows() return number of
2999 * preceding columns/rows if current index is spanned from other column/row.
3000 * Otherwise, i.e., current point is not spanned form other column/row,
3003 [[nodiscard
]] int32_t NumberOfPrecedingColmuns() const {
3004 if (NS_WARN_IF(FailedOrNotFound())) {
3007 return mCurrent
.mColumn
- mFirst
.mColumn
;
3009 [[nodiscard
]] int32_t NumberOfPrecedingRows() const {
3010 if (NS_WARN_IF(FailedOrNotFound())) {
3013 return mCurrent
.mRow
- mFirst
.mRow
;
3017 * NumberOfFollowingColumns() and NumberOfFollowingRows() return
3018 * number of remaining columns/rows if the cell spans to other
3021 [[nodiscard
]] int32_t NumberOfFollowingColumns() const {
3022 if (NS_WARN_IF(FailedOrNotFound())) {
3025 return mEffectiveColSpan
- 1;
3027 [[nodiscard
]] int32_t NumberOfFollowingRows() const {
3028 if (NS_WARN_IF(FailedOrNotFound())) {
3031 return mEffectiveRowSpan
- 1;
3035 explicit CellData(int32_t aCurrentRowIndex
, int32_t aCurrentColumnIndex
,
3036 int32_t aFirstRowIndex
, int32_t aFirstColumnIndex
)
3037 : mCurrent(aCurrentRowIndex
, aCurrentColumnIndex
),
3038 mFirst(aFirstRowIndex
, aFirstColumnIndex
) {}
3039 explicit CellData(Element
& aElement
, int32_t aRowIndex
,
3040 int32_t aColumnIndex
, nsTableCellFrame
& aTableCellFrame
,
3041 nsTableWrapperFrame
& aTableWrapperFrame
);
3043 [[nodiscard
]] static CellData
Error(int32_t aRowIndex
,
3044 int32_t aColumnIndex
) {
3045 return CellData(aRowIndex
, aColumnIndex
, -1, -1);
3047 [[nodiscard
]] static CellData
NotFound(int32_t aRowIndex
,
3048 int32_t aColumnIndex
) {
3049 return CellData(aRowIndex
, aColumnIndex
, aRowIndex
, aColumnIndex
);
3054 * TableSize stores and computes number of rows and columns of a <table>
3057 struct MOZ_STACK_CLASS TableSize final
{
3059 int32_t mColumnCount
;
3061 TableSize() = delete;
3064 * @param aHTMLEditor The editor which creates the instance.
3065 * @param aTableOrElementInTable If a <table> element, computes number
3066 * of rows and columns of it.
3067 * If another element in a <table> element,
3068 * computes number of rows and columns
3069 * of nearest ancestor <table> element.
3070 * Otherwise, i.e., non-<table> element
3071 * not in <table>, returns error.
3073 [[nodiscard
]] static Result
<TableSize
, nsresult
> Create(
3074 HTMLEditor
& aHTMLEditor
, Element
& aTableOrElementInTable
);
3076 [[nodiscard
]] bool IsEmpty() const { return !mRowCount
|| !mColumnCount
; }
3079 TableSize(int32_t aRowCount
, int32_t aColumCount
)
3080 : mRowCount(aRowCount
), mColumnCount(aColumCount
) {}
3084 * GetTableCellElementAt() returns a <td> or <th> element of aTableElement
3085 * if there is a cell at the indexes.
3087 * @param aTableElement Must be a <table> element.
3088 * @param aCellIndexes Indexes of cell which you want.
3089 * If rowspan and/or colspan is specified 2 or
3090 * larger, any indexes are allowed to retrieve
3091 * the cell in the area.
3092 * @return The cell element if there is in the <table>.
3093 * Returns nullptr without error if the indexes
3094 * are out of bounds.
3096 [[nodiscard
]] inline Element
* GetTableCellElementAt(
3097 Element
& aTableElement
, const CellIndexes
& aCellIndexes
) const;
3098 [[nodiscard
]] Element
* GetTableCellElementAt(Element
& aTableElement
,
3100 int32_t aColumnIndex
) const;
3103 * GetSelectedOrParentTableElement() returns <td>, <th>, <tr> or <table>
3105 * #1 if the first selection range selects a cell, returns it.
3106 * #2 if the first selection range does not select a cell and
3107 * the selection anchor refers a <table>, returns it.
3108 * #3 if the first selection range does not select a cell and
3109 * the selection anchor refers a <tr>, returns it.
3110 * #4 if the first selection range does not select a cell and
3111 * the selection anchor refers a <td>, returns it.
3112 * #5 otherwise, nearest ancestor <td> or <th> element of the
3113 * selection anchor if there is.
3114 * In #1 and #4, *aIsCellSelected will be set to true (i.e,, when
3115 * a selection range selects a cell element).
3117 Result
<RefPtr
<Element
>, nsresult
> GetSelectedOrParentTableElement(
3118 bool* aIsCellSelected
= nullptr) const;
3121 * GetFirstSelectedCellElementInTable() returns <td> or <th> element at
3122 * first selection (using GetSelectedOrParentTableElement). If found cell
3123 * element is not in <table> or <tr> element, this returns nullptr.
3125 Result
<RefPtr
<Element
>, nsresult
> GetFirstSelectedCellElementInTable() const;
3127 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
HandlePaste(
3128 AutoEditActionDataSetter
& aEditActionData
, int32_t aClipboardType
) final
;
3129 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
HandlePasteAsQuotation(
3130 AutoEditActionDataSetter
& aEditActionData
, int32_t aClipboardType
) final
;
3131 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3132 HandlePasteTransferable(AutoEditActionDataSetter
& aEditActionData
,
3133 nsITransferable
& aTransferable
) final
;
3136 * PasteInternal() pasts text with replacing selected content.
3137 * This tries to dispatch ePaste event first. If its defaultPrevent() is
3138 * called, this does nothing but returns NS_OK.
3140 * @param aClipboardType nsIClipboard::kGlobalClipboard or
3141 * nsIClipboard::kSelectionClipboard.
3143 MOZ_CAN_RUN_SCRIPT nsresult
PasteInternal(int32_t aClipboardType
);
3145 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3146 InsertWithQuotationsAsSubAction(const nsAString
& aQuotedText
) final
;
3149 * InsertAsCitedQuotationInternal() inserts a <blockquote> element whose
3150 * cite attribute is aCitation and whose content is aQuotedText.
3151 * Note that this shouldn't be called when IsPlaintextMailComposer() is true.
3153 * @param aQuotedText HTML source if aInsertHTML is true. Otherwise,
3154 * plain text. This is inserted into new <blockquote>
3156 * @param aCitation cite attribute value of new <blockquote> element.
3157 * @param aInsertHTML true if aQuotedText should be treated as HTML
3159 * false if aQuotedText should be treated as plain
3161 * @param aNodeInserted [OUT] The new <blockquote> element.
3163 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertAsCitedQuotationInternal(
3164 const nsAString
& aQuotedText
, const nsAString
& aCitation
,
3165 bool aInsertHTML
, nsINode
** aNodeInserted
);
3168 * InsertNodeIntoProperAncestorWithTransaction() attempts to insert aNode
3169 * into the document, at aPointToInsert. Checks with strict dtd to see if
3170 * containment is allowed. If not allowed, will attempt to find a parent
3171 * in the parent hierarchy of aPointToInsert.GetContainer() that will accept
3172 * aNode as a child. If such a parent is found, will split the document
3173 * tree from aPointToInsert up to parent, and then insert aNode.
3174 * aPointToInsert is then adjusted to point to the actual location that
3175 * aNode was inserted at. aSplitAtEdges specifies if the splitting process
3176 * is allowed to result in empty nodes.
3178 * @param aContent The content node to insert.
3179 * @param aPointToInsert Insertion point.
3180 * @param aSplitAtEdges Splitting can result in empty nodes?
3182 template <typename NodeType
>
3183 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
3184 Result
<CreateNodeResultBase
<NodeType
>, nsresult
>
3185 InsertNodeIntoProperAncestorWithTransaction(
3186 NodeType
& aContent
, const EditorDOMPoint
& aPointToInsert
,
3187 SplitAtEdges aSplitAtEdges
);
3190 * InsertTextWithQuotationsInternal() replaces selection with new content.
3191 * First, this method splits aStringToInsert to multiple chunks which start
3192 * with non-linebreaker except first chunk and end with a linebreaker except
3193 * last chunk. Then, each chunk starting with ">" is inserted after wrapping
3194 * with <span _moz_quote="true">, and each chunk not starting with ">" is
3195 * inserted as normal text.
3197 MOZ_CAN_RUN_SCRIPT nsresult
3198 InsertTextWithQuotationsInternal(const nsAString
& aStringToInsert
);
3201 * ReplaceContainerWithTransactionInternal() is implementation of
3202 * ReplaceContainerWithTransaction() and
3203 * ReplaceContainerAndCloneAttributesWithTransaction().
3205 * @param aOldContainer The element which will be replaced with new
3207 * @param aTagName The name of new element node.
3208 * @param aAttribute Attribute name which will be set to the new
3209 * element. This will be ignored if
3210 * aCloneAllAttributes is set to true.
3211 * @param aAttributeValue Attribute value which will be set to
3213 * @param aCloneAllAttributes If true, all attributes of aOldContainer will
3214 * be copied to the new element.
3216 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
3217 ReplaceContainerWithTransactionInternal(Element
& aOldContainer
,
3218 const nsAtom
& aTagName
,
3219 const nsAtom
& aAttribute
,
3220 const nsAString
& aAttributeValue
,
3221 bool aCloneAllAttributes
);
3224 * DeleteSelectionAndCreateElement() creates a element whose name is aTag.
3225 * And insert it into the DOM tree after removing the selected content.
3227 * @param aTag The element name to be created.
3228 * @param aInitializer A function to initialize the new element before
3229 * or after (depends on the pref) connecting the
3230 * element into the DOM tree. Note that this should
3231 * not touch outside given element because doing it
3232 * would break range updater's result.
3234 MOZ_CAN_RUN_SCRIPT Result
<RefPtr
<Element
>, nsresult
>
3235 DeleteSelectionAndCreateElement(
3237 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
3240 * This method first deletes the selection, if it's not collapsed. Then if
3241 * the selection lies in a CharacterData node, it splits it. If the
3242 * selection is at this point collapsed in a CharacterData node, it's
3243 * adjusted to be collapsed right before or after the node instead (which is
3244 * always possible, since the node was split).
3246 MOZ_CAN_RUN_SCRIPT nsresult
DeleteSelectionAndPrepareToCreateNode();
3249 * PrepareToInsertBRElement() returns a point where new <br> element should
3250 * be inserted. If aPointToInsert points middle of a text node, this method
3251 * splits the text node and returns the point before right node.
3253 * @param aPointToInsert Candidate point to insert new <br> element.
3254 * @return Computed point to insert new <br> element.
3255 * If something failed, this return error.
3257 MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
> PrepareToInsertBRElement(
3258 const EditorDOMPoint
& aPointToInsert
);
3261 * IndentAsSubAction() indents the content around Selection.
3263 * @param aEditingHost The editing host.
3265 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
3266 IndentAsSubAction(const Element
& aEditingHost
);
3269 * OutdentAsSubAction() outdents the content around Selection.
3271 * @param aEditingHost The editing host.
3273 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
3274 OutdentAsSubAction(const Element
& aEditingHost
);
3276 MOZ_CAN_RUN_SCRIPT nsresult
LoadHTML(const nsAString
& aInputString
);
3279 * UpdateMetaCharsetWithTransaction() scans all <meta> elements in the
3280 * document and if and only if there is a <meta> element having `httpEquiv`
3281 * attribute and whose value includes `content-type`, updates its `content`
3282 * attribute value to aCharacterSet.
3284 MOZ_CAN_RUN_SCRIPT
bool UpdateMetaCharsetWithTransaction(
3285 Document
& aDocument
, const nsACString
& aCharacterSet
);
3288 * SetInlinePropertiesAsSubAction() stores new styles with
3289 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3290 * applying the styles to all selected contents.
3292 * @param aStylesToSet The styles which should be applied to the
3296 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertiesAsSubAction(
3297 const AutoTArray
<EditorInlineStyleAndValue
, N
>& aStylesToSet
);
3300 * SetInlinePropertiesAroundRanges() applying the styles to the ranges even if
3301 * the ranges are collapsed.
3304 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertiesAroundRanges(
3305 AutoRangeArray
& aRanges
,
3306 const AutoTArray
<EditorInlineStyleAndValue
, N
>& aStylesToSet
,
3307 const Element
& aEditingHost
);
3310 * RemoveInlinePropertiesAsSubAction() removes specified styles from
3311 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3312 * removing the style.
3314 * @param aStylesToRemove Styles to remove from the selected contents.
3316 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
RemoveInlinePropertiesAsSubAction(
3317 const nsTArray
<EditorInlineStyle
>& aStylesToRemove
);
3320 * Helper method to call RemoveInlinePropertiesAsSubAction(). If you want to
3321 * remove other elements to remove the style completely, this will append
3322 * related elements of aStyleToRemove and aStyleToRemove itself to the array.
3323 * E.g., nsGkAtoms::strong and nsGkAtoms::b will be appended if aStyleToRemove
3326 void AppendInlineStyleAndRelatedStyle(
3327 const EditorInlineStyle
& aStyleToRemove
,
3328 nsTArray
<EditorInlineStyle
>& aStylesToRemove
) const;
3331 * ReplaceHeadContentsWithSourceWithTransaction() replaces all children of
3332 * <head> element with given source code. This is undoable.
3334 * @param aSourceToInsert HTML source fragment to replace the children
3335 * of <head> element.
3337 MOZ_CAN_RUN_SCRIPT nsresult
ReplaceHeadContentsWithSourceWithTransaction(
3338 const nsAString
& aSourceToInsert
);
3340 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetCSSBackgroundColorState(
3341 bool* aMixed
, nsAString
& aOutColor
, bool aBlockLevel
);
3342 nsresult
GetHTMLBackgroundColorState(bool* aMixed
, nsAString
& outColor
);
3345 * This sets background on the appropriate container element (table, cell,)
3346 * or calls to set the page background.
3348 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3349 SetBlockBackgroundColorWithCSSAsSubAction(const nsAString
& aColor
);
3350 MOZ_CAN_RUN_SCRIPT nsresult
3351 SetHTMLBackgroundColorWithTransaction(const nsAString
& aColor
);
3353 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void InitializeSelectionAncestorLimit(
3354 nsIContent
& aAncestorLimit
) const final
;
3357 * Make the given selection span the entire document.
3359 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SelectEntireDocument() final
;
3362 * Use this to assure that selection is set after attribute nodes when
3363 * trying to collapse selection at begining of a block node
3364 * e.g., when setting at beginning of a table cell
3365 * This will stop at a table, however, since we don't want to
3366 * "drill down" into nested tables.
3368 MOZ_CAN_RUN_SCRIPT
void CollapseSelectionToDeepestNonTableFirstChild(
3371 * MaybeCollapseSelectionAtFirstEditableNode() may collapse selection at
3372 * proper position to staring to edit. If there is a non-editable node
3373 * before any editable text nodes or inline elements which can have text
3374 * nodes as their children, collapse selection at start of the editing
3375 * host. If there is an editable text node which is not collapsed, collapses
3376 * selection at the start of the text node. If there is an editable inline
3377 * element which cannot have text nodes as its child, collapses selection at
3378 * before the element node. Otherwise, collapses selection at start of the
3381 * @param aIgnoreIfSelectionInEditingHost
3382 * This method does nothing if selection is in the
3383 * editing host except if it's collapsed at start of
3385 * Note that if selection ranges were outside of
3386 * current selection limiter, selection was collapsed
3387 * at the start of the editing host therefore, if
3388 * you call this with setting this to true, you can
3389 * keep selection ranges if user has already been
3392 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3393 MaybeCollapseSelectionAtFirstEditableNode(
3394 bool aIgnoreIfSelectionInEditingHost
) const;
3396 class BlobReader final
{
3397 using AutoEditActionDataSetter
= EditorBase::AutoEditActionDataSetter
;
3400 MOZ_CAN_RUN_SCRIPT
BlobReader(dom::BlobImpl
* aBlob
, HTMLEditor
* aHTMLEditor
,
3401 SafeToInsertData aSafeToInsertData
,
3402 const EditorDOMPoint
& aPointToInsert
,
3403 DeleteSelectedContent aDeleteSelectedContent
);
3405 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BlobReader
)
3406 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BlobReader
)
3408 MOZ_CAN_RUN_SCRIPT nsresult
OnResult(const nsACString
& aResult
);
3409 nsresult
OnError(const nsAString
& aErrorName
);
3412 ~BlobReader() = default;
3414 RefPtr
<dom::BlobImpl
> mBlob
;
3415 RefPtr
<HTMLEditor
> mHTMLEditor
;
3416 RefPtr
<dom::DataTransfer
> mDataTransfer
;
3417 EditorDOMPoint mPointToInsert
;
3418 EditAction mEditAction
;
3419 SafeToInsertData mSafeToInsertData
;
3420 DeleteSelectedContent mDeleteSelectedContent
;
3421 bool mNeedsToDispatchBeforeInputEvent
;
3424 void CreateEventListeners() final
;
3425 nsresult
InstallEventListeners() final
;
3427 bool ShouldReplaceRootElement() const;
3428 MOZ_CAN_RUN_SCRIPT
void NotifyRootChanged();
3429 Element
* GetBodyElement() const;
3432 * Get the focused node of this editor.
3433 * @return If the editor has focus, this returns the focused node.
3434 * Otherwise, returns null.
3436 nsINode
* GetFocusedNode() const;
3438 already_AddRefed
<Element
> GetInputEventTargetElement() const final
;
3441 * Return TRUE if aElement is a table-related elemet and caret was set.
3443 MOZ_CAN_RUN_SCRIPT
bool SetCaretInTableCell(dom::Element
* aElement
);
3446 * HandleTabKeyPressInTable() handles "Tab" key press in table if selection
3447 * is in a `<table>` element.
3449 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
3450 HandleTabKeyPressInTable(WidgetKeyboardEvent
* aKeyboardEvent
);
3453 * InsertPosition is an enum to indicate where the method should insert to.
3455 enum class InsertPosition
{
3456 // Before selected cell or a cell containing first selection range.
3457 eBeforeSelectedCell
,
3458 // After selected cell or a cell containing first selection range.
3463 * InsertTableCellsWithTransaction() inserts <td> elements at aPointToInsert.
3464 * Note that this simply inserts <td> elements, i.e., colspan and rowspan
3465 * around the cell containing selection are not modified. So, for example,
3466 * adding a cell to rectangular table changes non-rectangular table.
3467 * And if the cell containing selection is at left of row-spanning cell,
3468 * it may be moved to right side of the row-spanning cell after inserting
3469 * some cell elements before it. Similarly, colspan won't be adjusted
3470 * for keeping table rectangle.
3471 * Finally, puts caret into previous cell of the insertion point or the
3472 * first inserted cell if aPointToInsert is start of the row.
3474 * @param aPointToInsert The place to insert one or more cell
3475 * elements. The container must be a
3477 * @param aNumberOfCellsToInsert Number of cells to insert.
3478 * @return The first inserted cell element and
3479 * start of the last inserted cell element
3480 * as a point to put caret.
3482 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
3483 InsertTableCellsWithTransaction(const EditorDOMPoint
& aPointToInsert
,
3484 int32_t aNumberOfCellsToInsert
);
3487 * InsertTableColumnsWithTransaction() inserts cell elements to every rows
3488 * at same column index as the cell specified by aPointToInsert.
3490 * @param aNumberOfColumnsToInsert Number of columns to insert.
3492 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertTableColumnsWithTransaction(
3493 const EditorDOMPoint
& aPointToInsert
, int32_t aNumberOfColumnsToInsert
);
3496 * InsertTableRowsWithTransaction() inserts <tr> elements before or after
3497 * aCellElement. When aCellElement spans rows and aInsertPosition is
3498 * eAfterSelectedCell, new rows will be inserted after the most-bottom row
3499 * which contains the cell.
3501 * @param aCellElement The cell element pinting where this will
3502 * insert a row before or after.
3503 * @param aNumberOfRowsToInsert Number of rows to insert.
3504 * @param aInsertPosition Before or after the target cell which
3505 * contains first selection range.
3507 MOZ_CAN_RUN_SCRIPT nsresult
InsertTableRowsWithTransaction(
3508 Element
& aCellElement
, int32_t aNumberOfRowsToInsert
,
3509 InsertPosition aInsertPosition
);
3512 * Insert a new cell after or before supplied aCell.
3513 * Optional: If aNewCell supplied, returns the newly-created cell (addref'd,
3515 * This doesn't change or use the current selection.
3517 MOZ_CAN_RUN_SCRIPT nsresult
InsertCell(Element
* aCell
, int32_t aRowSpan
,
3518 int32_t aColSpan
, bool aAfter
,
3519 bool aIsHeader
, Element
** aNewCell
);
3522 * DeleteSelectedTableColumnsWithTransaction() removes cell elements which
3523 * belong to same columns of selected cell elements.
3524 * If only one cell element is selected or first selection range is
3525 * in a cell, removes cell elements which belong to same column.
3526 * If 2 or more cell elements are selected, removes cell elements which
3527 * belong to any of all selected columns. In this case,
3528 * aNumberOfColumnsToDelete is ignored.
3529 * If there is no selection ranges, returns error.
3530 * If selection is not in a cell element, this does not return error,
3531 * just does nothing.
3532 * WARNING: This does not remove <col> nor <colgroup> elements.
3534 * @param aNumberOfColumnsToDelete Number of columns to remove. This is
3535 * ignored if 2 ore more cells are
3538 MOZ_CAN_RUN_SCRIPT nsresult
3539 DeleteSelectedTableColumnsWithTransaction(int32_t aNumberOfColumnsToDelete
);
3542 * DeleteTableColumnWithTransaction() removes cell elements which belong
3543 * to the specified column.
3544 * This method adjusts colspan attribute value if cells spanning the
3546 * WARNING: This does not remove <col> nor <colgroup> elements.
3548 * @param aTableElement The <table> element which contains the
3549 * column which you want to remove.
3550 * @param aRowIndex Index of the column which you want to remove.
3551 * 0 is the first column.
3553 MOZ_CAN_RUN_SCRIPT nsresult
DeleteTableColumnWithTransaction(
3554 Element
& aTableElement
, int32_t aColumnIndex
);
3557 * DeleteSelectedTableRowsWithTransaction() removes <tr> elements.
3558 * If only one cell element is selected or first selection range is
3559 * in a cell, removes <tr> elements starting from a <tr> element
3560 * containing the selected cell or first selection range.
3561 * If 2 or more cell elements are selected, all <tr> elements
3562 * which contains selected cell(s). In this case, aNumberOfRowsToDelete
3564 * If there is no selection ranges, returns error.
3565 * If selection is not in a cell element, this does not return error,
3566 * just does nothing.
3568 * @param aNumberOfRowsToDelete Number of rows to remove. This is ignored
3569 * if 2 or more cells are selected.
3571 MOZ_CAN_RUN_SCRIPT nsresult
3572 DeleteSelectedTableRowsWithTransaction(int32_t aNumberOfRowsToDelete
);
3575 * DeleteTableRowWithTransaction() removes a <tr> element whose index in
3576 * the <table> is aRowIndex.
3577 * This method adjusts rowspan attribute value if the <tr> element contains
3578 * cells which spans rows.
3580 * @param aTableElement The <table> element which contains the
3581 * <tr> element which you want to remove.
3582 * @param aRowIndex Index of the <tr> element which you want to
3583 * remove. 0 is the first row.
3585 MOZ_CAN_RUN_SCRIPT nsresult
3586 DeleteTableRowWithTransaction(Element
& aTableElement
, int32_t aRowIndex
);
3589 * DeleteTableCellWithTransaction() removes table cell elements. If two or
3590 * more cell elements are selected, this removes all selected cell elements.
3591 * Otherwise, this removes some cell elements starting from selected cell
3592 * element or a cell containing first selection range. When this removes
3593 * last cell element in <tr> or <table>, this removes the <tr> or the
3594 * <table> too. Note that when removing a cell causes number of its row
3595 * becomes less than the others, this method does NOT fill the place with
3596 * rowspan nor colspan. This does not return error even if selection is not
3597 * in cell element, just does nothing.
3599 * @param aNumberOfCellsToDelete Number of cells to remove. This is ignored
3600 * if 2 or more cells are selected.
3602 MOZ_CAN_RUN_SCRIPT nsresult
3603 DeleteTableCellWithTransaction(int32_t aNumberOfCellsToDelete
);
3606 * DeleteAllChildrenWithTransaction() removes all children of aElement from
3609 * @param aElement The element whose children you want to remove.
3611 MOZ_CAN_RUN_SCRIPT nsresult
3612 DeleteAllChildrenWithTransaction(Element
& aElement
);
3615 * Move all contents from aCellToMerge into aTargetCell (append at end).
3617 MOZ_CAN_RUN_SCRIPT nsresult
MergeCells(RefPtr
<Element
> aTargetCell
,
3618 RefPtr
<Element
> aCellToMerge
,
3619 bool aDeleteCellToMerge
);
3622 * DeleteTableElementAndChildren() removes aTableElement (and its children)
3623 * from the DOM tree with transaction.
3625 * @param aTableElement The <table> element which you want to remove.
3627 MOZ_CAN_RUN_SCRIPT nsresult
3628 DeleteTableElementAndChildrenWithTransaction(Element
& aTableElement
);
3630 MOZ_CAN_RUN_SCRIPT nsresult
SetColSpan(Element
* aCell
, int32_t aColSpan
);
3631 MOZ_CAN_RUN_SCRIPT nsresult
SetRowSpan(Element
* aCell
, int32_t aRowSpan
);
3634 * Helper used to get nsTableWrapperFrame for a table.
3636 static nsTableWrapperFrame
* GetTableFrame(const Element
* aTable
);
3639 * GetNumberOfCellsInRow() returns number of actual cell elements in the row.
3640 * If some cells appear by "rowspan" in other rows, they are ignored.
3642 * @param aTableElement The <table> element.
3643 * @param aRowIndex Valid row index in aTableElement. This method
3644 * counts cell elements in the row.
3645 * @return -1 if this meets unexpected error.
3646 * Otherwise, number of cells which this method found.
3648 int32_t GetNumberOfCellsInRow(Element
& aTableElement
, int32_t aRowIndex
);
3651 * Test if all cells in row or column at given index are selected.
3653 bool AllCellsInRowSelected(Element
* aTable
, int32_t aRowIndex
,
3654 int32_t aNumberOfColumns
);
3655 bool AllCellsInColumnSelected(Element
* aTable
, int32_t aColIndex
,
3656 int32_t aNumberOfRows
);
3658 bool IsEmptyCell(Element
* aCell
);
3661 * Most insert methods need to get the same basic context data.
3662 * Any of the pointers may be null if you don't need that datum (for more
3664 * Input: *aCell is a known cell,
3665 * if null, cell is obtained from the anchor node of the selection.
3666 * Returns NS_EDITOR_ELEMENT_NOT_FOUND if cell is not found even if aCell is
3669 MOZ_CAN_RUN_SCRIPT nsresult
GetCellContext(Element
** aTable
, Element
** aCell
,
3670 nsINode
** aCellParent
,
3671 int32_t* aCellOffset
,
3673 int32_t* aColIndex
);
3675 nsresult
GetCellSpansAt(Element
* aTable
, int32_t aRowIndex
, int32_t aColIndex
,
3676 int32_t& aActualRowSpan
, int32_t& aActualColSpan
);
3678 MOZ_CAN_RUN_SCRIPT nsresult
SplitCellIntoColumns(
3679 Element
* aTable
, int32_t aRowIndex
, int32_t aColIndex
,
3680 int32_t aColSpanLeft
, int32_t aColSpanRight
, Element
** aNewCell
);
3682 MOZ_CAN_RUN_SCRIPT nsresult
SplitCellIntoRows(
3683 Element
* aTable
, int32_t aRowIndex
, int32_t aColIndex
,
3684 int32_t aRowSpanAbove
, int32_t aRowSpanBelow
, Element
** aNewCell
);
3686 MOZ_CAN_RUN_SCRIPT nsresult
CopyCellBackgroundColor(Element
* aDestCell
,
3687 Element
* aSourceCell
);
3690 * Reduce rowspan/colspan when cells span into nonexistent rows/columns.
3692 MOZ_CAN_RUN_SCRIPT nsresult
FixBadRowSpan(Element
* aTable
, int32_t aRowIndex
,
3693 int32_t& aNewRowCount
);
3694 MOZ_CAN_RUN_SCRIPT nsresult
FixBadColSpan(Element
* aTable
, int32_t aColIndex
,
3695 int32_t& aNewColCount
);
3698 * XXX NormalizeTableInternal() is broken. If it meets a cell which has
3699 * bigger or smaller rowspan or colspan than actual number of cells,
3700 * this always failed to scan the table. Therefore, this does nothing
3701 * when the table should be normalized.
3703 * @param aTableOrElementInTable An element which is in a <table> element
3704 * or <table> element itself. Otherwise,
3705 * this returns NS_OK but does nothing.
3707 MOZ_CAN_RUN_SCRIPT nsresult
3708 NormalizeTableInternal(Element
& aTableOrElementInTable
);
3711 * Fallback method: Call this after using ClearSelection() and you
3712 * failed to set selection to some other content in the document.
3714 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetSelectionAtDocumentStart();
3716 // Methods for handling plaintext quotations
3717 MOZ_CAN_RUN_SCRIPT nsresult
PasteAsPlaintextQuotation(int32_t aSelectionType
);
3720 * Insert a string as quoted text, replacing the selected text (if any).
3721 * @param aQuotedText The string to insert.
3722 * @param aAddCites Whether to prepend extra ">" to each line
3723 * (usually true, unless those characters
3724 * have already been added.)
3725 * @return aNodeInserted The node spanning the insertion, if applicable.
3726 * If aAddCites is false, this will be null.
3728 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertAsPlaintextQuotation(
3729 const nsAString
& aQuotedText
, bool aAddCites
, nsINode
** aNodeInserted
);
3732 * InsertObject() inserts given object at aPointToInsert.
3734 * @param aType one of kFileMime, kJPEGImageMime, kJPGImageMime,
3735 * kPNGImageMime, kGIFImageMime.
3737 MOZ_CAN_RUN_SCRIPT nsresult
InsertObject(
3738 const nsACString
& aType
, nsISupports
* aObject
,
3739 SafeToInsertData aSafeToInsertData
, const EditorDOMPoint
& aPointToInsert
,
3740 DeleteSelectedContent aDeleteSelectedContent
);
3742 class HTMLTransferablePreparer
;
3743 nsresult
PrepareHTMLTransferable(nsITransferable
** aTransferable
) const;
3745 enum class HavePrivateHTMLFlavor
{ No
, Yes
};
3746 MOZ_CAN_RUN_SCRIPT nsresult
InsertFromTransferableAtSelection(
3747 nsITransferable
* aTransferable
, const nsAString
& aContextStr
,
3748 const nsAString
& aInfoStr
, HavePrivateHTMLFlavor aHavePrivateHTMLFlavor
);
3751 * InsertFromDataTransfer() is called only when user drops data into
3752 * this editor. Don't use this method for other purposes.
3754 * @param aIndex index of aDataTransfer's item to insert.
3756 MOZ_CAN_RUN_SCRIPT nsresult
InsertFromDataTransfer(
3757 const dom::DataTransfer
* aDataTransfer
, uint32_t aIndex
,
3758 nsIPrincipal
* aSourcePrincipal
, const EditorDOMPoint
& aDroppedAt
,
3759 DeleteSelectedContent aDeleteSelectedContent
);
3761 static HavePrivateHTMLFlavor
ClipboardHasPrivateHTMLFlavor(
3762 nsIClipboard
* clipboard
);
3766 * <https://docs.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format>.
3768 * @param[in] aCfhtml a CF_HTML string as defined above.
3769 * @param[out] aStuffToPaste the fragment, excluding context.
3770 * @param[out] aCfcontext the context, excluding the fragment, including a
3771 * marker (`kInsertionCookie`) indicating where the
3774 nsresult
ParseCFHTML(const nsCString
& aCfhtml
, char16_t
** aStuffToPaste
,
3775 char16_t
** aCfcontext
);
3778 * AutoHTMLFragmentBoundariesFixer fixes both edges of topmost child contents
3779 * which are created with SubtreeContentIterator.
3781 class MOZ_STACK_CLASS AutoHTMLFragmentBoundariesFixer final
{
3784 * @param aArrayOfTopMostChildContents
3785 * [in/out] The topmost child contents which will be
3786 * inserted into the DOM tree. Both edges, i.e.,
3787 * first node and last node in this array will be
3788 * checked whether they can be inserted into
3789 * another DOM tree. If not, it'll replaces some
3790 * orphan nodes around nodes with proper parent.
3792 explicit AutoHTMLFragmentBoundariesFixer(
3793 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfTopMostChildContents
);
3797 * EnsureBeginsOrEndsWithValidContent() replaces some nodes starting from
3798 * start or end with proper element node if it's necessary.
3799 * If first or last node of aArrayOfTopMostChildContents is in list and/or
3800 * `<table>` element, looks for topmost list element or `<table>` element
3801 * with `CollectTableAndAnyListElementsOfInclusiveAncestorsAt()` and
3802 * `GetMostDistantAncestorListOrTableElement()`. Then, checks
3803 * whether some nodes are in aArrayOfTopMostChildContents are the topmost
3804 * list/table element or its descendant and if so, removes the nodes from
3805 * aArrayOfTopMostChildContents and inserts the list/table element instead.
3806 * Then, aArrayOfTopMostChildContents won't start/end with list-item nor
3809 enum class StartOrEnd
{ start
, end
};
3810 void EnsureBeginsOrEndsWithValidContent(
3811 StartOrEnd aStartOrEnd
,
3812 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfTopMostChildContents
)
3816 * CollectTableAndAnyListElementsOfInclusiveAncestorsAt() collects list
3817 * elements and table related elements from the inclusive ancestors
3818 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of aNode.
3820 static void CollectTableAndAnyListElementsOfInclusiveAncestorsAt(
3821 nsIContent
& aContent
,
3822 nsTArray
<OwningNonNull
<Element
>>& aOutArrayOfListAndTableElements
);
3825 * GetMostDistantAncestorListOrTableElement() returns a list or a
3826 * `<table>` element which is in
3827 * aInclusiveAncestorsTableOrListElements and they are actually
3828 * valid ancestor of at least one of aArrayOfTopMostChildContents.
3830 static Element
* GetMostDistantAncestorListOrTableElement(
3831 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfTopMostChildContents
,
3832 const nsTArray
<OwningNonNull
<Element
>>&
3833 aInclusiveAncestorsTableOrListElements
);
3836 * FindReplaceableTableElement() is a helper method of
3837 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInTableElement is
3838 * a descendant of aTableElement, returns aNodeMaybeInTableElement or its
3839 * nearest ancestor whose tag name is `<td>`, `<th>`, `<tr>`, `<thead>`,
3840 * `<tfoot>`, `<tbody>` or `<caption>`.
3842 * @param aTableElement Must be a `<table>` element.
3843 * @param aContentMaybeInTableElement A node which may be in aTableElement.
3845 Element
* FindReplaceableTableElement(
3846 Element
& aTableElement
, nsIContent
& aContentMaybeInTableElement
) const;
3849 * IsReplaceableListElement() is a helper method of
3850 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInListElement is a
3851 * descendant of aListElement, returns true. Otherwise, false.
3853 * @param aListElement Must be a list element.
3854 * @param aContentMaybeInListElement A node which may be in aListElement.
3856 bool IsReplaceableListElement(Element
& aListElement
,
3857 nsIContent
& aContentMaybeInListElement
) const;
3861 * MakeDefinitionListItemWithTransaction() replaces parent list of current
3862 * selection with <dl> or create new <dl> element and creates a definition
3863 * list item whose name is aTagName.
3865 * @param aTagName Must be nsGkAtoms::dt or nsGkAtoms::dd.
3867 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3868 MakeDefinitionListItemWithTransaction(nsAtom
& aTagName
);
3871 * FormatBlockContainerAsSubAction() inserts a block element whose name
3872 * is aTagName at selection. If selection is not collapsed and aTagName is
3873 * nsGkAtoms::normal or nsGkAtoms::_empty, this removes block containers.
3875 * @param aTagName A block level element name. Must NOT be
3876 * nsGkAtoms::dt nor nsGkAtoms::dd.
3877 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
3878 * paragraphState command.
3880 MOZ_CAN_RUN_SCRIPT nsresult
FormatBlockContainerAsSubAction(
3881 const nsStaticAtom
& aTagName
, FormatBlockMode aFormatBlockMode
);
3884 * Increase/decrease the font size of selection.
3886 MOZ_CAN_RUN_SCRIPT nsresult
3887 IncrementOrDecrementFontSizeAsSubAction(FontSize aIncrementOrDecrement
);
3890 * Wrap aContent in <big> or <small> element and make children of
3891 * <font size=n> wrap with <big> or <small> too. Note that if there is
3892 * opposite element for aIncrementOrDecrement, their children will be just
3895 * @param aDir Whether increase or decrease the font size of aContent.
3896 * @param aContent The content node whose font size will be changed.
3897 * @return A suggest point to put caret.
3899 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
3900 SetFontSizeWithBigOrSmallElement(nsIContent
& aContent
,
3901 FontSize aIncrementOrDecrement
);
3904 * Adjust font size of font element children recursively with handling
3905 * <big> and <small> elements.
3907 * @param aDir Whether increase or decrease the font size of aContent.
3908 * @param aContent The content node whose font size will be changed.
3909 * All descendants will be handled recursively.
3910 * @return A suggest point to put caret.
3912 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
3913 SetFontSizeOfFontElementChildren(nsIContent
& aContent
,
3914 FontSize aIncrementOrDecrement
);
3917 * Get extended range to select element whose all children are selected by
3920 EditorRawDOMRange
GetExtendedRangeWrappingEntirelySelectedElements(
3921 const EditorRawDOMRange
& aRange
) const;
3924 * Get extended range to select ancestor <a name> elements.
3926 EditorRawDOMRange
GetExtendedRangeWrappingNamedAnchor(
3927 const EditorRawDOMRange
& aRange
) const;
3929 // Declared in HTMLEditorNestedClasses.h and defined in HTMLStyleEditor.cpp
3930 class AutoInlineStyleSetter
;
3933 * RemoveStyleInside() removes elements which represent aStyleToRemove
3934 * and removes CSS style. This handles aElement and all its descendants
3935 * (including leaf text nodes) recursively.
3936 * TODO: Rename this to explain that this maybe remove aElement from the DOM
3939 * @param aSpecifiedStyle Whether the class and style attributes should
3940 * be preserved or discarded.
3941 * @return A suggest point to put caret.
3943 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
3944 RemoveStyleInside(Element
& aElement
, const EditorInlineStyle
& aStyleToRemove
,
3945 SpecifiedStyle aSpecifiedStyle
);
3948 * CollectEditableLeafTextNodes() collects text nodes in aElement.
3950 void CollectEditableLeafTextNodes(
3951 Element
& aElement
, nsTArray
<OwningNonNull
<Text
>>& aLeafTextNodes
) const;
3954 * IsRemovableParentStyleWithNewSpanElement() checks whether aStyle of parent
3955 * block can be removed from aContent with creating `<span>` element. Note
3956 * that this does NOT check whether the specified style comes from parent
3958 * XXX This may destroy the editor, but using `Result<bool, nsresult>`
3959 * is not reasonable because code for accessing the result becomes
3960 * messy. However, anybody must forget to check `Destroyed()` after
3961 * calling this. Which is the way to smart to make every caller
3962 * must check the editor state?
3964 MOZ_CAN_RUN_SCRIPT Result
<bool, nsresult
>
3965 IsRemovableParentStyleWithNewSpanElement(
3966 nsIContent
& aContent
, const EditorInlineStyle
& aStyle
) const;
3969 * HasStyleOrIdOrClassAttribute() returns true when at least one of
3970 * `style`, `id` or `class` attribute value of aElement is not empty.
3972 static bool HasStyleOrIdOrClassAttribute(Element
& aElement
);
3975 * Whether the outer window of the DOM event target has focus or not.
3977 bool OurWindowHasFocus() const;
3979 class HTMLWithContextInserter
;
3982 * This function is used to insert a string of HTML input optionally with some
3983 * context information into the editable field. The HTML input either comes
3984 * from a transferable object created as part of a drop/paste operation, or
3985 * from the InsertHTML method. We may want the HTML input to be sanitized
3986 * (for example, if it's coming from a transferable object), in which case
3987 * aTrustedInput should be set to false, otherwise, the caller should set it
3988 * to true, which means that the HTML will be inserted in the DOM verbatim.
3990 enum class InlineStylesAtInsertionPoint
{
3991 Preserve
, // If you want the paste to be affected by local style, e.g.,
3992 // for the insertHTML command, use "Preserve"
3993 Clear
, // If you want the paste to be keep its own style, e.g., pasting
3994 // from clipboard, use "Clear"
3996 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertHTMLWithContextAsSubAction(
3997 const nsAString
& aInputString
, const nsAString
& aContextStr
,
3998 const nsAString
& aInfoStr
, const nsAString
& aFlavor
,
3999 SafeToInsertData aSafeToInsertData
, const EditorDOMPoint
& aPointToInsert
,
4000 DeleteSelectedContent aDeleteSelectedContent
,
4001 InlineStylesAtInsertionPoint aInlineStylesAtInsertionPoint
);
4004 * sets the position of an element; warning it does NOT check if the
4005 * element is already positioned or not and that's on purpose.
4006 * @param aStyledElement [IN] the element
4007 * @param aX [IN] the x position in pixels.
4008 * @param aY [IN] the y position in pixels.
4010 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetTopAndLeftWithTransaction(
4011 nsStyledElement
& aStyledElement
, int32_t aX
, int32_t aY
);
4014 * Reset a selected cell or collapsed selection (the caret) after table
4017 * @param aTable A table in the document.
4018 * @param aRow The row ...
4019 * @param aCol ... and column defining the cell where we will try to
4021 * @param aSelected If true, we select the whole cell instead of setting
4023 * @param aDirection If cell at (aCol, aRow) is not found, search for
4024 * previous cell in the same column (aPreviousColumn) or
4025 * row (ePreviousRow) or don't search for another cell
4026 * (aNoSearch). If no cell is found, caret is place just
4027 * before table; and if that fails, at beginning of
4028 * document. Thus we generally don't worry about the
4029 * return value and can use the
4030 * AutoSelectionSetterAfterTableEdit stack-based object to
4031 * insure we reset the caret in a table-editing method.
4033 MOZ_CAN_RUN_SCRIPT
void SetSelectionAfterTableEdit(Element
* aTable
,
4034 int32_t aRow
, int32_t aCol
,
4038 void RemoveListenerAndDeleteRef(const nsAString
& aEvent
,
4039 nsIDOMEventListener
* aListener
,
4040 bool aUseCapture
, ManualNACPtr aElement
,
4041 PresShell
* aPresShell
);
4042 void DeleteRefToAnonymousNode(ManualNACPtr aContent
, PresShell
* aPresShell
);
4045 * RefreshEditingUI() may refresh editing UIs for current Selection, focus,
4046 * etc. If this shows or hides some UIs, it causes reflow. So, this is
4049 MOZ_CAN_RUN_SCRIPT nsresult
RefreshEditingUI();
4052 * Returns the offset of an element's frame to its absolute containing block.
4054 nsresult
GetElementOrigin(Element
& aElement
, int32_t& aX
, int32_t& aY
);
4055 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetPositionAndDimensions(
4056 Element
& aElement
, int32_t& aX
, int32_t& aY
, int32_t& aW
, int32_t& aH
,
4057 int32_t& aBorderLeft
, int32_t& aBorderTop
, int32_t& aMarginLeft
,
4058 int32_t& aMarginTop
);
4060 bool IsInObservedSubtree(nsIContent
* aChild
);
4062 void UpdateRootElement();
4065 * SetAllResizersPosition() moves all resizers to proper position.
4066 * If the resizers are hidden or replaced with another set of resizers
4067 * while this is running, this returns error. So, callers shouldn't
4068 * keep handling the resizers if this returns error.
4070 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetAllResizersPosition();
4073 * Shows active resizers around an element's frame
4074 * @param aResizedElement [IN] a DOM Element
4076 MOZ_CAN_RUN_SCRIPT nsresult
ShowResizersInternal(Element
& aResizedElement
);
4079 * Hide resizers if they are visible. If this is called while there is no
4080 * visible resizers, this does not return error, but does nothing.
4082 nsresult
HideResizersInternal();
4085 * RefreshResizersInternal() moves resizers to proper position. This does
4086 * nothing if there is no resizing target.
4088 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
RefreshResizersInternal();
4090 ManualNACPtr
CreateResizer(int16_t aLocation
, nsIContent
& aParentContent
);
4091 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4092 SetAnonymousElementPositionWithoutTransaction(nsStyledElement
& aStyledElement
,
4093 int32_t aX
, int32_t aY
);
4095 ManualNACPtr
CreateShadow(nsIContent
& aParentContent
,
4096 Element
& aOriginalObject
);
4099 * SetShadowPosition() moves the shadow element to proper position.
4101 * @param aShadowElement Must be mResizingShadow or mPositioningShadow.
4102 * @param aElement The element which has the shadow.
4103 * @param aElementX Left of aElement.
4104 * @param aElementY Top of aElement.
4106 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4107 SetShadowPosition(Element
& aShadowElement
, Element
& aElement
,
4108 int32_t aElementLeft
, int32_t aElementTop
);
4110 ManualNACPtr
CreateResizingInfo(nsIContent
& aParentContent
);
4111 MOZ_CAN_RUN_SCRIPT nsresult
SetResizingInfoPosition(int32_t aX
, int32_t aY
,
4112 int32_t aW
, int32_t aH
);
4114 enum class ResizeAt
{
4120 [[nodiscard
]] int32_t GetNewResizingIncrement(int32_t aX
, int32_t aY
,
4121 ResizeAt aResizeAt
) const;
4123 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
StartResizing(Element
& aHandle
);
4124 int32_t GetNewResizingX(int32_t aX
, int32_t aY
);
4125 int32_t GetNewResizingY(int32_t aX
, int32_t aY
);
4126 int32_t GetNewResizingWidth(int32_t aX
, int32_t aY
);
4127 int32_t GetNewResizingHeight(int32_t aX
, int32_t aY
);
4128 void HideShadowAndInfo();
4129 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4130 SetFinalSizeWithTransaction(int32_t aX
, int32_t aY
);
4131 void SetResizeIncrements(int32_t aX
, int32_t aY
, int32_t aW
, int32_t aH
,
4132 bool aPreserveRatio
);
4135 * HideAnonymousEditingUIs() forcibly hides all editing UIs (resizers,
4136 * inline-table-editing UI, absolute positioning UI).
4138 void HideAnonymousEditingUIs();
4141 * HideAnonymousEditingUIsIfUnnecessary() hides all editing UIs if some of
4142 * visible UIs are now unnecessary.
4144 void HideAnonymousEditingUIsIfUnnecessary();
4147 * sets the z-index of an element.
4148 * @param aElement [IN] the element
4149 * @param aZorder [IN] the z-index
4151 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4152 SetZIndexWithTransaction(nsStyledElement
& aElement
, int32_t aZIndex
);
4155 * shows a grabber attached to an arbitrary element. The grabber is an image
4156 * positioned on the left hand side of the top border of the element. Draggin
4157 * and dropping it allows to change the element's absolute position in the
4158 * document. See chrome://editor/content/images/grabber.gif
4159 * @param aElement [IN] the element
4161 MOZ_CAN_RUN_SCRIPT nsresult
ShowGrabberInternal(Element
& aElement
);
4164 * Setting grabber to proper position for current mAbsolutelyPositionedObject.
4165 * For example, while an element has grabber, the element may be resized
4166 * or repositioned by script or something. Then, you need to reset grabber
4167 * position with this.
4169 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
RefreshGrabberInternal();
4172 * hide the grabber if it shown.
4174 void HideGrabberInternal();
4177 * CreateGrabberInternal() creates a grabber for moving aParentContent.
4178 * This sets mGrabber to the new grabber. If this returns true, it's
4179 * always non-nullptr. Otherwise, i.e., the grabber is hidden during
4180 * creation, this returns false.
4182 bool CreateGrabberInternal(nsIContent
& aParentContent
);
4184 MOZ_CAN_RUN_SCRIPT nsresult
StartMoving();
4185 MOZ_CAN_RUN_SCRIPT nsresult
SetFinalPosition(int32_t aX
, int32_t aY
);
4186 void SnapToGrid(int32_t& newX
, int32_t& newY
) const;
4187 nsresult
GrabberClicked();
4188 MOZ_CAN_RUN_SCRIPT nsresult
EndMoving();
4189 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4190 GetTemporaryStyleForFocusedPositionedElement(Element
& aElement
,
4191 nsAString
& aReturn
);
4194 * Shows inline table editing UI around a <table> element which contains
4195 * aCellElement. This returns error if creating UI is hidden during this,
4196 * or detects another set of UI during this. In such case, callers
4197 * shouldn't keep handling anything for the UI.
4199 * @param aCellElement Must be an <td> or <th> element.
4201 MOZ_CAN_RUN_SCRIPT nsresult
4202 ShowInlineTableEditingUIInternal(Element
& aCellElement
);
4205 * Hide all inline table editing UI.
4207 void HideInlineTableEditingUIInternal();
4210 * RefreshInlineTableEditingUIInternal() moves inline table editing UI to
4211 * proper position. This returns error if the UI is hidden or replaced
4214 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4215 RefreshInlineTableEditingUIInternal();
4217 enum class ContentNodeIs
{ Inserted
, Appended
};
4218 MOZ_CAN_RUN_SCRIPT
void DoContentInserted(nsIContent
* aChild
,
4219 ContentNodeIs aContentNodeIs
);
4222 * Returns an anonymous Element of type aTag,
4223 * child of aParentContent. If aIsCreatedHidden is true, the class
4224 * "hidden" is added to the created element. If aAnonClass is not
4225 * the empty string, it becomes the value of the attribute "_moz_anonclass"
4227 * @param aTag [IN] desired type of the element to create
4228 * @param aParentContent [IN] the parent node of the created anonymous
4230 * @param aAnonClass [IN] contents of the _moz_anonclass attribute
4231 * @param aIsCreatedHidden [IN] a boolean specifying if the class "hidden"
4232 * is to be added to the created anonymous
4235 ManualNACPtr
CreateAnonymousElement(nsAtom
* aTag
, nsIContent
& aParentContent
,
4236 const nsAString
& aAnonClass
,
4237 bool aIsCreatedHidden
);
4240 * Reads a blob into memory and notifies the BlobReader object when the read
4241 * operation is finished.
4243 * @param aBlob The input blob
4244 * @param aGlobal The global object under which the read should happen.
4245 * @param aBlobReader The blob reader object to be notified when finished.
4247 static nsresult
SlurpBlob(dom::Blob
* aBlob
, nsIGlobalObject
* aGlobal
,
4248 BlobReader
* aBlobReader
);
4251 * OnModifyDocumentInternal() is called by OnModifyDocument().
4253 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
OnModifyDocumentInternal();
4256 * For saving allocation cost in the constructor of
4257 * EditorBase::TopLevelEditSubActionData, we should reuse same RangeItem
4258 * instance with all top level edit sub actions.
4259 * The instance is always cleared when TopLevelEditSubActionData is
4260 * destructed and the class is stack only class so that we don't need
4261 * to (and also should not) add the RangeItem into the cycle collection.
4263 [[nodiscard
]] inline already_AddRefed
<RangeItem
>
4264 GetSelectedRangeItemForTopLevelEditSubAction() const;
4267 * For saving allocation cost in the constructor of
4268 * EditorBase::TopLevelEditSubActionData, we should reuse same nsRange
4269 * instance with all top level edit sub actions.
4270 * The instance is always cleared when TopLevelEditSubActionData is
4271 * destructed, but AbstractRange::mOwner keeps grabbing the owner document
4272 * so that we need to make it in the cycle collection.
4274 [[nodiscard
]] inline already_AddRefed
<nsRange
>
4275 GetChangedRangeForTopLevelEditSubAction() const;
4277 MOZ_CAN_RUN_SCRIPT
void DidDoTransaction(
4278 TransactionManager
& aTransactionManager
, nsITransaction
& aTransaction
,
4279 nsresult aDoTransactionResult
) {
4280 if (mComposerCommandsUpdater
) {
4281 RefPtr
<ComposerCommandsUpdater
> updater(mComposerCommandsUpdater
);
4282 updater
->DidDoTransaction(aTransactionManager
);
4286 MOZ_CAN_RUN_SCRIPT
void DidUndoTransaction(
4287 TransactionManager
& aTransactionManager
, nsITransaction
& aTransaction
,
4288 nsresult aUndoTransactionResult
) {
4289 if (mComposerCommandsUpdater
) {
4290 RefPtr
<ComposerCommandsUpdater
> updater(mComposerCommandsUpdater
);
4291 updater
->DidUndoTransaction(aTransactionManager
);
4295 MOZ_CAN_RUN_SCRIPT
void DidRedoTransaction(
4296 TransactionManager
& aTransactionManager
, nsITransaction
& aTransaction
,
4297 nsresult aRedoTransactionResult
) {
4298 if (mComposerCommandsUpdater
) {
4299 RefPtr
<ComposerCommandsUpdater
> updater(mComposerCommandsUpdater
);
4300 updater
->DidRedoTransaction(aTransactionManager
);
4306 * IndentListChildWithTransaction() is a helper method of
4307 * Handle(CSS|HTML)IndentAtSelectionInternal().
4309 * @param aSubListElement [in/out] Specify a sub-list element of the
4310 * container of aPointInListElement or nullptr.
4311 * When there is no proper sub-list element to
4312 * move aContentMovingToSubList, this method
4313 * inserts a new sub-list element and update this
4315 * @param aPointInListElement A point in a list element whose child should
4316 * be indented. If this method creates new list
4317 * element into the list element, this inserts
4318 * the new list element to this point.
4319 * @param aContentMovingToSubList
4320 * A content node which is a child of a list
4321 * element and should be moved into a sub-list
4323 * @param aEditingHost The editing host.
4324 * @return A candidate caret position.
4326 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
4327 IndentListChildWithTransaction(RefPtr
<Element
>* aSubListElement
,
4328 const EditorDOMPoint
& aPointInListElement
,
4329 nsIContent
& aContentMovingToSubList
,
4330 const Element
& aEditingHost
);
4333 * Stack based helper class for saving/restoring selection. Note that this
4334 * assumes that the nodes involved are still around afterwords!
4336 class AutoSelectionRestorer final
{
4338 AutoSelectionRestorer() = delete;
4339 explicit AutoSelectionRestorer(const AutoSelectionRestorer
& aOther
) =
4341 AutoSelectionRestorer(AutoSelectionRestorer
&& aOther
) = delete;
4344 * Constructor responsible for remembering all state needed to restore
4346 * XXX This constructor and the destructor should be marked as
4347 * `MOZ_CAN_RUN_SCRIPT`, but it's impossible due to this may be used
4350 MOZ_CAN_RUN_SCRIPT_BOUNDARY
explicit AutoSelectionRestorer(
4351 HTMLEditor
& aHTMLEditor
);
4354 * Destructor restores mSelection to its former state
4356 MOZ_CAN_RUN_SCRIPT_BOUNDARY
~AutoSelectionRestorer();
4359 * Abort() cancels to restore the selection.
4363 bool MaybeRestoreSelectionLater() const { return !!mHTMLEditor
; }
4366 // The lifetime must be guaranteed by the creator of this instance.
4367 MOZ_KNOWN_LIVE HTMLEditor
* mHTMLEditor
= nullptr;
4371 * Stack based helper class for calling EditorBase::EndTransactionInternal().
4372 * NOTE: This does not suppress multiple input events. In most cases,
4373 * only one "input" event should be fired for an edit action rather
4374 * than per edit sub-action. In such case, you should use
4375 * EditorBase::AutoPlaceholderBatch instead.
4377 class MOZ_RAII AutoTransactionBatch final
{
4380 * @param aRequesterFuncName function name which wants to end the batch.
4381 * This won't be stored nor exposed to selection listeners etc, used only
4382 * for logging. This MUST be alive when the destructor runs.
4384 MOZ_CAN_RUN_SCRIPT
explicit AutoTransactionBatch(
4385 HTMLEditor
& aHTMLEditor
, const char* aRequesterFuncName
)
4386 : mHTMLEditor(aHTMLEditor
), mRequesterFuncName(aRequesterFuncName
) {
4387 MOZ_KnownLive(mHTMLEditor
).BeginTransactionInternal(mRequesterFuncName
);
4390 MOZ_CAN_RUN_SCRIPT
~AutoTransactionBatch() {
4391 MOZ_KnownLive(mHTMLEditor
).EndTransactionInternal(mRequesterFuncName
);
4395 // The lifetime must be guaranteed by the creator of this instance.
4396 MOZ_KNOWN_LIVE HTMLEditor
& mHTMLEditor
;
4397 const char* const mRequesterFuncName
;
4400 RefPtr
<PendingStyles
> mPendingStylesToApplyToNewContent
;
4401 RefPtr
<ComposerCommandsUpdater
> mComposerCommandsUpdater
;
4403 // Used by TopLevelEditSubActionData::mSelectedRange.
4404 mutable RefPtr
<RangeItem
> mSelectedRangeForTopLevelEditSubAction
;
4405 // Used by TopLevelEditSubActionData::mChangedRange.
4406 mutable RefPtr
<nsRange
> mChangedRangeForTopLevelEditSubAction
;
4408 RefPtr
<Runnable
> mPendingRootElementUpdatedRunner
;
4409 RefPtr
<Runnable
> mPendingDocumentModifiedRunner
;
4411 // mPaddingBRElementForEmptyEditor should be used for placing caret
4412 // at proper position when editor is empty.
4413 RefPtr
<dom::HTMLBRElement
> mPaddingBRElementForEmptyEditor
;
4415 bool mCRInParagraphCreatesParagraph
;
4418 bool mIsObjectResizingEnabled
;
4420 bool mPreserveRatio
;
4421 bool mResizedObjectIsAnImage
;
4423 // absolute positioning
4424 bool mIsAbsolutelyPositioningEnabled
;
4425 bool mResizedObjectIsAbsolutelyPositioned
;
4426 bool mGrabberClicked
;
4429 bool mSnapToGridEnabled
;
4431 // inline table editing
4432 bool mIsInlineTableEditingEnabled
;
4434 bool mIsCSSPrefChecked
;
4437 ManualNACPtr mTopLeftHandle
;
4438 ManualNACPtr mTopHandle
;
4439 ManualNACPtr mTopRightHandle
;
4440 ManualNACPtr mLeftHandle
;
4441 ManualNACPtr mRightHandle
;
4442 ManualNACPtr mBottomLeftHandle
;
4443 ManualNACPtr mBottomHandle
;
4444 ManualNACPtr mBottomRightHandle
;
4446 RefPtr
<Element
> mActivatedHandle
;
4448 ManualNACPtr mResizingShadow
;
4449 ManualNACPtr mResizingInfo
;
4451 RefPtr
<Element
> mResizedObject
;
4456 int32_t mResizedObjectX
;
4457 int32_t mResizedObjectY
;
4458 int32_t mResizedObjectWidth
;
4459 int32_t mResizedObjectHeight
;
4461 int32_t mResizedObjectMarginLeft
;
4462 int32_t mResizedObjectMarginTop
;
4463 int32_t mResizedObjectBorderLeft
;
4464 int32_t mResizedObjectBorderTop
;
4466 int32_t mXIncrementFactor
;
4467 int32_t mYIncrementFactor
;
4468 int32_t mWidthIncrementFactor
;
4469 int32_t mHeightIncrementFactor
;
4471 int8_t mInfoXIncrement
;
4472 int8_t mInfoYIncrement
;
4474 // absolute positioning
4475 int32_t mPositionedObjectX
;
4476 int32_t mPositionedObjectY
;
4477 int32_t mPositionedObjectWidth
;
4478 int32_t mPositionedObjectHeight
;
4480 int32_t mPositionedObjectMarginLeft
;
4481 int32_t mPositionedObjectMarginTop
;
4482 int32_t mPositionedObjectBorderLeft
;
4483 int32_t mPositionedObjectBorderTop
;
4485 RefPtr
<Element
> mAbsolutelyPositionedObject
;
4486 ManualNACPtr mGrabber
;
4487 ManualNACPtr mPositioningShadow
;
4491 // inline table editing
4492 RefPtr
<Element
> mInlineEditedCell
;
4494 ManualNACPtr mAddColumnBeforeButton
;
4495 ManualNACPtr mRemoveColumnButton
;
4496 ManualNACPtr mAddColumnAfterButton
;
4498 ManualNACPtr mAddRowBeforeButton
;
4499 ManualNACPtr mRemoveRowButton
;
4500 ManualNACPtr mAddRowAfterButton
;
4502 void AddMouseClickListener(Element
* aElement
);
4503 void RemoveMouseClickListener(Element
* aElement
);
4505 bool mDisabledLinkHandling
= false;
4506 bool mOldLinkHandlingEnabled
= false;
4508 bool mHasBeforeInputBeenCanceled
= false;
4510 ParagraphSeparator mDefaultParagraphSeparator
;
4512 friend class AlignStateAtSelection
; // CollectEditableTargetNodes,
4513 // CollectNonEditableNodes
4514 friend class AutoRangeArray
; // RangeUpdaterRef, SplitNodeWithTransaction,
4515 // SplitInlineAncestorsAtRangeBoundaries
4516 friend class AutoSelectionSetterAfterTableEdit
; // SetSelectionAfterEdit
4518 AutoSetTemporaryAncestorLimiter
; // InitializeSelectionAncestorLimit
4519 friend class CSSEditUtils
; // DoTransactionInternal, HasAttributes,
4520 // RemoveContainerWithTransaction
4521 friend class EditorBase
; // ComputeTargetRanges,
4522 // GetChangedRangeForTopLevelEditSubAction,
4523 // GetSelectedRangeItemForTopLevelEditSubAction,
4524 // MaybeCreatePaddingBRElementForEmptyEditor,
4525 // PrepareToInsertBRElement,
4526 // ReflectPaddingBRElementForEmptyEditor,
4527 // RefreshEditingUI,
4528 // RemoveEmptyInclusiveAncestorInlineElements,
4529 // mComposerUpdater, mHasBeforeInputBeenCanceled
4530 friend class JoinNodesTransaction
; // DidJoinNodesTransaction, DoJoinNodes,
4531 // DoSplitNode, // RangeUpdaterRef
4532 friend class ListElementSelectionState
; // CollectEditTargetNodes,
4533 // CollectNonEditableNodes
4534 friend class ListItemElementSelectionState
; // CollectEditTargetNodes,
4535 // CollectNonEditableNodes
4536 friend class MoveNodeTransaction
; // AllowsTransactionsToChangeSelection,
4537 // CollapseSelectionTo, MarkElementDirty,
4539 friend class ParagraphStateAtSelection
; // CollectChildren,
4540 // CollectEditTargetNodes,
4541 // CollectListChildren,
4542 // CollectNonEditableNodes,
4543 // CollectTableChildren
4544 friend class SlurpBlobEventListener
; // BlobReader
4545 friend class SplitNodeTransaction
; // DoJoinNodes, DoSplitNode
4546 friend class TransactionManager
; // DidDoTransaction, DidRedoTransaction,
4547 // DidUndoTransaction
4549 WhiteSpaceVisibilityKeeper
; // AutoMoveOneLineHandler
4551 // ChangeListElementType,
4552 // DeleteNodeWithTransaction,
4553 // DeleteTextAndTextNodesWithTransaction,
4554 // JoinNearestEditableNodesWithTransaction,
4555 // MoveChildrenWithTransaction,
4556 // SplitAncestorStyledInlineElementsAt,
4557 // TreatEmptyTextNodes
4561 * ListElementSelectionState class gets which list element is selected right
4564 class MOZ_STACK_CLASS ListElementSelectionState final
{
4566 ListElementSelectionState() = delete;
4567 ListElementSelectionState(HTMLEditor
& aHTMLEditor
, ErrorResult
& aRv
);
4569 bool IsOLElementSelected() const { return mIsOLElementSelected
; }
4570 bool IsULElementSelected() const { return mIsULElementSelected
; }
4571 bool IsDLElementSelected() const { return mIsDLElementSelected
; }
4572 bool IsNotOneTypeListElementSelected() const {
4573 return (mIsOLElementSelected
+ mIsULElementSelected
+ mIsDLElementSelected
+
4574 mIsOtherContentSelected
) > 1;
4578 bool mIsOLElementSelected
= false;
4579 bool mIsULElementSelected
= false;
4580 bool mIsDLElementSelected
= false;
4581 bool mIsOtherContentSelected
= false;
4585 * ListItemElementSelectionState class gets which list item element is selected
4588 class MOZ_STACK_CLASS ListItemElementSelectionState final
{
4590 ListItemElementSelectionState() = delete;
4591 ListItemElementSelectionState(HTMLEditor
& aHTMLEditor
, ErrorResult
& aRv
);
4593 bool IsLIElementSelected() const { return mIsLIElementSelected
; }
4594 bool IsDTElementSelected() const { return mIsDTElementSelected
; }
4595 bool IsDDElementSelected() const { return mIsDDElementSelected
; }
4596 bool IsNotOneTypeDefinitionListItemElementSelected() const {
4597 return (mIsDTElementSelected
+ mIsDDElementSelected
+
4598 mIsOtherElementSelected
) > 1;
4602 bool mIsLIElementSelected
= false;
4603 bool mIsDTElementSelected
= false;
4604 bool mIsDDElementSelected
= false;
4605 bool mIsOtherElementSelected
= false;
4609 * AlignStateAtSelection class gets alignment at selection.
4610 * XXX This currently returns only first alignment.
4612 class MOZ_STACK_CLASS AlignStateAtSelection final
{
4614 AlignStateAtSelection() = delete;
4615 MOZ_CAN_RUN_SCRIPT
AlignStateAtSelection(HTMLEditor
& aHTMLEditor
,
4618 nsIHTMLEditor::EAlignment
AlignmentAtSelectionStart() const {
4621 bool IsSelectionRangesFound() const { return mFoundSelectionRanges
; }
4624 nsIHTMLEditor::EAlignment mFirstAlign
= nsIHTMLEditor::eLeft
;
4625 bool mFoundSelectionRanges
= false;
4629 * ParagraphStateAtSelection class gets format block types around selection.
4631 class MOZ_STACK_CLASS ParagraphStateAtSelection final
{
4633 using FormatBlockMode
= HTMLEditor::FormatBlockMode
;
4635 ParagraphStateAtSelection() = delete;
4637 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4638 * paragraphState command.
4640 ParagraphStateAtSelection(HTMLEditor
& aHTMLEditor
,
4641 FormatBlockMode aFormatBlockMode
, ErrorResult
& aRv
);
4644 * GetFirstParagraphStateAtSelection() returns:
4645 * - nullptr if there is no format blocks nor inline nodes.
4646 * - nsGkAtoms::_empty if first node is not in any format block.
4647 * - a tag name of format block at first node.
4648 * XXX See the private method explanations. If selection ranges contains
4649 * non-format block first, it'll be check after its siblings. Therefore,
4650 * this may return non-first paragraph state.
4652 nsAtom
* GetFirstParagraphStateAtSelection() const {
4653 return mIsMixed
&& mIsInDLElement
? nsGkAtoms::dl
4654 : mFirstParagraphState
.get();
4658 * If selected nodes are not in same format node nor only in no-format blocks,
4659 * this returns true.
4661 bool IsMixed() const { return mIsMixed
&& !mIsInDLElement
; }
4664 using EditorType
= EditorBase::EditorType
;
4666 [[nodiscard
]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode
,
4667 const nsIContent
& aContent
);
4670 * AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
4671 * format blocks and first inline child node in aNonFormatBlockElement to
4672 * the last of the array (not inserting where aNonFormatBlockElement is,
4673 * so that the node order becomes randomly).
4675 * @param aArrayOfContents [in/out] Found descendant format blocks
4676 * and first inline node in each non-format
4677 * block will be appended to this.
4678 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4679 * paragraphState command.
4680 * @param aNonFormatBlockElement Must be a non-format block element.
4682 static void AppendDescendantFormatNodesAndFirstInlineNode(
4683 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
4684 FormatBlockMode aFormatBlockMode
, dom::Element
& aNonFormatBlockElement
);
4687 * CollectEditableFormatNodesInSelection() collects only editable nodes
4688 * around selection ranges (with `AutoRangeArray::ExtendRangesToWrapLines()`
4689 * and `HTMLEditor::CollectEditTargetNodes()`, see its document for the
4690 * detail). If it includes list, list item or table related elements, they
4691 * will be replaced their children.
4693 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4694 * paragraphState command.
4696 static nsresult
CollectEditableFormatNodesInSelection(
4697 HTMLEditor
& aHTMLEditor
, FormatBlockMode aFormatBlockMode
,
4698 const dom::Element
& aEditingHost
,
4699 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
);
4701 RefPtr
<nsAtom
> mFirstParagraphState
;
4702 bool mIsInDLElement
= false;
4703 bool mIsMixed
= false;
4706 } // namespace mozilla
4708 mozilla::HTMLEditor
* nsIEditor::AsHTMLEditor() {
4709 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4710 return static_cast<mozilla::HTMLEditor
*>(this);
4713 const mozilla::HTMLEditor
* nsIEditor::AsHTMLEditor() const {
4714 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4715 return static_cast<const mozilla::HTMLEditor
*>(this);
4718 mozilla::HTMLEditor
* nsIEditor::GetAsHTMLEditor() {
4719 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4722 const mozilla::HTMLEditor
* nsIEditor::GetAsHTMLEditor() const {
4723 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4726 #endif // #ifndef mozilla_HTMLEditor_h