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
;
42 class nsStyledElement
;
43 class nsTableCellFrame
;
44 class nsTableWrapperFrame
;
49 class AlignStateAtSelection
;
50 class AutoSelectionSetterAfterTableEdit
;
51 class EmptyEditableFunctor
;
52 class ListElementSelectionState
;
53 class ListItemElementSelectionState
;
54 class ParagraphStateAtSelection
;
55 class ResizerSelectionListener
;
62 class DocumentFragment
;
72 enum class ParagraphSeparator
{ div
, p
, br
};
75 * The HTML editor implementation.<br>
76 * Use to edit HTML document represented as a DOM tree.
78 class HTMLEditor final
: public EditorBase
,
80 public nsIHTMLObjectResizer
,
81 public nsIHTMLAbsPosEditor
,
82 public nsITableEditor
,
83 public nsIHTMLInlineTableEditor
,
84 public nsStubMutationObserver
,
85 public nsIEditorMailSupport
{
87 /****************************************************************************
88 * NOTE: DO NOT MAKE YOUR NEW METHODS PUBLIC IF they are called by other
89 * classes under libeditor except EditorEventListener and
90 * HTMLEditorEventListener because each public method which may fire
91 * eEditorInput event will need to instantiate new stack class for
92 * managing input type value of eEditorInput and cache some objects
93 * for smarter handling. In other words, when you add new root
94 * method to edit the DOM tree, you can make your new method public.
95 ****************************************************************************/
97 NS_DECL_ISUPPORTS_INHERITED
98 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditor
, EditorBase
)
100 // nsStubMutationObserver overrides
101 NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
102 NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
103 NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
104 NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
106 // nsIHTMLEditor methods
107 NS_DECL_NSIHTMLEDITOR
109 // nsIHTMLObjectResizer methods (implemented in HTMLObjectResizer.cpp)
110 NS_DECL_NSIHTMLOBJECTRESIZER
112 // nsIHTMLAbsPosEditor methods (implemented in HTMLAbsPositionEditor.cpp)
113 NS_DECL_NSIHTMLABSPOSEDITOR
115 // nsIHTMLInlineTableEditor methods (implemented in HTMLInlineTableEditor.cpp)
116 NS_DECL_NSIHTMLINLINETABLEEDITOR
118 // nsIEditorMailSupport methods
119 NS_DECL_NSIEDITORMAILSUPPORT
121 // nsITableEditor methods
122 NS_DECL_NSITABLEEDITOR
124 // nsISelectionListener overrides
125 NS_DECL_NSISELECTIONLISTENER
128 * @param aDocument The document whose content will be editable.
130 explicit HTMLEditor(const Document
& aDocument
);
133 * @param aDocument The document whose content will be editable.
134 * @param aComposerCommandsUpdater The composer command updater.
135 * @param aFlags Some of nsIEditor::eEditor*Mask flags.
137 MOZ_CAN_RUN_SCRIPT nsresult
138 Init(Document
& aDocument
, ComposerCommandsUpdater
& aComposerCommandsUpdater
,
142 * PostCreate() should be called after Init, and is the time that the editor
143 * tells its documentStateObservers that the document has been created.
145 MOZ_CAN_RUN_SCRIPT nsresult
PostCreate();
148 * PreDestroy() is called before the editor goes away, and gives the editor a
149 * chance to tell its documentStateObservers that the document is going away.
151 MOZ_CAN_RUN_SCRIPT
void PreDestroy();
153 static HTMLEditor
* GetFrom(nsIEditor
* aEditor
) {
154 return aEditor
? aEditor
->GetAsHTMLEditor() : nullptr;
156 static const HTMLEditor
* GetFrom(const nsIEditor
* aEditor
) {
157 return aEditor
? aEditor
->GetAsHTMLEditor() : nullptr;
160 [[nodiscard
]] bool GetReturnInParagraphCreatesNewParagraph() const;
162 // EditorBase overrides
163 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
BeginningOfDocument() final
;
164 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
EndOfDocument() final
;
166 NS_IMETHOD
GetDocumentCharacterSet(nsACString
& aCharacterSet
) final
;
167 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
168 SetDocumentCharacterSet(const nsACString
& aCharacterSet
) final
;
170 bool IsEmpty() const final
;
172 bool CanPaste(nsIClipboard::ClipboardType aClipboardType
) const final
;
173 using EditorBase::CanPaste
;
175 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
DeleteNode(nsINode
* aNode
,
176 bool aPreseveSelection
,
177 uint8_t aOptionalArgCount
) final
;
179 MOZ_CAN_RUN_SCRIPT NS_IMETHOD
InsertLineBreak() final
;
182 * PreHandleMouseDown() and PreHandleMouseUp() are called before
183 * HTMLEditorEventListener handles them. The coming event may be
184 * non-acceptable event.
186 void PreHandleMouseDown(const dom::MouseEvent
& aMouseDownEvent
);
187 void PreHandleMouseUp(const dom::MouseEvent
& aMouseUpEvent
);
190 * PreHandleSelectionChangeCommand() and PostHandleSelectionChangeCommand()
191 * are called before or after handling a command which may change selection
192 * and/or scroll position.
194 void PreHandleSelectionChangeCommand(Command aCommand
);
195 void PostHandleSelectionChangeCommand(Command aCommand
);
197 MOZ_CAN_RUN_SCRIPT nsresult
198 HandleKeyPressEvent(WidgetKeyboardEvent
* aKeyboardEvent
) final
;
199 Element
* GetFocusedElement() const final
;
200 bool IsActiveInDOMWindow() const final
;
201 dom::EventTarget
* GetDOMEventTarget() const final
;
202 [[nodiscard
]] Element
* FindSelectionRoot(const nsINode
& aNode
) const final
;
203 bool IsAcceptableInputEvent(WidgetGUIEvent
* aGUIEvent
) const final
;
204 nsresult
GetPreferredIMEState(widget::IMEState
* aState
) final
;
205 MOZ_CAN_RUN_SCRIPT nsresult
206 OnFocus(const nsINode
& aOriginalEventTargetNode
) final
;
207 nsresult
OnBlur(const dom::EventTarget
* aEventTarget
) final
;
210 * Called when aDocument or aElement becomes editable without focus change.
211 * E.g., when the design mode is enabled or the contenteditable attribute
212 * is set to the focused element.
214 MOZ_CAN_RUN_SCRIPT nsresult
FocusedElementOrDocumentBecomesEditable(
215 Document
& aDocument
, Element
* aElement
);
218 * Called when aDocument or aElement becomes not editable without focus
219 * change. E.g., when the design mode ends or the contenteditable attribute is
220 * removed or set to "false".
222 MOZ_CAN_RUN_SCRIPT
static nsresult
FocusedElementOrDocumentBecomesNotEditable(
223 HTMLEditor
* aHTMLEditor
, Document
& aDocument
, Element
* aElement
);
226 * GetBackgroundColorState() returns what the background color of the
229 * @param aMixed true if there is more than one font color
230 * @param aOutColor Color string. "" is returned for none.
232 MOZ_CAN_RUN_SCRIPT nsresult
GetBackgroundColorState(bool* aMixed
,
233 nsAString
& aOutColor
);
236 * PasteNoFormattingAsAction() pastes content in clipboard without any style
239 * @param aClipboardType nsIClipboard::kGlobalClipboard or
240 * nsIClipboard::kSelectionClipboard.
241 * @param aDispatchPasteEvent Yes if this should dispatch ePaste event
242 * before pasting. Otherwise, No.
243 * @param aDataTransfer The object containing the data to use for the
244 * paste operation. May be nullptr, in which case
245 * this will just get the data from the clipboard.
246 * @param aPrincipal Set subject principal if it may be called by
247 * JS. If set to nullptr, will be treated as
250 MOZ_CAN_RUN_SCRIPT nsresult
251 PasteNoFormattingAsAction(nsIClipboard::ClipboardType aClipboardType
,
252 DispatchPasteEvent aDispatchPasteEvent
,
253 DataTransfer
* aDataTransfer
= nullptr,
254 nsIPrincipal
* aPrincipal
= nullptr);
256 bool CanPasteTransferable(nsITransferable
* aTransferable
) final
;
258 MOZ_CAN_RUN_SCRIPT nsresult
259 InsertLineBreakAsAction(nsIPrincipal
* aPrincipal
= nullptr) final
;
262 * InsertParagraphSeparatorAsAction() is called when user tries to separate
263 * current paragraph with Enter key press in HTMLEditor or something.
265 * @param aPrincipal Set subject principal if it may be called by
266 * JS. If set to nullptr, will be treated as
269 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
270 InsertParagraphSeparatorAsAction(nsIPrincipal
* aPrincipal
= nullptr);
272 enum class InsertElementOption
{
273 // Delete selection if set, otherwise, insert aElement at start or end of
276 // Whether split all inline ancestors or not.
277 SplitAncestorInlineElements
,
279 using InsertElementOptions
= EnumSet
<InsertElementOption
>;
280 MOZ_CAN_RUN_SCRIPT nsresult
InsertElementAtSelectionAsAction(
281 Element
* aElement
, const InsertElementOptions aOptions
,
282 nsIPrincipal
* aPrincipal
= nullptr);
284 MOZ_CAN_RUN_SCRIPT nsresult
InsertLinkAroundSelectionAsAction(
285 Element
* aAnchorElement
, nsIPrincipal
* aPrincipal
= nullptr);
288 * CreateElementWithDefaults() creates new element whose name is
289 * aTagName with some default attributes are set. Note that this is a
290 * public utility method. I.e., just creates element, not insert it
292 * NOTE: This is available for internal use too since this does not change
293 * the DOM tree nor undo transactions, and does not refer Selection,
296 * @param aTagName The new element's tag name. If the name is
297 * one of "href", "anchor" or "namedanchor",
298 * this creates an <a> element.
299 * @return Newly created element.
301 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Element
> CreateElementWithDefaults(
302 const nsAtom
& aTagName
);
305 * Indent or outdent content around Selection.
307 * @param aPrincipal Set subject principal if it may be called by
308 * JS. If set to nullptr, will be treated as
311 MOZ_CAN_RUN_SCRIPT nsresult
312 IndentAsAction(nsIPrincipal
* aPrincipal
= nullptr);
313 MOZ_CAN_RUN_SCRIPT nsresult
314 OutdentAsAction(nsIPrincipal
* aPrincipal
= nullptr);
317 * The Document.execCommand("formatBlock") handler.
319 * @param aParagraphFormat Must not be an empty string, and the value must
320 * be one of address, article, aside, blockquote,
321 * div, footer, h1, h2, h3, h4, h5, h6, header,
322 * hgroup, main, nav, p, pre, selection, dt or dd.
324 MOZ_CAN_RUN_SCRIPT nsresult
FormatBlockAsAction(
325 const nsAString
& aParagraphFormat
, nsIPrincipal
* aPrincipal
= nullptr);
328 * The cmd_paragraphState command handler.
330 * @param aParagraphFormat Can be empty string. If this is empty string,
331 * this removes ancestor format elements.
332 * Otherwise, the value must be one of p, pre,
333 * h1, h2, h3, h4, h5, h6, address, dt or dl.
335 MOZ_CAN_RUN_SCRIPT nsresult
SetParagraphStateAsAction(
336 const nsAString
& aParagraphFormat
, nsIPrincipal
* aPrincipal
= nullptr);
338 MOZ_CAN_RUN_SCRIPT nsresult
AlignAsAction(const nsAString
& aAlignType
,
339 nsIPrincipal
* aPrincipal
= nullptr);
341 MOZ_CAN_RUN_SCRIPT nsresult
RemoveListAsAction(
342 const nsAString
& aListType
, nsIPrincipal
* aPrincipal
= nullptr);
345 * MakeOrChangeListAsAction() makes selected hard lines list element(s).
347 * @param aListElementTagName The new list element tag name. Must be
348 * nsGkAtoms::ul, nsGkAtoms::ol or
350 * @param aBulletType If this is not empty string, it's set
351 * to `type` attribute of new list item
352 * elements. Otherwise, existing `type`
353 * attributes will be removed.
354 * @param aSelectAllOfCurrentList Yes if this should treat all of
355 * ancestor list element at selection.
357 enum class SelectAllOfCurrentList
{ Yes
, No
};
358 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
MakeOrChangeListAsAction(
359 const nsStaticAtom
& aListElementTagName
, const nsAString
& aBulletType
,
360 SelectAllOfCurrentList aSelectAllOfCurrentList
,
361 nsIPrincipal
* aPrincipal
= nullptr);
364 * If aTargetElement is a resizer, start to drag the resizer. Otherwise, if
365 * aTargetElement is the grabber, start to handle drag gester on it.
367 * @param aMouseDownEvent A `mousedown` event fired on aTargetElement.
368 * @param aEventTargetElement The target element being pressed. This must
369 * be same as explicit original event target of
372 MOZ_CAN_RUN_SCRIPT nsresult
StartToDragResizerOrHandleDragGestureOnGrabber(
373 dom::MouseEvent
& aMouseDownEvent
, Element
& aEventTargetElement
);
376 * If the editor is handling dragging a resizer, handling drag gesture on
377 * the grabber or dragging the grabber, this finalize it. Otherwise,
380 * @param aClientPoint The final point of the drag.
382 MOZ_CAN_RUN_SCRIPT nsresult
383 StopDraggingResizerOrGrabberAt(const CSSIntPoint
& aClientPoint
);
386 * If the editor is handling dragging a resizer, handling drag gesture to
387 * start dragging the grabber or dragging the grabber, this method updates
390 * @param aClientPoint The new point of the drag.
392 MOZ_CAN_RUN_SCRIPT nsresult
393 UpdateResizerOrGrabberPositionTo(const CSSIntPoint
& aClientPoint
);
396 * IsCSSEnabled() returns true if this editor treats styles with style
397 * attribute of HTML elements. Otherwise, if this editor treats all styles
398 * with "font style elements" like <b>, <i>, etc, and <blockquote> to indent,
399 * align attribute to align contents, returns false.
401 bool IsCSSEnabled() const { return mIsCSSPrefChecked
; }
404 * Enable/disable object resizers for <img> elements, <table> elements,
405 * absolute positioned elements (required absolute position editor enabled).
407 MOZ_CAN_RUN_SCRIPT
void EnableObjectResizer(bool aEnable
) {
408 if (mIsObjectResizingEnabled
== aEnable
) {
412 AutoEditActionDataSetter
editActionData(
413 *this, EditAction::eEnableOrDisableResizer
);
414 if (NS_WARN_IF(!editActionData
.CanHandle())) {
418 mIsObjectResizingEnabled
= aEnable
;
421 bool IsObjectResizerEnabled() const { return mIsObjectResizingEnabled
; }
423 Element
* GetResizerTarget() const { return mResizedObject
; }
426 * Enable/disable inline table editor, e.g., adding new row or column,
427 * removing existing row or column.
429 MOZ_CAN_RUN_SCRIPT
void EnableInlineTableEditor(bool aEnable
) {
430 if (mIsInlineTableEditingEnabled
== aEnable
) {
434 AutoEditActionDataSetter
editActionData(
435 *this, EditAction::eEnableOrDisableInlineTableEditingUI
);
436 if (NS_WARN_IF(!editActionData
.CanHandle())) {
440 mIsInlineTableEditingEnabled
= aEnable
;
443 bool IsInlineTableEditorEnabled() const {
444 return mIsInlineTableEditingEnabled
;
448 * Enable/disable absolute position editor, resizing absolute positioned
449 * elements (required object resizers enabled) or positioning them with
452 MOZ_CAN_RUN_SCRIPT
void EnableAbsolutePositionEditor(bool aEnable
) {
453 if (mIsAbsolutelyPositioningEnabled
== aEnable
) {
457 AutoEditActionDataSetter
editActionData(
458 *this, EditAction::eEnableOrDisableAbsolutePositionEditor
);
459 if (NS_WARN_IF(!editActionData
.CanHandle())) {
463 mIsAbsolutelyPositioningEnabled
= aEnable
;
466 bool IsAbsolutePositionEditorEnabled() const {
467 return mIsAbsolutelyPositioningEnabled
;
471 * returns the deepest absolutely positioned container of the selection
472 * if it exists or null.
474 MOZ_CAN_RUN_SCRIPT already_AddRefed
<Element
>
475 GetAbsolutelyPositionedSelectionContainer() const;
477 Element
* GetPositionedElement() const { return mAbsolutelyPositionedObject
; }
480 * extracts the selection from the normal flow of the document and
483 * @param aEnabled [IN] true to absolutely position the selection,
484 * false to put it back in the normal flow
485 * @param aPrincipal Set subject principal if it may be called by
486 * JS. If set to nullptr, will be treated as
489 MOZ_CAN_RUN_SCRIPT nsresult
SetSelectionToAbsoluteOrStaticAsAction(
490 bool aEnabled
, nsIPrincipal
* aPrincipal
= nullptr);
493 * returns the absolute z-index of a positioned element. Never returns 'auto'
494 * @return the z-index of the element
495 * @param aElement [IN] the element.
497 MOZ_CAN_RUN_SCRIPT
int32_t GetZIndex(Element
& aElement
);
500 * adds aChange to the z-index of the currently positioned element.
502 * @param aChange [IN] relative change to apply to current z-index
503 * @param aPrincipal Set subject principal if it may be called by
504 * JS. If set to nullptr, will be treated as
507 MOZ_CAN_RUN_SCRIPT nsresult
508 AddZIndexAsAction(int32_t aChange
, nsIPrincipal
* aPrincipal
= nullptr);
510 MOZ_CAN_RUN_SCRIPT nsresult
SetBackgroundColorAsAction(
511 const nsAString
& aColor
, nsIPrincipal
* aPrincipal
= nullptr);
514 * SetInlinePropertyAsAction() sets a property which changes inline style of
515 * text. E.g., bold, italic, super and sub.
516 * This automatically removes exclusive style, however, treats all changes
519 * @param aPrincipal Set subject principal if it may be called by
520 * JS. If set to nullptr, will be treated as
523 MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertyAsAction(
524 nsStaticAtom
& aProperty
, nsStaticAtom
* aAttribute
,
525 const nsAString
& aValue
, nsIPrincipal
* aPrincipal
= nullptr);
528 * GetInlineProperty() gets aggregate properties of the current selection.
529 * All object in the current selection are scanned and their attributes are
530 * represented in a list of Property object.
531 * TODO: Make this return Result<Something> instead of bool out arguments.
533 * @param aHTMLProperty the property to get on the selection
534 * @param aAttribute the attribute of the property, if applicable.
536 * Example: aHTMLProperty=nsGkAtoms::font,
537 * aAttribute=nsGkAtoms::color
538 * @param aValue if aAttribute is not null, the value of the
539 * attribute. May be null.
540 * Example: aHTMLProperty=nsGkAtoms::font,
541 * aAttribute=nsGkAtoms::color,
543 * @param aFirst [OUT] true if the first text node in the
544 * selection has the property
545 * @param aAny [OUT] true if any of the text nodes in the
546 * selection have the property
547 * @param aAll [OUT] true if all of the text nodes in the
548 * selection have the property
550 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlineProperty(
551 nsStaticAtom
& aHTMLProperty
, nsAtom
* aAttribute
, const nsAString
& aValue
,
552 bool* aFirst
, bool* aAny
, bool* aAll
) const;
554 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlinePropertyWithAttrValue(
555 nsStaticAtom
& aHTMLProperty
, nsAtom
* aAttribute
, const nsAString
& aValue
,
556 bool* aFirst
, bool* aAny
, bool* aAll
, nsAString
& outValue
);
559 * RemoveInlinePropertyAsAction() removes a property which changes inline
560 * style of text. E.g., bold, italic, super and sub.
562 * @param aHTMLProperty Tag name whcih represents the inline style you want
563 * to remove. E.g., nsGkAtoms::strong, nsGkAtoms::b,
564 * etc. If nsGkAtoms::href, <a> element which has
565 * href attribute will be removed.
566 * If nsGkAtoms::name, <a> element which has non-empty
567 * name attribute will be removed.
568 * @param aAttribute If aHTMLProperty is nsGkAtoms::font, aAttribute should
569 * be nsGkAtoms::fase, nsGkAtoms::size, nsGkAtoms::color
570 * or nsGkAtoms::bgcolor. Otherwise, set nullptr.
571 * Must not use nsGkAtoms::_empty here.
572 * @param aPrincipal Set subject principal if it may be called by JS. If
573 * set to nullptr, will be treated as called by system.
575 MOZ_CAN_RUN_SCRIPT nsresult
RemoveInlinePropertyAsAction(
576 nsStaticAtom
& aHTMLProperty
, nsStaticAtom
* aAttribute
,
577 nsIPrincipal
* aPrincipal
= nullptr);
579 MOZ_CAN_RUN_SCRIPT nsresult
580 RemoveAllInlinePropertiesAsAction(nsIPrincipal
* aPrincipal
= nullptr);
582 MOZ_CAN_RUN_SCRIPT nsresult
583 IncreaseFontSizeAsAction(nsIPrincipal
* aPrincipal
= nullptr);
585 MOZ_CAN_RUN_SCRIPT nsresult
586 DecreaseFontSizeAsAction(nsIPrincipal
* aPrincipal
= nullptr);
589 * GetFontColorState() returns foreground color information in first
590 * range of Selection.
591 * If first range of Selection is collapsed and there is a cache of style for
592 * new text, aIsMixed is set to false and aColor is set to the cached color.
593 * If first range of Selection is collapsed and there is no cached color,
594 * this returns the color of the node, aIsMixed is set to false and aColor is
596 * If first range of Selection is not collapsed, this collects colors of
597 * each node in the range. If there are two or more colors, aIsMixed is set
598 * to true and aColor is truncated. If only one color is set to all of the
599 * range, aIsMixed is set to false and aColor is set to the color.
600 * If there is no Selection ranges, aIsMixed is set to false and aColor is
603 * @param aIsMixed Must not be nullptr. This is set to true
604 * if there is two or more colors in first
605 * range of Selection.
606 * @param aColor Returns the color if only one color is set to
607 * all of first range in Selection. Otherwise,
608 * returns empty string.
609 * @return Returns error only when illegal cases, e.g.,
610 * Selection instance has gone, first range
611 * Selection is broken.
613 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
614 GetFontColorState(bool* aIsMixed
, nsAString
& aColor
);
617 * Detach aComposerCommandsUpdater from this.
619 void Detach(const ComposerCommandsUpdater
& aComposerCommandsUpdater
);
621 nsStaticAtom
& DefaultParagraphSeparatorTagName() const {
622 return HTMLEditor::ToParagraphSeparatorTagName(mDefaultParagraphSeparator
);
624 ParagraphSeparator
GetDefaultParagraphSeparator() const {
625 return mDefaultParagraphSeparator
;
627 void SetDefaultParagraphSeparator(ParagraphSeparator aSep
) {
628 mDefaultParagraphSeparator
= aSep
;
630 static nsStaticAtom
& ToParagraphSeparatorTagName(
631 ParagraphSeparator aSeparator
) {
632 switch (aSeparator
) {
633 case ParagraphSeparator::div
:
634 return *nsGkAtoms::div
;
635 case ParagraphSeparator::p
:
636 return *nsGkAtoms::p
;
637 case ParagraphSeparator::br
:
638 return *nsGkAtoms::br
;
640 MOZ_ASSERT_UNREACHABLE("New paragraph separator isn't handled here");
641 return *nsGkAtoms::div
;
646 * Modifies the table containing the selection according to the
647 * activation of an inline table editing UI element
648 * @param aUIAnonymousElement [IN] the inline table editing UI element
650 MOZ_CAN_RUN_SCRIPT nsresult
651 DoInlineTableEditingAction(const Element
& aUIAnonymousElement
);
654 * GetInclusiveAncestorByTagName() looks for an element node whose name
655 * matches aTagName from aNode or anchor node of Selection to <body> element.
657 * @param aTagName The tag name which you want to look for.
658 * Must not be nsGkAtoms::_empty.
659 * If nsGkAtoms::list, the result may be <ul>, <ol> or
661 * If nsGkAtoms::td, the result may be <td> or <th>.
662 * If nsGkAtoms::href, the result may be <a> element
663 * which has "href" attribute with non-empty value.
664 * If nsGkAtoms::anchor, the result may be <a> which
665 * has "name" attribute with non-empty value.
666 * @param aContent Start node to look for the result.
667 * @return If an element which matches aTagName, returns
668 * an Element. Otherwise, nullptr.
670 Element
* GetInclusiveAncestorByTagName(const nsStaticAtom
& aTagName
,
671 nsIContent
& aContent
) const;
674 * Compute editing host for aContent. If this editor isn't active in the DOM
675 * window, this returns nullptr.
677 enum class LimitInBodyElement
{ No
, Yes
};
678 [[nodiscard
]] Element
* ComputeEditingHost(
679 const nsIContent
& aContent
,
680 LimitInBodyElement aLimitInBodyElement
= LimitInBodyElement::Yes
) const {
681 return ComputeEditingHostInternal(&aContent
, aLimitInBodyElement
);
685 * Compute editing host for the focus node of the Selection. If this editor
686 * isn't active in the DOM window, this returns nullptr.
688 [[nodiscard
]] Element
* ComputeEditingHost(
689 LimitInBodyElement aLimitInBodyElement
= LimitInBodyElement::Yes
) const {
690 return ComputeEditingHostInternal(nullptr, aLimitInBodyElement
);
694 * Return true if this editor was notified of focus, but has not been notified
697 [[nodiscard
]] bool HasFocus() const { return mHasFocus
; }
700 * Return true if this editor is in the designMode.
702 [[nodiscard
]] bool IsInDesignMode() const { return mIsInDesignMode
; }
705 * Return true if entire the document is editable (although the document
706 * may have non-editable nodes, e.g.,
707 * <body contenteditable><div contenteditable="false"></div></body>
709 bool EntireDocumentIsEditable() const;
712 * Basically, this always returns true if we're for `contenteditable` or
713 * `designMode` editor in web apps. However, e.g., Composer of SeaMonkey
714 * can make the editor not tabbable.
716 bool IsTabbable() const { return IsInteractionAllowed(); }
719 * NotifyEditingHostMaybeChanged() is called when new element becomes
720 * contenteditable when the document already had contenteditable elements.
722 void NotifyEditingHostMaybeChanged();
724 /** Insert a string as quoted text
725 * (whose representation is dependant on the editor type),
726 * replacing the selected text (if any).
728 * @param aQuotedText The actual text to be quoted
729 * @parem aNodeInserted Return the node which was inserted.
731 MOZ_CAN_RUN_SCRIPT
// USED_BY_COMM_CENTRAL
733 InsertAsQuotation(const nsAString
& aQuotedText
, nsINode
** aNodeInserted
);
735 MOZ_CAN_RUN_SCRIPT nsresult
InsertHTMLAsAction(
736 const nsAString
& aInString
, nsIPrincipal
* aPrincipal
= nullptr);
739 * Refresh positions of resizers. If you change size of target of resizers,
740 * you need to refresh position of resizers with calling this.
742 MOZ_CAN_RUN_SCRIPT nsresult
RefreshResizers();
744 bool IsWrapHackEnabled() const {
745 return (mFlags
& nsIEditor::eEditorEnableWrapHackMask
) != 0;
749 * Return true if this is in the plaintext mail composer mode of
750 * Thunderbird or something.
751 * NOTE: This is different from contenteditable="plaintext-only"
753 bool IsPlaintextMailComposer() const {
754 const bool isPlaintextMode
=
755 (mFlags
& nsIEditor::eEditorPlaintextMask
) != 0;
756 MOZ_ASSERT_IF(IsTextEditor(), isPlaintextMode
);
757 return isPlaintextMode
;
760 protected: // May be called by friends.
761 /****************************************************************************
762 * Some friend classes are allowed to call the following protected methods.
763 * However, those methods won't prepare caches of some objects which are
764 * necessary for them. So, if you call them from friend classes, you need
765 * to make sure that AutoEditActionDataSetter is created.
766 ****************************************************************************/
768 enum class LineBreakType
: bool {
770 Linefeed
, // Preformatted linefeed
772 friend std::ostream
& operator<<(std::ostream
& aStream
,
773 const LineBreakType aLineBreakType
) {
774 switch (aLineBreakType
) {
775 case LineBreakType::BRElement
:
776 return aStream
<< "LineBreakType::BRElement";
777 case LineBreakType::Linefeed
:
778 return aStream
<< "LineBreakType::BRElement";
780 MOZ_ASSERT_UNREACHABLE("Invalid LineBreakType");
785 * Return preferred line break when you insert a line break in aNode (if
786 * aNode is a Text node, this assumes that line break will be inserted to
787 * its parent element).
789 * @param aNode The node where you want to insert a line break.
790 * This should be a inclusive descendant of
791 * aEditingHost because if it's not connected, we can
792 * not refer the proper style information.
793 * @param aEditingHost The editing host.
795 Maybe
<LineBreakType
> GetPreferredLineBreakType(
796 const nsINode
& aNode
, const Element
& aEditingHost
) const;
799 * InsertLineBreak() creates a <br> element or a Text node which has only
800 * preformatted linefeed and inserts it at aPointToInsert.
802 * @param aWithTransaction Whether the inserting is new element is undoable
803 * or not. WithTransaction::No is useful only when
804 * the new element is inserted into a new element
805 * which has not been connected yet.
806 * @param aLineBreakType Whether a <br> element or a linefeed should be
808 * @param aPointToInsert The DOM point where a <br> element or a Text
809 * node should be inserted.
810 * @param aSelect If eNone, returns a point to put caret which is
811 * suggested by InsertNodeTransaction.
812 * If eNext, returns a point after the new <br>
814 * If ePrevious, returns a point at the new <br>
816 * @return The new <br> or Text node and suggesting point
817 * to put caret with respecting aSelect.
819 MOZ_CAN_RUN_SCRIPT Result
<CreateLineBreakResult
, nsresult
> InsertLineBreak(
820 WithTransaction aWithTransaction
, LineBreakType aLineBreakType
,
821 const EditorDOMPoint
& aPointToInsert
, EDirection aSelect
= eNone
);
824 * Delete text in the range in aTextNode. If aTextNode is not editable, this
827 * @param aTextNode The text node which should be modified.
828 * @param aOffset Start offset of removing text in aTextNode.
829 * @param aLength Length of removing text.
831 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
832 DeleteTextWithTransaction(dom::Text
& aTextNode
, uint32_t aOffset
,
836 * Replace text in the range with aStringToInsert. If there is a DOM range
837 * exactly same as the replacing range, it'll be collapsed to
838 * {aTextNode, aOffset} because of the order of deletion and insertion.
839 * Therefore, the callers may need to handle `Selection` even when callers
840 * do not want to update `Selection`.
842 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertTextResult
, nsresult
>
843 ReplaceTextWithTransaction(dom::Text
& aTextNode
, uint32_t aOffset
,
845 const nsAString
& aStringToInsert
);
848 * Insert aStringToInsert to aPointToInsert. If the point is not editable,
849 * this returns error.
851 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertTextResult
, nsresult
>
852 InsertTextWithTransaction(Document
& aDocument
,
853 const nsAString
& aStringToInsert
,
854 const EditorDOMPoint
& aPointToInsert
,
855 InsertTextTo aInsertTextTo
) final
;
858 * CopyLastEditableChildStyles() clones inline container elements into
859 * aPreviousBlock to aNewBlock to keep using same style in it.
861 * @param aPreviousBlock The previous block element. All inline
862 * elements which are last sibling of each level
863 * are cloned to aNewBlock.
864 * @param aNewBlock New block container element. All children of
865 * this is deleted first.
866 * @param aEditingHost The editing host.
867 * @return If succeeded, returns a suggesting point to put
870 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
871 CopyLastEditableChildStylesWithTransaction(Element
& aPreviousBlock
,
873 const Element
& aEditingHost
);
876 * RemoveBlockContainerWithTransaction() removes aElement from the DOM tree
877 * but moves its all children to its parent node and if its parent needs <br>
878 * element to have at least one line-height, this inserts <br> element
881 * @param aElement Block element to be removed.
882 * @return If succeeded, returns a suggesting point to put
885 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
886 RemoveBlockContainerWithTransaction(Element
& aElement
);
888 MOZ_CAN_RUN_SCRIPT nsresult
RemoveAttributeOrEquivalent(
889 Element
* aElement
, nsAtom
* aAttribute
, bool aSuppressTransaction
) final
;
890 MOZ_CAN_RUN_SCRIPT nsresult
SetAttributeOrEquivalent(
891 Element
* aElement
, nsAtom
* aAttribute
, const nsAString
& aValue
,
892 bool aSuppressTransaction
) final
;
893 using EditorBase::RemoveAttributeOrEquivalent
;
894 using EditorBase::SetAttributeOrEquivalent
;
897 * Returns container element of ranges in Selection. If Selection is
898 * collapsed, returns focus container node (or its parent element).
899 * If Selection selects only one element node, returns the element node.
900 * If Selection is only one range, returns common ancestor of the range.
901 * XXX If there are two or more Selection ranges, this returns parent node
902 * of start container of a range which starts with different node from
903 * start container of the first range.
905 Element
* GetSelectionContainerElement() const;
908 * DeleteTableCellContentsWithTransaction() removes any contents in cell
909 * elements. If two or more cell elements are selected, this removes
910 * all selected cells' contents. Otherwise, this removes contents of
911 * a cell which contains first selection range. This does not return
912 * error even if selection is not in cell element, just does nothing.
914 MOZ_CAN_RUN_SCRIPT nsresult
DeleteTableCellContentsWithTransaction();
917 * extracts an element from the normal flow of the document and
918 * positions it, and puts it back in the normal flow.
919 * @param aElement [IN] the element
920 * @param aEnabled [IN] true to absolutely position the element,
921 * false to put it back in the normal flow
923 MOZ_CAN_RUN_SCRIPT nsresult
SetPositionToAbsoluteOrStatic(Element
& aElement
,
927 * adds aChange to the z-index of an arbitrary element.
928 * @param aElement [IN] the element
929 * @param aChange [IN] relative change to apply to current z-index of
931 * @return The new z-index of the element
933 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<int32_t, nsresult
>
934 AddZIndexWithTransaction(nsStyledElement
& aStyledElement
, int32_t aChange
);
937 * Join together adjacent editable text nodes in the range except preformatted
938 * linefeed only nodes.
940 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
941 CollapseAdjacentTextNodes(nsRange
& aRange
);
943 static dom::Element
* GetLinkElement(nsINode
* aNode
);
946 * Helper routines for font size changing.
948 enum class FontSize
{ incr
, decr
};
949 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
950 SetFontSizeOnTextNode(Text
& aTextNode
, uint32_t aStartOffset
,
951 uint32_t aEndOffset
, FontSize aIncrementOrDecrement
);
953 enum class SplitAtEdges
{
954 // SplitNodeDeepWithTransaction() won't split container element
955 // nodes at their edges. I.e., when split point is start or end of
956 // container, it won't be split.
957 eDoNotCreateEmptyContainer
,
958 // SplitNodeDeepWithTransaction() always splits containers even
959 // if the split point is at edge of a container. E.g., if split point is
960 // start of an inline element, empty inline element is created as a new left
962 eAllowToCreateEmptyContainer
,
966 * SplitAncestorStyledInlineElementsAtRangeEdges() splits all ancestor inline
967 * elements in the block at aRange if given style matches with some of them.
969 * @param aRange Ancestor inline elements of the start and end
970 * boundaries will be split.
971 * @param aStyle The style which you want to split.
972 * RemoveAllStyles instance is allowed to split any
974 * @param aSplitAtEdges Whether this should split elements at start or
975 * end of inline elements or not.
977 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffResult
, nsresult
>
978 SplitAncestorStyledInlineElementsAtRangeEdges(const EditorDOMRange
& aRange
,
979 const EditorInlineStyle
& aStyle
,
980 SplitAtEdges aSplitAtEdges
);
983 * SplitAncestorStyledInlineElementsAt() splits ancestor inline elements at
984 * aPointToSplit if specified style matches with them.
986 * @param aPointToSplit The point to split style at.
987 * @param aStyle The style which you want to split.
988 * RemoveAllStyles instance is allowed to split any
990 * @param aSplitAtEdges Whether this should split elements at start or
991 * end of inline elements or not.
992 * @return The result of SplitNodeDeepWithTransaction()
993 * with topmost split element. If this didn't
994 * find inline elements to be split, Handled()
997 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
998 SplitAncestorStyledInlineElementsAt(const EditorDOMPoint
& aPointToSplit
,
999 const EditorInlineStyle
& aStyle
,
1000 SplitAtEdges aSplitAtEdges
);
1002 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlinePropertyBase(
1003 const EditorInlineStyle
& aStyle
, const nsAString
* aValue
, bool* aFirst
,
1004 bool* aAny
, bool* aAll
, nsAString
* outValue
) const;
1007 * ClearStyleAt() splits parent elements to remove the specified style.
1008 * If this splits some parent elements at near their start or end, such
1009 * empty elements will be removed. Then, remove the specified style
1010 * from the point and returns DOM point to put caret.
1012 * @param aPoint The point to clear style at.
1013 * @param aStyleToRemove The style which you want to clear.
1014 * @param aSpecifiedStyle Whether the class and style attributes should
1015 * be preserved or discarded.
1016 * @param aEditingHost The editing host.
1017 * @return A candidate position to put caret. If there is
1018 * AutoTransactionsConserveSelection instances, this stops
1019 * suggesting caret point only in some cases.
1021 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1022 ClearStyleAt(const EditorDOMPoint
& aPoint
,
1023 const EditorInlineStyle
& aStyleToRemove
,
1024 SpecifiedStyle aSpecifiedStyle
, const Element
& aEditingHost
);
1026 MOZ_CAN_RUN_SCRIPT nsresult
SetPositionToAbsolute(Element
& aElement
);
1027 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1028 SetPositionToStatic(Element
& aElement
);
1030 class DocumentModifiedEvent final
: public Runnable
{
1032 explicit DocumentModifiedEvent(HTMLEditor
& aHTMLEditor
)
1033 : Runnable("DocumentModifiedEvent"), mHTMLEditor(aHTMLEditor
) {}
1035 MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD
Run() {
1036 Unused
<< MOZ_KnownLive(mHTMLEditor
)->OnModifyDocument(*this);
1040 const nsTArray
<EditorDOMPointInText
>& NewInvisibleWhiteSpacesRef() const {
1041 return mNewInvisibleWhiteSpaces
;
1044 void MaybeAppendNewInvisibleWhiteSpace(
1045 const nsIContent
* aContentWillBeRemoved
);
1048 ~DocumentModifiedEvent() = default;
1050 const OwningNonNull
<HTMLEditor
> mHTMLEditor
;
1051 nsTArray
<EditorDOMPointInText
> mNewInvisibleWhiteSpaces
;
1055 * OnModifyDocument() is called when the editor is changed. This should
1056 * be called only by DocumentModifiedEvent when AutoEditActionDataSetter
1057 * instance is in the stack.
1059 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1060 OnModifyDocument(const DocumentModifiedEvent
& aRunner
);
1063 * DoSplitNode() inserts aNewNode and moves all content before or after
1064 * aStartOfRightNode to aNewNode.
1066 * @param aStartOfRightNode The point to split. The container will keep
1067 * having following or previous content of this.
1068 * @param aNewNode The new node called. The previous or following
1069 * content of aStartOfRightNode will be moved into
1072 MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
> DoSplitNode(
1073 const EditorDOMPoint
& aStartOfRightNode
, nsIContent
& aNewNode
);
1076 * DoJoinNodes() merges contents in aContentToRemove to aContentToKeep and
1077 * remove aContentToRemove from the DOM tree. aContentToRemove and
1078 * aContentToKeep must have same parent. Additionally, if one of
1079 * aContentToRemove or aContentToKeep is a text node, the other must be a
1082 * @param aContentToKeep The node that will remain after the join.
1083 * @param aContentToRemove The node that will be joined with aContentToKeep.
1084 * There is no requirement that the two nodes be of
1087 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1088 DoJoinNodes(nsIContent
& aContentToKeep
, nsIContent
& aContentToRemove
);
1091 * Called when JoinNodesTransaction::DoTransaction() did its transaction.
1092 * Note that this is not called when undoing nor redoing.
1094 * @param aTransaction The transaction which did join nodes.
1095 * @param aDoJoinNodesResult Result of the doing join nodes.
1097 MOZ_CAN_RUN_SCRIPT
void DidJoinNodesTransaction(
1098 const JoinNodesTransaction
& aTransaction
, nsresult aDoJoinNodesResult
);
1100 protected: // edit sub-action handler
1102 * CanHandleHTMLEditSubAction() checks whether there is at least one
1103 * selection range or not, and whether the first range is editable.
1104 * If it's not editable, `Canceled()` of the result returns true.
1105 * If `Selection` is in odd situation, returns an error.
1107 * XXX I think that `IsSelectionEditable()` is better name, but it's already
1108 * in `EditorBase`...
1110 enum class CheckSelectionInReplacedElement
{ Yes
, OnlyWhenNotInSameNode
};
1111 Result
<EditActionResult
, nsresult
> CanHandleHTMLEditSubAction(
1112 CheckSelectionInReplacedElement aCheckSelectionInReplacedElement
=
1113 CheckSelectionInReplacedElement::Yes
) const;
1116 * EnsureCaretNotAfterInvisibleBRElement() makes sure that caret is NOT after
1117 * padding `<br>` element for preventing insertion after padding `<br>`
1118 * element at empty last line.
1119 * NOTE: This method should be called only when `Selection` is collapsed
1120 * because `Selection` is a pain to work with when not collapsed.
1121 * (no good way to extend start or end of selection), so we need to
1122 * ignore those types of selections.
1124 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1125 EnsureCaretNotAfterInvisibleBRElement(const Element
& aEditingHost
);
1128 * MaybeCreatePaddingBRElementForEmptyEditor() creates padding <br> element
1129 * for empty editor if there is no children.
1131 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1132 MaybeCreatePaddingBRElementForEmptyEditor();
1135 * EnsureNoPaddingBRElementForEmptyEditor() removes padding <br> element
1136 * for empty editor if there is.
1138 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1139 EnsureNoPaddingBRElementForEmptyEditor();
1142 * ReflectPaddingBRElementForEmptyEditor() scans the tree from the root
1143 * element and sets mPaddingBRElementForEmptyEditor if exists, or otherwise
1144 * nullptr. Can be used to manage undo/redo.
1146 [[nodiscard
]] nsresult
ReflectPaddingBRElementForEmptyEditor();
1149 * PrepareInlineStylesForCaret() consider inline styles from top level edit
1150 * sub-action and setting it to `mPendingStylesToApplyToNewContent` and clear
1151 * inline style cache if necessary.
1152 * NOTE: This method should be called only when `Selection` is collapsed.
1154 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
PrepareInlineStylesForCaret();
1156 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
1157 HandleInsertText(EditSubAction aEditSubAction
,
1158 const nsAString
& aInsertionString
,
1159 SelectionHandling aSelectionHandling
) final
;
1161 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertDroppedDataTransferAsAction(
1162 AutoEditActionDataSetter
& aEditActionData
, DataTransfer
& aDataTransfer
,
1163 const EditorDOMPoint
& aDroppedAt
, nsIPrincipal
* aSourcePrincipal
) final
;
1166 * GetInlineStyles() retrieves the style of aElement and modifies each item of
1167 * aPendingStyleCacheArray. This might cause flushing layout at retrieving
1168 * computed values of CSS properties.
1170 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetInlineStyles(
1171 Element
& aElement
, AutoPendingStyleCacheArray
& aPendingStyleCacheArray
);
1174 * CacheInlineStyles() caches style of aElement into mCachedPendingStyles of
1175 * TopLevelEditSubAction. This may cause flushing layout at retrieving
1176 * computed value of CSS properties.
1178 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1179 CacheInlineStyles(Element
& aElement
);
1182 * ReapplyCachedStyles() restores some styles which are disappeared during
1183 * handling edit action and it should be restored. This may cause flushing
1184 * layout at retrieving computed value of CSS properties.
1186 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
ReapplyCachedStyles();
1189 * CreateStyleForInsertText() sets CSS properties which are stored in
1190 * PendingStyles to proper element node.
1192 * @param aPointToInsertText The point to insert text.
1193 * @param aEditingHost The editing host.
1194 * @return A suggest point to put caret or unset point.
1196 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1197 CreateStyleForInsertText(const EditorDOMPoint
& aPointToInsertText
,
1198 const Element
& aEditingHost
);
1201 * GetMostDistantAncestorMailCiteElement() returns most-ancestor mail cite
1202 * element. "mail cite element" is <pre> element when it's in plaintext editor
1203 * mode or an element with which calling HTMLEditUtils::IsMailCite() returns
1206 * @param aNode The start node to look for parent mail cite elements.
1208 Element
* GetMostDistantAncestorMailCiteElement(const nsINode
& aNode
) const;
1211 * HandleInsertParagraphInMailCiteElement() splits aMailCiteElement at
1214 * @param aMailCiteElement The mail-cite element which should be split.
1215 * @param aPointToSplit The point to split.
1216 * @return Candidate caret position where is at inserted
1217 * <br> element into the split point.
1219 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
1220 HandleInsertParagraphInMailCiteElement(Element
& aMailCiteElement
,
1221 const EditorDOMPoint
& aPointToSplit
);
1224 * HandleInsertBRElement() inserts a <br> element into aPointToBreak.
1225 * This may split container elements at the point and/or may move following
1226 * <br> element to immediately after the new <br> element if necessary.
1228 * @param aPointToBreak The point where new <br> element will be
1230 * @param aEditingHost Current active editing host.
1231 * @return If succeeded, returns new <br> element and
1232 * candidate caret point.
1234 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1235 HandleInsertBRElement(const EditorDOMPoint
& aPointToBreak
,
1236 const Element
& aEditingHost
);
1239 * HandleInsertLinefeed() inserts a linefeed character into aPointToBreak.
1241 * @param aPointToBreak The point where new linefeed character will be
1243 * @param aEditingHost Current active editing host.
1244 * @return A suggest point to put caret.
1246 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1247 HandleInsertLinefeed(const EditorDOMPoint
& aPointToBreak
,
1248 const Element
& aEditingHost
);
1251 * Splits inclusive inline ancestors at both start and end of aRangeItem. If
1252 * this splits at every point, this modifies aRangeItem to point each split
1253 * point (typically, at right node).
1255 * @param aRangeItem [in/out] One or two DOM points where should be
1256 * split. Will be modified to split point if
1258 * @param aBlockInlineCheck [in] Whether this method considers block vs.
1259 * inline with computed style or the default style.
1260 * @param aEditingHost [in] The editing host.
1261 * @param aAncestorLimiter [in/optional] If specified, this stops splitting
1262 * ancestors when meets this node.
1263 * @return A suggest point to put caret if succeeded, but
1266 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1267 SplitInlineAncestorsAtRangeBoundaries(
1268 RangeItem
& aRangeItem
, BlockInlineCheck aBlockInlineCheck
,
1269 const Element
& aEditingHost
,
1270 const nsIContent
* aAncestorLimiter
= nullptr);
1273 * SplitElementsAtEveryBRElement() splits before all <br> elements in
1274 * aMostAncestorToBeSplit. All <br> nodes will be moved before right node
1275 * at splitting its parent. Finally, this returns left node, first <br>
1276 * element, next left node, second <br> element... and right-most node.
1278 * @param aMostAncestorToBeSplit Most-ancestor element which should
1280 * @param aOutArrayOfNodes First left node, first <br> element,
1281 * Second left node, second <br> element,
1282 * ...right-most node. So, all nodes
1283 * in this list should be siblings (may be
1284 * broken the relation by mutation event
1285 * listener though). If first <br> element
1286 * is first leaf node of
1287 * aMostAncestorToBeSplit, starting from
1288 * the first <br> element.
1289 * @return A suggest point to put caret if
1290 * succeeded, but it may unset.
1292 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1293 SplitElementsAtEveryBRElement(
1294 nsIContent
& aMostAncestorToBeSplit
,
1295 nsTArray
<OwningNonNull
<nsIContent
>>& aOutArrayOfContents
);
1298 * MaybeSplitElementsAtEveryBRElement() calls SplitElementsAtEveryBRElement()
1299 * for each given node when this needs to do that for aEditSubAction.
1300 * If split a node, it in aArrayOfContents is replaced with split nodes and
1303 * @return A suggest point to put caret if
1304 * succeeded, but it may unset.
1306 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1307 MaybeSplitElementsAtEveryBRElement(
1308 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1309 EditSubAction aEditSubAction
);
1312 * CreateRangeIncludingAdjuscentWhiteSpaces() creates an nsRange instance
1313 * which may be expanded from the given range to include adjuscent
1314 * white-spaces. If this fails handling something, returns nullptr.
1316 template <typename EditorDOMRangeType
>
1317 already_AddRefed
<nsRange
> CreateRangeIncludingAdjuscentWhiteSpaces(
1318 const EditorDOMRangeType
& aRange
);
1319 template <typename EditorDOMPointType1
, typename EditorDOMPointType2
>
1320 already_AddRefed
<nsRange
> CreateRangeIncludingAdjuscentWhiteSpaces(
1321 const EditorDOMPointType1
& aStartPoint
,
1322 const EditorDOMPointType2
& aEndPoint
);
1325 * GetRangeExtendedToHardLineEdgesForBlockEditAction() returns an extended
1326 * range if aRange should be extended before handling a block level editing.
1327 * If aRange start and/or end point <br> or something non-editable point, they
1328 * should be moved to nearest text node or something where the other methods
1329 * easier to handle edit action.
1331 [[nodiscard
]] Result
<EditorRawDOMRange
, nsresult
>
1332 GetRangeExtendedToHardLineEdgesForBlockEditAction(
1333 const nsRange
* aRange
, const Element
& aEditingHost
) const;
1336 * InitializeInsertingElement is a callback type of methods which inserts
1337 * an element into the DOM tree. This is called immediately before inserting
1338 * aNewElement into the DOM tree.
1340 * @param aHTMLEditor The HTML editor which modifies the DOM tree.
1341 * @param aNewElement The new element which will be or was inserted into
1343 * @param aPointToInsert The position aNewElement will be or was inserted.
1345 using InitializeInsertingElement
=
1346 std::function
<nsresult(HTMLEditor
& aHTMLEditor
, Element
& aNewElement
,
1347 const EditorDOMPoint
& aPointToInsert
)>;
1348 static InitializeInsertingElement DoNothingForNewElement
;
1349 static InitializeInsertingElement InsertNewBRElement
;
1352 * Helper methods to implement InitializeInsertingElement.
1354 MOZ_CAN_RUN_SCRIPT
static Result
<CreateElementResult
, nsresult
>
1355 AppendNewElementToInsertingElement(
1356 HTMLEditor
& aHTMLEditor
, const nsStaticAtom
& aTagName
,
1357 Element
& aNewElement
,
1358 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1359 MOZ_CAN_RUN_SCRIPT
static Result
<CreateElementResult
, nsresult
>
1360 AppendNewElementWithBRToInsertingElement(HTMLEditor
& aHTMLEditor
,
1361 const nsStaticAtom
& aTagName
,
1362 Element
& aNewElement
);
1365 * Create an element node whose name is aTag at before aPointToInsert. When
1366 * this succeed to create an element node, this inserts the element to
1369 * @param aWithTransaction Whether the inserting is new element is undoable
1370 * or not. WithTransaction::No is useful only when
1371 * the new element is inserted into a new element
1372 * which has not been connected yet.
1373 * @param aTagName The element name to create.
1374 * @param aPointToInsert The insertion point of new element.
1375 * If this refers end of the container or after,
1376 * the transaction will append the element to the
1378 * Otherwise, will insert the element before the
1379 * child node referred by this.
1380 * Note that this point will be invalid once this
1381 * method inserts the new element.
1382 * @param aInitializer A function to initialize the new element before
1383 * connecting the element into the DOM tree. Note
1384 * that this should not touch outside given element
1385 * because doing it would break range updater's
1387 * @return The created new element node and candidate caret
1390 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1391 CreateAndInsertElement(
1392 WithTransaction aWithTransaction
, const nsAtom
& aTagName
,
1393 const EditorDOMPoint
& aPointToInsert
,
1394 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1397 * Callback of CopyAttributes().
1399 * @param aHTMLEditor The HTML editor.
1400 * @param aSrcElement The element which have the attribute.
1401 * @param aDestElement The element which will have the attribute.
1402 * @param aNamespaceID [in] The namespace ID of aAttrName.
1403 * @param aAttrName [in] The attribute name which will be copied.
1404 * @param aValue [in/out] The attribute value which will be copied.
1405 * Once updated, the new value is used.
1406 * @return true if the attribute should be copied, otherwise,
1409 using AttributeFilter
= std::function
<bool(
1410 HTMLEditor
& aHTMLEditor
, Element
& aSrcElement
, Element
& aDestElement
,
1411 int32_t aNamespaceID
, const nsAtom
& aAttrName
, nsString
& aValue
)>;
1412 static AttributeFilter CopyAllAttributes
;
1413 static AttributeFilter CopyAllAttributesExceptId
;
1414 static AttributeFilter CopyAllAttributesExceptDir
;
1415 static AttributeFilter CopyAllAttributesExceptIdAndDir
;
1418 * Copy all attributes of aSrcElement to aDestElement as-is. Different from
1419 * EditorBase::CloneAttributesWithTransaction(), this does not use
1420 * SetAttributeOrEquivalent() nor does not clear existing attributes of
1423 * @param aWithTransaction Whether recoding with transactions or not.
1424 * @param aDestElement The element will have attributes.
1425 * @param aSrcElement The element whose attributes will be copied.
1427 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
CopyAttributes(
1428 WithTransaction aWithTransaction
, Element
& aDestElement
,
1429 Element
& aSrcElement
, const AttributeFilter
& = CopyAllAttributes
);
1432 * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of
1433 * aStartOfDeepestRightNode can have an element whose tag name is aTag.
1434 * Otherwise, looks for an ancestor node which is or is in active editing
1435 * host and can have an element whose name is aTag. If there is such
1436 * ancestor, its descendants are split.
1438 * Note that this may create empty elements while splitting ancestors.
1440 * @param aTag The name of element to be inserted
1441 * after calling this method.
1442 * @param aStartOfDeepestRightNode The start point of deepest right node.
1443 * This point must be in aEditingHost.
1444 * @param aEditingHost The editing host.
1445 * @return When succeeded, SplitPoint() returns
1446 * the point to insert the element.
1448 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
1449 MaybeSplitAncestorsForInsertWithTransaction(
1450 const nsAtom
& aTag
, const EditorDOMPoint
& aStartOfDeepestRightNode
,
1451 const Element
& aEditingHost
);
1454 * InsertElementWithSplittingAncestorsWithTransaction() is a wrapper of
1455 * MaybeSplitAncestorsForInsertWithTransaction() and CreateAndInsertElement().
1456 * I.e., will create an element whose tag name is aTagName and split ancestors
1457 * if it's necessary, then, insert it.
1459 * @param aTagName The tag name which you want to insert new
1460 * element at aPointToInsert.
1461 * @param aPointToInsert The insertion point. New element will be
1462 * inserted before here.
1463 * @param aBRElementNextToSplitPoint
1464 * Whether <br> element should be deleted or
1465 * kept if and only if a <br> element follows
1467 * @param aEditingHost The editing host with which we're handling it.
1468 * @param aInitializer A function to initialize the new element before
1469 * connecting the element into the DOM tree. Note
1470 * that this should not touch outside given element
1471 * because doing it would break range updater's
1473 * @return If succeeded, returns the new element node and
1474 * suggesting point to put caret.
1476 enum class BRElementNextToSplitPoint
{ Keep
, Delete
};
1477 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1478 InsertElementWithSplittingAncestorsWithTransaction(
1479 const nsAtom
& aTagName
, const EditorDOMPoint
& aPointToInsert
,
1480 BRElementNextToSplitPoint aBRElementNextToSplitPoint
,
1481 const Element
& aEditingHost
,
1482 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1485 * Split aElementToSplit at two points, before aStartOfMiddleElement and after
1486 * aEndOfMiddleElement. If they are very start or very end of aBlockElement,
1487 * this won't create empty block.
1489 * @param aElementToSplit An element which will be split.
1490 * @param aStartOfMiddleElement Start node of middle block element.
1491 * @param aEndOfMiddleElement End node of middle block element.
1493 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
1494 SplitRangeOffFromElement(Element
& aElementToSplit
,
1495 nsIContent
& aStartOfMiddleElement
,
1496 nsIContent
& aEndOfMiddleElement
);
1499 * RemoveBlockContainerElementWithTransactionBetween() splits the nodes
1500 * at aStartOfRange and aEndOfRange, then, removes the middle element which
1501 * was split off from aBlockContainerElement and moves the ex-children to
1502 * where the middle element was. I.e., all nodes between aStartOfRange and
1503 * aEndOfRange (including themselves) will be unwrapped from
1504 * aBlockContainerElement.
1506 * @param aBlockContainerElement The node which will be split.
1507 * @param aStartOfRange The first node which will be unwrapped
1508 * from aBlockContainerElement.
1509 * @param aEndOfRange The last node which will be unwrapped from
1510 * aBlockContainerElement.
1511 * @param aBlockInlineCheck Whether this method considers block vs.
1512 * inline with computed style or the default
1514 * @return The left content is new created left
1515 * element of aBlockContainerElement.
1516 * The right content is split element,
1517 * i.e., must be aBlockContainerElement.
1518 * The middle content is nullptr since
1519 * removing it is the job of this method.
1521 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
1522 RemoveBlockContainerElementWithTransactionBetween(
1523 Element
& aBlockContainerElement
, nsIContent
& aStartOfRange
,
1524 nsIContent
& aEndOfRange
, BlockInlineCheck aBlockInlineCheck
);
1527 * WrapContentsInBlockquoteElementsWithTransaction() inserts at least one
1528 * <blockquote> element and moves nodes in aArrayOfContents into new
1529 * <blockquote> elements. If aArrayOfContents includes a table related element
1530 * except <table>, this calls itself recursively to insert <blockquote> into
1533 * @param aArrayOfContents Nodes which will be moved into created
1534 * <blockquote> elements.
1535 * @param aEditingHost The editing host.
1536 * @return A blockquote element which is created at last
1537 * and a suggest of caret position if succeeded.
1538 * The caret suggestion may be unset if there is
1541 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1542 WrapContentsInBlockquoteElementsWithTransaction(
1543 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1544 const Element
& aEditingHost
);
1547 * Our traditional formatBlock was same as XUL cmd_paragraphState command.
1548 * However, the behavior is pretty different from the others and aligning
1549 * the XUL command behavior may break Thunderbird a lot because it handles
1550 * <blockquote> in a special path and <div> (generic block element) is not
1551 * treated as a format node and these things may be used for designing
1552 * current roles of the elements in the email composer of Thunderbird.
1553 * Therefore, we create a new mode for HTMLFormatBlockCommand to align
1554 * the behavior to the others but does not harm Thunderbird.
1556 enum class FormatBlockMode
{
1557 // Document.execCommand("formatBlock"). Cannot set new format to "normal"
1558 // nor "". So, the paths to handle these ones are not used in this mode.
1559 HTMLFormatBlockCommand
,
1560 // cmd_paragraphState. Can set new format to "normal" or "" to remove
1561 // ancestor format blocks.
1562 XULParagraphStateCommand
,
1566 * RemoveBlockContainerElementsWithTransaction() removes all format blocks,
1567 * table related element, etc in aArrayOfContents from the DOM tree. If
1568 * aArrayOfContents has a format node, it will be removed and its contents
1569 * will be moved to where it was.
1570 * If aArrayOfContents has a table related element, <li>, <blockquote> or
1571 * <div>, it will be removed and its contents will be moved to where it was.
1573 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1574 * paragraphState command.
1576 * @return A suggest point to put caret if succeeded, but it may be
1577 * unset if there is no suggestion.
1579 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1580 RemoveBlockContainerElementsWithTransaction(
1581 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1582 FormatBlockMode aFormatBlockMode
, BlockInlineCheck aBlockInlineCheck
);
1585 * CreateOrChangeFormatContainerElement() formats all nodes in
1586 * aArrayOfContents with block elements whose name is aNewFormatTagName.
1588 * If aArrayOfContents has an inline element, a block element is created and
1589 * the inline element and following inline elements are moved into the new
1591 * If aArrayOfContents has <br> elements, they'll be removed from the DOM tree
1592 * and new block element will be created when there are some remaining inline
1594 * If aArrayOfContents has a block element, this calls itself with children of
1595 * the block element. Then, new block element will be created when there are
1596 * some remaining inline elements.
1598 * @param aArrayOfContents Must be descendants of a node.
1599 * @param aNewFormatTagName The element name of new block elements.
1600 * @param aFormatBlockMode The replacing block element target type is for
1601 * whether HTML formatBLock command or XUL
1602 * paragraphState command.
1603 * @param aEditingHost The editing host.
1604 * @return The latest created new block element and a
1605 * suggest point to put caret.
1607 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1608 CreateOrChangeFormatContainerElement(
1609 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
1610 const nsStaticAtom
& aNewFormatTagName
, FormatBlockMode aFormatBlockMode
,
1611 const Element
& aEditingHost
);
1614 * FormatBlockContainerWithTransaction() is implementation of "formatBlock"
1615 * command of `Document.execCommand()`. This applies block style or removes
1618 * @param aSelectionRanges The ranges which are cloned by selection or
1619 * updated from it with doing something before
1621 * @param aNewFormatTagName New block tag name.
1622 * If nsGkAtoms::normal or nsGkAtoms::_empty,
1623 * RemoveBlockContainerElementsWithTransaction()
1625 * If nsGkAtoms::blockquote,
1626 * WrapContentsInBlockquoteElementsWithTransaction()
1628 * Otherwise, CreateOrChangeBlockContainerElement()
1630 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
1631 * paragraphState command.
1632 * @param aEditingHost The editing host.
1633 * @return If selection should be finally collapsed in a
1634 * created block element, this returns the element.
1636 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<RefPtr
<Element
>, nsresult
>
1637 FormatBlockContainerWithTransaction(
1638 AutoClonedSelectionRangeArray
& aSelectionRanges
,
1639 const nsStaticAtom
& aNewFormatTagName
, FormatBlockMode aFormatBlockMode
,
1640 const Element
& aEditingHost
);
1643 * Retrun true if the specified line break can be inserted around aContent.
1644 * If aContent is an Element, this checks whether the element can have the
1646 * If aContent is a Text, this check whether its container element can have
1649 [[nodiscard
]] static bool CanInsertLineBreak(LineBreakType aLineBreakType
,
1650 const nsIContent
& aContent
);
1653 * If aPointToInsert is between line breaks or block boundaries, this
1654 * puts a <br> element to make an empty line between them.
1656 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateLineBreakResult
, nsresult
>
1657 InsertPaddingBRElementToMakeEmptyLineVisibleIfNeeded(
1658 const EditorDOMPoint
& aPointToInsert
);
1661 * Insert a padding <br> if aPoint is in an empty block.
1663 * @param aPoint The place where you want to put a padding line
1665 * @param aDeleteEmptyInlines If nsIEditor::eStrip, this deletes empty inlines
1666 * before inserting a line break from the inserting
1669 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateLineBreakResult
, nsresult
>
1670 InsertPaddingBRElementIfInEmptyBlock(
1671 const EditorDOMPoint
& aPoint
,
1672 nsIEditor::EStripWrappers aDeleteEmptyInlines
);
1675 * Insert a padding <br> element for making preceding collapsible white-spaces
1676 * visible or the point is empty between block boundaries.
1678 * @param aPoint Where you want to check. A padding <br> may be
1679 * inserted different from this point.
1680 * @param aDeleteEmptyInlines If nsIEditor::eStrip, this deletes empty inlines
1681 * before inserting <br> from the inserting point.
1682 * @param aEditingHost The editing host.
1684 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateLineBreakResult
, nsresult
>
1685 InsertPaddingBRElementIfNeeded(const EditorDOMPoint
& aPoint
,
1686 nsIEditor::EStripWrappers aDeleteEmptyInlines
,
1687 const Element
& aEditingHost
);
1689 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
1690 DeleteRangesWithTransaction(
1691 nsIEditor::EDirection aDirectionAndAmount
,
1692 nsIEditor::EStripWrappers aStripWrappers
,
1693 const AutoClonedRangeArray
& aRangesToDelete
) override
;
1696 * SplitParagraphWithTransaction() splits the parent block, aParentDivOrP, at
1697 * aStartOfRightNode.
1699 * @param aParentDivOrP The parent block to be split. This must be <p>
1701 * @param aStartOfRightNode The point to be start of right node after
1702 * split. This must be descendant of
1704 * @param aMayBecomeVisibleBRElement
1705 * Next <br> element of the split point if there
1706 * is. Otherwise, nullptr. If this is not nullptr,
1707 * the <br> element may be removed if it becomes
1709 * @param aEditingHost The editing host.
1711 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
1712 SplitParagraphWithTransaction(Element
& aParentDivOrP
,
1713 const EditorDOMPoint
& aStartOfRightNode
,
1714 dom::HTMLBRElement
* aMayBecomeVisibleBRElement
,
1715 const Element
& aEditingHost
);
1718 * HandleInsertParagraphInParagraph() does the right thing for Enter key
1719 * press or 'insertParagraph' command in aParentDivOrP. aParentDivOrP will
1720 * be split **around** aCandidatePointToSplit. If this thinks that it should
1721 * be handled to insert a <br> instead, this returns "not handled".
1723 * @param aParentDivOrP The parent block. This must be <p> or <div>
1725 * @param aCandidatePointToSplit
1726 * The point where the caller want to split
1727 * aParentDivOrP. However, in some cases, this is not
1728 * used as-is. E.g., this method avoids to create new
1729 * empty <a href> in the right paragraph. So this may
1730 * be adjusted to proper position around it.
1731 * @param aEditingHost The editing host.
1732 * @return If the caller should default to inserting <br>
1733 * element, returns "not handled".
1735 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
1736 HandleInsertParagraphInParagraph(Element
& aParentDivOrP
,
1737 const EditorDOMPoint
& aCandidatePointToSplit
,
1738 const Element
& aEditingHost
);
1741 * HandleInsertParagraphInHeadingElement() handles insertParagraph command
1742 * (i.e., handling Enter key press) in a heading element. This splits
1743 * aHeadingElement element at aPointToSplit. Then, if right heading element
1744 * is empty, it'll be removed and new paragraph is created (its type is
1745 * decided with default paragraph separator).
1747 * @param aHeadingElement The heading element to be split.
1748 * @param aPointToSplit The point to split aHeadingElement.
1749 * @return New paragraph element, meaning right heading
1750 * element if aHeadingElement is split, or newly
1751 * created or existing paragraph element.
1753 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertParagraphResult
, nsresult
>
1754 HandleInsertParagraphInHeadingElement(Element
& aHeadingElement
,
1755 const EditorDOMPoint
& aPointToSplit
);
1758 * HandleInsertParagraphInListItemElement() handles insertParagraph command
1759 * (i.e., handling Enter key press) in a list item element.
1761 * @param aListItemElement The list item which has the following point.
1762 * @param aPointToSplit The point to split aListItemElement.
1763 * @param aEditingHost The editing host.
1764 * @return New paragraph element, meaning right list item
1765 * element if aListItemElement is split, or newly
1766 * created paragraph element.
1768 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<InsertParagraphResult
, nsresult
>
1769 HandleInsertParagraphInListItemElement(Element
& aListItemElement
,
1770 const EditorDOMPoint
& aPointToSplit
,
1771 const Element
& aEditingHost
);
1774 * InsertParagraphSeparatorAsSubAction() handles insertPargraph commad
1775 * (i.e., handling Enter key press) with the above helper methods.
1777 * @param aEditingHost The editing host.
1779 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
1780 InsertParagraphSeparatorAsSubAction(const Element
& aEditingHost
);
1783 * InsertLineBreakAsSubAction() inserts a new <br> element or a linefeed
1784 * character at selection. If there is non-collapsed selection ranges, the
1785 * selected ranges is deleted first.
1787 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertLineBreakAsSubAction();
1790 * ChangeListElementType() replaces child list items of aListElement with
1791 * new list item element whose tag name is aNewListItemTag.
1792 * Note that if there are other list elements as children of aListElement,
1793 * this calls itself recursively even though it's invalid structure.
1795 * @param aListElement The list element whose list items will be
1797 * @param aNewListTag New list tag name.
1798 * @param aNewListItemTag New list item tag name.
1799 * @return New list element or an error code if it fails.
1800 * New list element may be aListElement if its
1801 * tag name is same as aNewListTag.
1803 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1804 ChangeListElementType(Element
& aListElement
, nsAtom
& aListType
,
1807 class AutoListElementCreator
;
1809 [[nodiscard
]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode
,
1810 const nsIContent
& aContent
);
1813 * MakeOrChangeListAndListItemAsSubAction() handles create list commands with
1814 * current selection. If
1816 * @param aListElementOrListItemElementTagName
1817 * The new list element tag name or
1818 * new list item tag name.
1819 * If the former, list item tag name will
1820 * be computed automatically. Otherwise,
1821 * list tag name will be computed.
1822 * @param aBulletType If this is not empty string, it's set
1823 * to `type` attribute of new list item
1824 * elements. Otherwise, existing `type`
1825 * attributes will be removed.
1826 * @param aSelectAllOfCurrentList Yes if this should treat all of
1827 * ancestor list element at selection.
1828 * @param aEditingHost The editing host.
1830 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
1831 MakeOrChangeListAndListItemAsSubAction(
1832 const nsStaticAtom
& aListElementOrListItemElementTagName
,
1833 const nsAString
& aBulletType
,
1834 SelectAllOfCurrentList aSelectAllOfCurrentList
,
1835 const Element
& aEditingHost
);
1838 * DeleteTextAndTextNodesWithTransaction() removes text or text nodes in
1841 enum class TreatEmptyTextNodes
{
1842 // KeepIfContainerOfRangeBoundaries:
1843 // Will remove empty text nodes middle of the range, but keep empty
1844 // text nodes which are containers of range boundaries.
1845 KeepIfContainerOfRangeBoundaries
,
1847 // Will remove all empty text nodes.
1849 // RemoveAllEmptyInlineAncestors:
1850 // Will remove all empty text nodes and its inline ancestors which
1851 // become empty due to removing empty text nodes.
1852 RemoveAllEmptyInlineAncestors
,
1854 template <typename EditorDOMPointType
>
1855 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
1856 DeleteTextAndTextNodesWithTransaction(
1857 const EditorDOMPointType
& aStartPoint
,
1858 const EditorDOMPointType
& aEndPoint
,
1859 TreatEmptyTextNodes aTreatEmptyTextNodes
);
1862 * Delete the line break with DeleteNodeTransaction or DeleteTextTransaction.
1864 * @param aLineBreak The line break to be deleted.
1865 * @param aDeleteEmptyInlines If nsIEditor::eStrip, this deletes new empty
1866 * inline element if and only if this deletes the
1868 * @param aEditingHost The editing host.
1869 * @return The point where the line break was.
1871 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1872 DeleteLineBreakWithTransaction(const EditorLineBreak
& aLineBreak
,
1873 nsIEditor::EStripWrappers aDeleteEmptyInlines
,
1874 const Element
& aEditingHost
);
1877 * JoinNodesWithTransaction() joins aLeftContent and aRightContent. Content
1878 * of aLeftContent will be merged into aRightContent. Actual implemenation of
1879 * this method is JoinNodesImpl(). So, see its explanation for the detail.
1881 * @param aLeftContent Will be removed from the DOM tree.
1882 * @param aRightContent The node which will be new container of the content
1885 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<JoinNodesResult
, nsresult
>
1886 JoinNodesWithTransaction(nsIContent
& aLeftContent
, nsIContent
& aRightContent
);
1889 * JoinNearestEditableNodesWithTransaction() joins two editable nodes which
1890 * are themselves or the nearest editable node of aLeftNode and aRightNode.
1891 * XXX This method's behavior is odd. For example, if user types Backspace
1892 * key at the second editable paragraph in this case:
1893 * <div contenteditable>
1894 * <p>first editable paragraph</p>
1895 * <p contenteditable="false">non-editable paragraph</p>
1896 * <p>second editable paragraph</p>
1898 * The first editable paragraph's content will be moved into the second
1899 * editable paragraph and the non-editable paragraph becomes the first
1900 * paragraph of the editor. I don't think that it's expected behavior of
1903 * @param aLeftNode The node which will be removed.
1904 * @param aRightNode The node which will be inserted the content of
1906 * @param aNewFirstChildOfRightNode
1907 * [out] The point at the first child of aRightNode.
1909 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
1910 JoinNearestEditableNodesWithTransaction(
1911 nsIContent
& aLeftNode
, nsIContent
& aRightNode
,
1912 EditorDOMPoint
* aNewFirstChildOfRightNode
);
1915 * ReplaceContainerAndCloneAttributesWithTransaction() creates new element
1916 * whose name is aTagName, copies all attributes from aOldContainer to the
1917 * new element, moves all children in aOldContainer to the new element, then,
1918 * removes aOldContainer from the DOM tree.
1920 * @param aOldContainer The element node which should be replaced
1922 * @param aTagName The name of new element node.
1924 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1925 ReplaceContainerAndCloneAttributesWithTransaction(Element
& aOldContainer
,
1926 const nsAtom
& aTagName
);
1929 * ReplaceContainerWithTransaction() creates new element whose name is
1930 * aTagName, sets aAttributes of the new element to aAttributeValue, moves
1931 * all children in aOldContainer to the new element, then, removes
1932 * aOldContainer from the DOM tree.
1934 * @param aOldContainer The element node which should be replaced
1936 * @param aTagName The name of new element node.
1937 * @param aAttribute Attribute name to be set to the new element.
1938 * @param aAttributeValue Attribute value to be set to aAttribute.
1940 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1941 ReplaceContainerWithTransaction(Element
& aOldContainer
,
1942 const nsAtom
& aTagName
,
1943 const nsAtom
& aAttribute
,
1944 const nsAString
& aAttributeValue
);
1947 * ReplaceContainerWithTransaction() creates new element whose name is
1948 * aTagName, moves all children in aOldContainer to the new element, then,
1949 * removes aOldContainer from the DOM tree.
1951 * @param aOldContainer The element node which should be replaced
1953 * @param aTagName The name of new element node.
1955 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1956 ReplaceContainerWithTransaction(Element
& aOldContainer
,
1957 const nsAtom
& aTagName
);
1960 * RemoveContainerWithTransaction() removes aElement from the DOM tree and
1961 * moves all its children to the parent of aElement.
1963 * @param aElement The element to be removed.
1964 * @return A suggestion point to put caret.
1966 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
1967 RemoveContainerWithTransaction(Element
& aElement
);
1970 * InsertContainerWithTransaction() creates new element whose name is
1971 * aWrapperTagName, moves aContentToBeWrapped into the new element, then,
1972 * inserts the new element into where aContentToBeWrapped was.
1973 * NOTE: This method does not check if aContentToBeWrapped is valid child
1974 * of the new element. So, callers need to guarantee it.
1976 * @param aContentToBeWrapped The content which will be wrapped with new
1978 * @param aWrapperTagName Element name of new element which will wrap
1979 * aContent and be inserted into where aContent
1981 * @param aInitializer A callback to initialize new element before
1982 * inserting to the DOM tree.
1984 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
1985 InsertContainerWithTransaction(
1986 nsIContent
& aContentToBeWrapped
, const nsAtom
& aWrapperTagName
,
1987 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
1990 * MoveNodeWithTransaction() moves aContentToMove to aPointToInsert.
1992 * @param aContentToMove The node to be moved.
1993 * @param aPointToInsert The point where aContentToMove will be inserted.
1995 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
1996 MoveNodeWithTransaction(nsIContent
& aContentToMove
,
1997 const EditorDOMPoint
& aPointToInsert
);
2000 * MoveNodeToEndWithTransaction() moves aContentToMove to end of
2003 * @param aContentToMove The node to be moved.
2004 * @param aNewContainer The new container which will contain aContentToMove
2005 * as its last child.
2007 [[nodiscard
]] inline MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
2008 MoveNodeToEndWithTransaction(nsIContent
& aContentToMove
,
2009 nsINode
& aNewContainer
);
2012 * MoveNodeOrChildrenWithTransaction() moves aContent to aPointToInsert. If
2013 * cannot insert aContent due to invalid relation, moves only its children
2014 * recursively and removes aContent from the DOM tree.
2016 * @param aContent Content which should be moved.
2017 * @param aPointToInsert The point to be inserted aContent or its
2019 * @param aPreserveWhiteSpaceStyle
2020 * If yes and if it's possible to keep white-space
2021 * style, this method will set `style` attribute to
2022 * moving node or creating new <span> element.
2023 * @param aRemoveIfCommentNode
2024 * If yes, this removes a comment node instead of
2025 * moving it to the destination. Note that this
2026 * does not remove comment nodes in moving nodes
2027 * because it requires additional scan.
2029 enum class PreserveWhiteSpaceStyle
{ No
, Yes
};
2030 friend std::ostream
& operator<<(
2031 std::ostream
& aStream
,
2032 const PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle
);
2033 enum class RemoveIfCommentNode
{ No
, Yes
};
2034 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
2035 MoveNodeOrChildrenWithTransaction(
2036 nsIContent
& aContentToMove
, const EditorDOMPoint
& aPointToInsert
,
2037 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle
,
2038 RemoveIfCommentNode aRemoveIfCommentNode
);
2041 * CanMoveNodeOrChildren() returns true if
2042 * `MoveNodeOrChildrenWithTransaction()` can move or delete at least a
2043 * descendant of aElement into aNewContainer. I.e., when this returns true,
2044 * `MoveNodeOrChildrenWithTransaction()` must return "handled".
2046 Result
<bool, nsresult
> CanMoveNodeOrChildren(
2047 const nsIContent
& aContent
, const nsINode
& aNewContainer
) const;
2050 * MoveChildrenWithTransaction() moves the children of aElement to
2051 * aPointToInsert. If cannot insert some children due to invalid relation,
2052 * calls MoveNodeOrChildrenWithTransaction() to remove the children but keep
2053 * moving its children.
2055 * @param aElement Container element whose children should be
2057 * @param aPointToInsert The point to be inserted children of aElement
2058 * or its descendants.
2059 * @param aPreserveWhiteSpaceStyle
2060 * If yes and if it's possible to keep white-space
2061 * style, this method will set `style` attribute to
2062 * moving node or creating new <span> element.
2063 * @param aRemoveIfCommentNode
2064 * If yes, this removes a comment node instead of
2065 * moving it to the destination. Note that this
2066 * does not remove comment nodes in moving nodes
2067 * because it requires additional scan.
2069 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<MoveNodeResult
, nsresult
>
2070 MoveChildrenWithTransaction(Element
& aElement
,
2071 const EditorDOMPoint
& aPointToInsert
,
2072 PreserveWhiteSpaceStyle aPreserveWhiteSpaceStyle
,
2073 RemoveIfCommentNode aRemoveIfCommentNode
);
2076 * CanMoveChildren() returns true if `MoveChildrenWithTransaction()` can move
2077 * at least a descendant of aElement into aNewContainer. I.e., when this
2078 * returns true, `MoveChildrenWithTransaction()` return "handled".
2080 Result
<bool, nsresult
> CanMoveChildren(const Element
& aElement
,
2081 const nsINode
& aNewContainer
) const;
2084 * MoveAllChildren() moves all children of aContainer to before
2085 * aPointToInsert.GetChild().
2086 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2088 * @param aContainer The container node whose all children should
2090 * @param aPointToInsert The insertion point. The container must not
2091 * be a data node like a text node.
2093 [[nodiscard
]] nsresult
MoveAllChildren(
2094 nsINode
& aContainer
, const EditorRawDOMPoint
& aPointToInsert
);
2097 * MoveChildrenBetween() moves all children between aFirstChild and aLastChild
2098 * to before aPointToInsert.GetChild(). If some children are moved to
2099 * different container while this method moves other children, they are just
2100 * ignored. If the child node referred by aPointToInsert is moved to different
2101 * container while this method moves children, returns error.
2103 * @param aFirstChild The first child which should be moved to
2105 * @param aLastChild The last child which should be moved. This
2106 * must be a sibling of aFirstChild and it should
2107 * be positioned after aFirstChild in the DOM tree
2109 * @param aPointToInsert The insertion point. The container must not
2110 * be a data node like a text node.
2112 [[nodiscard
]] nsresult
MoveChildrenBetween(
2113 nsIContent
& aFirstChild
, nsIContent
& aLastChild
,
2114 const EditorRawDOMPoint
& aPointToInsert
);
2117 * MovePreviousSiblings() moves all siblings before aChild (i.e., aChild
2118 * won't be moved) to before aPointToInsert.GetChild().
2119 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2121 * @param aChild The node which is next sibling of the last
2123 * @param aPointToInsert The insertion point. The container must not
2124 * be a data node like a text node.
2126 [[nodiscard
]] nsresult
MovePreviousSiblings(
2127 nsIContent
& aChild
, const EditorRawDOMPoint
& aPointToInsert
);
2130 * MoveInclusiveNextSiblings() moves aChild and all siblings after it to
2131 * before aPointToInsert.GetChild().
2132 * See explanation of MoveChildrenBetween() for the detail of the behavior.
2134 * @param aChild The node which is first node to be moved.
2135 * @param aPointToInsert The insertion point. The container must not
2136 * be a data node like a text node.
2138 [[nodiscard
]] nsresult
MoveInclusiveNextSiblings(
2139 nsIContent
& aChild
, const EditorRawDOMPoint
& aPointToInsert
);
2142 * SplitNodeWithTransaction() creates a transaction to create a new node
2143 * (left node) identical to an existing node (right node), and split the
2144 * contents between the same point in both nodes, then, execute the
2147 * @param aStartOfRightNode The point to split. Its container will be
2148 * the right node, i.e., become the new node's
2149 * next sibling. And the point will be start
2150 * of the right node.
2152 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
2153 SplitNodeWithTransaction(const EditorDOMPoint
& aStartOfRightNode
);
2156 * SplitNodeDeepWithTransaction() splits aMostAncestorToSplit deeply.
2158 * @param aMostAncestorToSplit The most ancestor node which should be
2160 * @param aStartOfDeepestRightNode The start point of deepest right node.
2161 * This point must be descendant of
2162 * aMostAncestorToSplit.
2163 * @param aSplitAtEdges Whether the caller allows this to
2164 * create empty container element when
2165 * split point is start or end of an
2167 * @return SplitPoint() returns split point in
2168 * aMostAncestorToSplit. The point must
2169 * be good to insert something if the
2170 * caller want to do it.
2172 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitNodeResult
, nsresult
>
2173 SplitNodeDeepWithTransaction(nsIContent
& aMostAncestorToSplit
,
2174 const EditorDOMPoint
& aDeepestStartOfRightNode
,
2175 SplitAtEdges aSplitAtEdges
);
2178 * DeleteEmptyInclusiveAncestorInlineElements() removes empty inclusive
2179 * ancestor inline elements in inclusive ancestor block element of aContent.
2181 * @param aContent Must be an empty content.
2182 * @param aEditingHost The editing host.
2184 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
2185 DeleteEmptyInclusiveAncestorInlineElements(nsIContent
& aContent
,
2186 const Element
& aEditingHost
);
2189 * DeleteTextAndNormalizeSurroundingWhiteSpaces() deletes text between
2190 * aStartToDelete and immediately before aEndToDelete and return new caret
2191 * position. If surrounding characters are white-spaces, this normalize them
2192 * too. Finally, inserts `<br>` element if it's required.
2193 * Note that if you wants only normalizing white-spaces, you can set same
2194 * point to both aStartToDelete and aEndToDelete. Then, this tries to
2195 * normalize white-space sequence containing previous character of
2198 enum class DeleteDirection
{
2202 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CaretPoint
, nsresult
>
2203 DeleteTextAndNormalizeSurroundingWhiteSpaces(
2204 const EditorDOMPointInText
& aStartToDelete
,
2205 const EditorDOMPointInText
& aEndToDelete
,
2206 TreatEmptyTextNodes aTreatEmptyTextNodes
,
2207 DeleteDirection aDeleteDirection
, const Element
& aEditingHost
);
2210 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() is a helper method of
2211 * DeleteTextAndNormalizeSurroundingWhiteSpaces(). This expands
2212 * aStartToDelete and/or aEndToDelete if there are white-spaces which need
2215 * @param aStartToDelete [In/Out] Start to delete. If this point
2216 * follows white-spaces, this may be modified.
2217 * @param aEndToDelete [In/Out] Next point of last content to be
2218 * deleted. If this point is a white-space,
2219 * this may be modified.
2220 * @param aNormalizedWhiteSpacesInStartNode
2221 * [Out] If container text node of aStartToDelete
2222 * should be modified, this offers new string
2223 * in the range in the text node.
2224 * @param aNormalizedWhiteSpacesInEndNode
2225 * [Out] If container text node of aEndToDelete
2226 * is different from the container of
2227 * aStartToDelete and it should be modified, this
2228 * offers new string in the range in the text node.
2230 void ExtendRangeToDeleteWithNormalizingWhiteSpaces(
2231 EditorDOMPointInText
& aStartToDelete
, EditorDOMPointInText
& aEndToDelete
,
2232 nsAString
& aNormalizedWhiteSpacesInStartNode
,
2233 nsAString
& aNormalizedWhiteSpacesInEndNode
) const;
2236 * CharPointType let the following helper methods of
2237 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2238 * character will be previous or next char point after deletion.
2240 enum class CharPointType
{
2241 TextEnd
, // Start or end of the text (hardline break or replaced inline
2243 ASCIIWhiteSpace
, // One of ASCII white-spaces (collapsible white-space)
2244 NoBreakingSpace
, // NBSP
2245 VisibleChar
, // Non-white-space characters
2246 PreformattedChar
, // Any character except a linefeed in a preformatted
2248 PreformattedLineBreak
, // Preformatted linebreak
2252 * GetPreviousCharPointType() and GetCharPointType() get type of
2253 * previous/current char point from current DOM tree. In other words, if the
2254 * point will be deleted, you cannot use these methods.
2256 template <typename EditorDOMPointType
>
2257 static CharPointType
GetPreviousCharPointType(
2258 const EditorDOMPointType
& aPoint
);
2259 template <typename EditorDOMPointType
>
2260 static CharPointType
GetCharPointType(const EditorDOMPointType
& aPoint
);
2263 * CharPointData let the following helper methods of
2264 * ExtendRangeToDeleteWithNormalizingWhiteSpaces() know what type of
2265 * character will be previous or next char point and the point is
2266 * in same or different text node after deletion.
2268 class MOZ_STACK_CLASS CharPointData final
{
2270 static CharPointData
InDifferentTextNode(CharPointType aCharPointType
) {
2271 CharPointData result
;
2272 result
.mIsInDifferentTextNode
= true;
2273 result
.mType
= aCharPointType
;
2276 static CharPointData
InSameTextNode(CharPointType aCharPointType
) {
2277 CharPointData result
;
2278 // Let's mark this as in different text node if given one indicates
2279 // that there is end of text because it means that adjacent content
2280 // from point of text node view is another element.
2281 result
.mIsInDifferentTextNode
= aCharPointType
== CharPointType::TextEnd
;
2282 result
.mType
= aCharPointType
;
2286 bool AcrossTextNodeBoundary() const { return mIsInDifferentTextNode
; }
2287 bool IsCollapsibleWhiteSpace() const {
2288 return mType
== CharPointType::ASCIIWhiteSpace
||
2289 mType
== CharPointType::NoBreakingSpace
;
2291 CharPointType
Type() const { return mType
; }
2294 CharPointData() = default;
2296 CharPointType mType
;
2297 bool mIsInDifferentTextNode
;
2301 * GetPreviousCharPointDataForNormalizingWhiteSpaces() and
2302 * GetInclusiveNextCharPointDataForNormalizingWhiteSpaces() is helper methods
2303 * of ExtendRangeToDeleteWithNormalizingWhiteSpaces(). This retrieves
2304 * previous or inclusive next editable char point and returns its data.
2306 CharPointData
GetPreviousCharPointDataForNormalizingWhiteSpaces(
2307 const EditorDOMPointInText
& aPoint
) const;
2308 CharPointData
GetInclusiveNextCharPointDataForNormalizingWhiteSpaces(
2309 const EditorDOMPointInText
& aPoint
) const;
2312 * GenerateWhiteSpaceSequence() generates white-space sequence which won't
2315 * @param aResult [out] White space sequence which won't be
2316 * collapsed, but wrapable.
2317 * @param aLength Length of generating white-space sequence.
2318 * Must be 1 or larger.
2319 * @param aPreviousCharPointData
2320 * Specify the previous char point where it'll be
2321 * inserted. Currently, for keepin this method
2322 * simple, does not support to generate a part
2323 * of white-space sequence in a text node. So,
2324 * if the type is white-space, it must indicate
2325 * different text nodes white-space.
2326 * @param aNextCharPointData Specify the next char point where it'll be
2327 * inserted. Same as aPreviousCharPointData,
2328 * this must node indidate white-space in same
2331 static void GenerateWhiteSpaceSequence(
2332 nsAString
& aResult
, uint32_t aLength
,
2333 const CharPointData
& aPreviousCharPointData
,
2334 const CharPointData
& aNextCharPointData
);
2337 * ComputeTargetRanges() computes actual delete ranges which will be deleted
2338 * unless the following `beforeinput` event is canceled.
2340 * @param aDirectionAndAmount The direction and amount of deletion.
2341 * @param aRangesToDelete [In/Out] The ranges to be deleted,
2342 * typically, initialized with the
2343 * selection ranges. This may be modified
2344 * if selection ranges should be extened.
2346 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2347 ComputeTargetRanges(nsIEditor::EDirection aDirectionAndAmount
,
2348 AutoClonedSelectionRangeArray
& aRangesToDelete
) const;
2351 * This method handles "delete selection" commands.
2353 * @param aDirectionAndAmount Direction of the deletion.
2354 * @param aStripWrappers Must be eStrip or eNoStrip.
2356 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2357 HandleDeleteSelection(nsIEditor::EDirection aDirectionAndAmount
,
2358 nsIEditor::EStripWrappers aStripWrappers
) final
;
2360 class AutoDeleteRangesHandler
;
2361 class AutoMoveOneLineHandler
;
2364 * DeleteMostAncestorMailCiteElementIfEmpty() deletes most ancestor
2365 * mail cite element (`<blockquote type="cite">` or
2366 * `<span _moz_quote="true">`, the former can be created with middle click
2367 * paste with `Control` or `Command` even in the web) of aContent if it
2370 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2371 DeleteMostAncestorMailCiteElementIfEmpty(nsIContent
& aContent
);
2374 * LiftUpListItemElement() moves aListItemElement outside its parent.
2375 * If it's in a middle of a list element, the parent list element is split
2376 * before aListItemElement. Then, moves aListItemElement to before its
2377 * parent list element. I.e., moves aListItemElement between the 2 list
2378 * elements if original parent was split. Then, if new parent becomes not a
2379 * list element, the list item element is removed and its contents are moved
2380 * to where the list item element was. If aListItemElement becomse not a
2381 * child of list element, its contents are unwrapped from aListItemElement.
2383 * @param aListItemElement Must be a <li>, <dt> or <dd> element.
2384 * @param aLiftUpFromAllParentListElements
2385 * If Yes, this method calls itself recursively
2386 * to unwrap the contents in aListItemElement
2387 * from any ancestor list elements.
2388 * XXX This checks only direct parent of list
2389 * elements. Therefore, if a parent list
2390 * element in a list item element, the
2391 * list item element and its list element
2392 * won't be unwrapped.
2394 enum class LiftUpFromAllParentListElements
{ Yes
, No
};
2395 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
LiftUpListItemElement(
2396 dom::Element
& aListItemElement
,
2397 LiftUpFromAllParentListElements aLiftUpFromAllParentListElements
);
2400 * DestroyListStructureRecursively() destroys the list structure of
2401 * aListElement recursively.
2402 * If aListElement has <li>, <dl> or <dt> as a child, the element is removed
2403 * but its descendants are moved to where the list item element was.
2404 * If aListElement has another <ul>, <ol> or <dl> as a child, this method is
2405 * called recursively.
2406 * If aListElement has other nodes as its child, they are just removed.
2407 * Finally, aListElement is removed. and its all children are moved to
2408 * where the aListElement was.
2410 * @param aListElement A <ul>, <ol> or <dl> element.
2412 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2413 DestroyListStructureRecursively(Element
& aListElement
);
2416 * RemoveListAtSelectionAsSubAction() removes list elements and list item
2417 * elements at Selection. And move contents in them where the removed list
2420 * @param aEditingHost The editing host.
2422 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2423 RemoveListAtSelectionAsSubAction(const Element
& aEditingHost
);
2426 * ChangeMarginStart() changes margin of aElement to indent or outdent.
2427 * If it's rtl text, margin-right will be changed. Otherwise, margin-left.
2428 * XXX This is not aware of vertical writing-mode.
2430 * @param aElement The element whose start margin should be
2432 * @param aChangeMargin Whether increase or decrease the margin.
2433 * @param aEditingHost The editing host.
2434 * @return May suggest a suggest point to put caret.
2436 enum class ChangeMargin
{ Increase
, Decrease
};
2437 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2438 ChangeMarginStart(Element
& aElement
, ChangeMargin aChangeMargin
,
2439 const Element
& aEditingHost
);
2442 * HandleCSSIndentAroundRanges() indents around aRanges with CSS.
2444 * @param aRanges The ranges where the content should be indented.
2445 * @param aEditingHost The editing host.
2447 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
HandleCSSIndentAroundRanges(
2448 AutoClonedSelectionRangeArray
& aRanges
, const Element
& aEditingHost
);
2451 * HandleCSSIndentAroundRanges() indents around aRanges with HTML.
2453 * @param aRanges The ranges where the content should be indented.
2454 * @param aEditingHost The editing host.
2456 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
HandleHTMLIndentAroundRanges(
2457 AutoClonedSelectionRangeArray
& aRanges
, const Element
& aEditingHost
);
2460 * HandleIndentAtSelection() indents around Selection with HTML or CSS.
2462 * @param aEditingHost The editing host.
2464 // TODO: Make this take AutoClonedSelectionRangeArray instead of retrieving
2466 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2467 HandleIndentAtSelection(const Element
& aEditingHost
);
2470 * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and
2471 * aEndOfOutdent. This splits the range off from aBlockElement first.
2472 * Then, removes the middle element if aIsBlockIndentedWithCSS is false.
2473 * Otherwise, decreases the margin of the middle element.
2475 * @param aBlockElement A block element which includes both
2476 * aStartOfOutdent and aEndOfOutdent.
2477 * @param aStartOfOutdent First node which is descendant of
2478 * aBlockElement will be outdented.
2479 * @param aEndOfOutdent Last node which is descandant of
2480 * aBlockElement will be outdented.
2481 * @param aBlockIndentedWith `CSS` if aBlockElement is indented with
2482 * CSS margin property.
2483 * `HTML` if aBlockElement is `<blockquote>`
2485 * @param aEditingHost The editing host.
2486 * @return The left content is new created element
2487 * splitting before aStartOfOutdent.
2488 * The right content is existing element.
2489 * The middle content is outdented element
2490 * if aBlockIndentedWith is `CSS`.
2491 * Otherwise, nullptr.
2493 enum class BlockIndentedWith
{ CSS
, HTML
};
2494 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
2495 OutdentPartOfBlock(Element
& aBlockElement
, nsIContent
& aStartOfOutdent
,
2496 nsIContent
& aEndOfOutdent
,
2497 BlockIndentedWith aBlockIndentedWith
,
2498 const Element
& aEditingHost
);
2501 * HandleOutdentAtSelectionInternal() outdents contents around Selection.
2502 * This method creates AutoSelectionRestorer. Therefore, each caller
2503 * needs to check if the editor is still available even if this returns
2505 * NOTE: Call `HandleOutdentAtSelection()` instead.
2507 * @param aEditingHost The editing host.
2508 * @return The left content is left content of last
2509 * outdented element.
2510 * The right content is right content of last
2511 * outdented element.
2512 * The middle content is middle content of last
2513 * outdented element.
2515 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<SplitRangeOffFromNodeResult
, nsresult
>
2516 HandleOutdentAtSelectionInternal(const Element
& aEditingHost
);
2519 * HandleOutdentAtSelection() outdents contents around Selection.
2521 * @param aEditingHost The editing host.
2523 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2524 HandleOutdentAtSelection(const Element
& aEditingHost
);
2527 * AlignBlockContentsWithDivElement() sets align attribute of <div> element
2528 * which is only child of aBlockElement to aAlignType. If aBlockElement
2529 * has 2 or more children or does not have a `<div>` element, inserts a
2530 * new `<div>` element into aBlockElement and move all children of
2531 * aBlockElement into the new `<div>` element.
2533 * @param aBlockElement The element node whose contents should be
2534 * aligned to aAlignType. This should be
2535 * an element which can have `<div>` element
2537 * @param aAlignType New value of align attribute of `<div>`
2539 * @return A candidate position to put caret.
2541 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2542 AlignBlockContentsWithDivElement(Element
& aBlockElement
,
2543 const nsAString
& aAlignType
);
2546 * AlignContentsInAllTableCellsAndListItems() calls
2547 * AlignBlockContentsWithDivElement() for aligning contents in every list
2548 * item element and table cell element in aElement.
2550 * @param aElement The node which is or whose descendants should
2551 * be aligned to aAlignType.
2552 * @param aAlignType New value of `align` attribute of `<div>`.
2553 * @return A candidate position to put caret.
2555 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2556 AlignContentsInAllTableCellsAndListItems(dom::Element
& aElement
,
2557 const nsAString
& aAlignType
);
2560 * MakeTransitionList() detects all the transitions in the array, where a
2561 * transition means that adjacent nodes in the array don't have the same
2564 static void MakeTransitionList(
2565 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
2566 nsTArray
<bool>& aTransitionArray
);
2569 * EnsureHardLineBeginsWithFirstChildOf() inserts `<br>` element before
2570 * first child of aRemovingContainerElement if it will not be start of a
2571 * hard line after removing aRemovingContainerElement.
2573 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2574 EnsureHardLineBeginsWithFirstChildOf(Element
& aRemovingContainerElement
);
2577 * EnsureHardLineEndsWithLastChildOf() inserts `<br>` element after last
2578 * child of aRemovingContainerElement if it will not be end of a hard line
2579 * after removing aRemovingContainerElement.
2581 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2582 EnsureHardLineEndsWithLastChildOf(Element
& aRemovingContainerElement
);
2585 * RemoveAlignFromDescendants() removes align attributes, text-align
2586 * properties and <center> elements in aElement.
2588 * @param aElement Alignment information of the node and/or its
2589 * descendants will be removed.
2590 * NOTE: aElement must not be a `<table>` element.
2591 * @param aAlignType New align value to be set only when it's in
2592 * CSS mode and this method meets <table> or <hr>.
2593 * XXX This is odd and not clear when you see caller of
2594 * this method. Do you have better idea?
2595 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2596 * descendants of aElement.
2597 * If `NodeAndDescendantsExceptTable`, modifies `aElement`
2598 * and its descendants.
2599 * @return A candidate point to put caret.
2601 enum class EditTarget
{
2602 OnlyDescendantsExceptTable
,
2603 NodeAndDescendantsExceptTable
2605 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2606 RemoveAlignFromDescendants(Element
& aElement
, const nsAString
& aAlignType
,
2607 EditTarget aEditTarget
);
2610 * SetBlockElementAlign() resets `align` attribute, `text-align` property
2611 * of descendants of aBlockOrHRElement except `<table>` element descendants.
2612 * Then, set `align` attribute or `text-align` property of aBlockOrHRElement.
2614 * @param aBlockOrHRElement The element whose contents will be aligned.
2615 * This must be a block element or `<hr>` element.
2616 * If we're not in CSS mode, this element has
2617 * to support `align` attribute (i.e.,
2618 * `HTMLEditUtils::SupportsAlignAttr()` must
2620 * @param aAlignType Boundary or "center" which contents should be
2622 * @param aEditTarget If `OnlyDescendantsExceptTable`, modifies only
2623 * descendants of aBlockOrHRElement.
2624 * If `NodeAndDescendantsExceptTable`, modifies
2625 * aBlockOrHRElement and its descendants.
2626 * @return A candidate point to put caret.
2628 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
2629 SetBlockElementAlign(Element
& aBlockOrHRElement
, const nsAString
& aAlignType
,
2630 EditTarget aEditTarget
);
2633 * InsertDivElementToAlignContents() inserts a new <div> element (which has
2634 * only a padding <br> element) to aPointToInsert for a placeholder whose
2635 * contents will be aligned.
2637 * @param aPointToInsert A point to insert new empty <div>.
2638 * @param aAlignType New align attribute value where the contents
2639 * should be aligned to.
2640 * @param aEditingHost The editing host.
2641 * @return New <div> element which has only a padding <br>
2642 * element and is styled to align contents.
2644 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2645 InsertDivElementToAlignContents(const EditorDOMPoint
& aPointToInsert
,
2646 const nsAString
& aAlignType
,
2647 const Element
& aEditingHost
);
2650 * AlignNodesAndDescendants() make contents of nodes in aArrayOfContents and
2651 * their descendants aligned to aAlignType.
2653 * @param aAlignType New align attribute value where the contents
2654 * should be aligned to.
2655 * @param aEditingHost The editing host.
2656 * @return Last created <div> element which should contain
2657 * caret and candidate position which may be
2658 * outside the <div> element.
2660 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
2661 AlignNodesAndDescendants(
2662 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
2663 const nsAString
& aAlignType
, const Element
& aEditingHost
);
2666 * AlignContentsAtRanges() aligns contents around aRanges to aAlignType.
2668 * @param aRanges The ranges where should be aligned.
2669 * @param aAlignType New align attribute value where the contents
2670 * should be aligned to.
2671 * @param aEditingHost The editing host.
2673 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
AlignContentsAtRanges(
2674 AutoClonedSelectionRangeArray
& aRanges
, const nsAString
& aAlignType
,
2675 const Element
& aEditingHost
);
2678 * AlignAsSubAction() handles "align" command with `Selection`.
2680 * @param aAlignType New align attribute value where the contents
2681 * should be aligned to.
2682 * @param aEditingHost The editing host.
2684 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2685 AlignAsSubAction(const nsAString
& aAlignType
, const Element
& aEditingHost
);
2688 * AdjustCaretPositionAndEnsurePaddingBRElement() may adjust caret
2689 * position to nearest editable content and if padding `<br>` element is
2690 * necessary at caret position, this creates it.
2692 * @param aDirectionAndAmount Direction of the edit action.
2694 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2695 AdjustCaretPositionAndEnsurePaddingBRElement(
2696 nsIEditor::EDirection aDirectionAndAmount
);
2699 * EnsureSelectionInBodyOrDocumentElement() collapse `Selection` to the
2700 * primary `<body>` element or document element when `Selection` crosses
2701 * `<body>` element's boundary.
2703 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2704 EnsureSelectionInBodyOrDocumentElement();
2707 * InsertBRElementToEmptyListItemsAndTableCellsInRange() inserts
2708 * `<br>` element into empty list item or table cell elements between
2709 * aStartRef and aEndRef.
2711 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2712 InsertBRElementToEmptyListItemsAndTableCellsInRange(
2713 const RawRangeBoundary
& aStartRef
, const RawRangeBoundary
& aEndRef
);
2716 * RemoveEmptyNodesIn() removes all empty nodes in aRange. However, if
2717 * mail-cite node has only a `<br>` element, the node will be removed
2718 * but <br> element is moved to where the mail-cite node was.
2719 * XXX This method is expensive if aRange is too wide and may remove
2720 * unexpected empty element, e.g., it was created by JS, but we haven't
2721 * touched it. Cannot we remove this method and make guarantee that
2722 * empty nodes won't be created?
2724 * @param aRange Must be positioned.
2726 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2727 RemoveEmptyNodesIn(const EditorDOMRange
& aRange
);
2730 * SetSelectionInterlinePosition() may set interline position if caret is
2731 * positioned around `<br>` or block boundary. Don't call this when
2732 * `Selection` is not collapsed.
2734 void SetSelectionInterlinePosition();
2737 * Called by `HTMLEditor::OnEndHandlingTopLevelEditSubAction()`. This may
2738 * adjust Selection, remove unnecessary empty nodes, create `<br>` elements
2741 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2742 OnEndHandlingTopLevelEditSubActionInternal();
2745 * MoveSelectedContentsToDivElementToMakeItAbsolutePosition() looks for
2746 * a `<div>` element in selection first. If not, creates new `<div>`
2747 * element. Then, move all selected contents into the target `<div>`
2749 * Note that this creates AutoSelectionRestorer. Therefore, callers need
2750 * to check whether we have been destroyed even when this returns NS_OK.
2752 * @param aTargetElement Returns target `<div>` element which should be
2753 * changed to absolute positioned.
2754 * @param aEditingHost The editing host.
2756 // TODO: Rewrite this with `Result<RefPtr<Element>, nsresult>`.
2757 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2758 MoveSelectedContentsToDivElementToMakeItAbsolutePosition(
2759 RefPtr
<Element
>* aTargetElement
, const Element
& aEditingHost
);
2762 * SetSelectionToAbsoluteAsSubAction() move selected contents to first
2763 * selected `<div>` element or newly created `<div>` element and make
2764 * the `<div>` element positioned absolutely.
2766 * @param aEditingHost The editing host.
2768 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2769 SetSelectionToAbsoluteAsSubAction(const Element
& aEditingHost
);
2772 * SetSelectionToStaticAsSubAction() sets the `position` property of a
2773 * selection parent's block whose `position` is `absolute` to `static`.
2775 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2776 SetSelectionToStaticAsSubAction();
2779 * AddZIndexAsSubAction() adds aChange to `z-index` of nearest parent
2780 * absolute-positioned element from current selection.
2782 * @param aChange Amount to change `z-index`.
2784 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
2785 AddZIndexAsSubAction(int32_t aChange
);
2788 * OnDocumentModified() is called when editor content is changed.
2790 MOZ_CAN_RUN_SCRIPT nsresult
2791 OnDocumentModified(const nsIContent
* aContentWillBeRemoved
= nullptr);
2793 protected: // Called by helper classes.
2794 MOZ_CAN_RUN_SCRIPT
void OnStartToHandleTopLevelEditSubAction(
2795 EditSubAction aTopLevelEditSubAction
,
2796 nsIEditor::EDirection aDirectionOfTopLevelEditSubAction
,
2797 ErrorResult
& aRv
) final
;
2798 MOZ_CAN_RUN_SCRIPT nsresult
OnEndHandlingTopLevelEditSubAction() final
;
2800 protected: // Shouldn't be used by friend classes
2801 virtual ~HTMLEditor();
2804 * InitEditorContentAndSelection() may insert `<br>` elements and padding
2805 * `<br>` elements if they are required for `<body>` or document element.
2806 * And collapse selection at the end if there is no selection ranges.
2808 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InitEditorContentAndSelection();
2811 * Collapse `Selection` to the last leaf content of the <body> or the document
2814 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2815 CollapseSelectionToEndOfLastLeafNodeOfDocument() const;
2817 MOZ_CAN_RUN_SCRIPT nsresult
SelectAllInternal() final
;
2819 [[nodiscard
]] Element
* ComputeEditingHostInternal(
2820 const nsIContent
* aContent
, LimitInBodyElement aLimitInBodyElement
) const;
2823 * Creates a range with just the supplied node and appends that to the
2826 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
2827 AppendContentToSelectionAsRange(nsIContent
& aContent
);
2830 * When you are using AppendContentToSelectionAsRange(), call this first to
2831 * start a new selection.
2833 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
ClearSelection();
2836 * SelectContentInternal() sets Selection to aContentToSelect to
2837 * aContentToSelect + 1 in parent of aContentToSelect.
2839 * @param aContentToSelect The content which should be selected.
2841 MOZ_CAN_RUN_SCRIPT nsresult
2842 SelectContentInternal(nsIContent
& aContentToSelect
);
2845 * GetInclusiveAncestorByTagNameAtSelection() looks for an element node whose
2846 * name matches aTagName from anchor node of Selection to <body> element.
2848 * @param aTagName The tag name which you want to look for.
2849 * Must not be nsGkAtoms::_empty.
2850 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2852 * If nsGkAtoms::td, the result may be <td> or <th>.
2853 * If nsGkAtoms::href, the result may be <a> element
2854 * which has "href" attribute with non-empty value.
2855 * If nsGkAtoms::anchor, the result may be <a> which
2856 * has "name" attribute with non-empty value.
2857 * @return If an element which matches aTagName, returns
2858 * an Element. Otherwise, nullptr.
2860 Element
* GetInclusiveAncestorByTagNameAtSelection(
2861 const nsStaticAtom
& aTagName
) const;
2864 * GetInclusiveAncestorByTagNameInternal() looks for an element node whose
2865 * name matches aTagName from aNode to <body> element.
2867 * @param aTagName The tag name which you want to look for.
2868 * Must not be nsGkAtoms::_empty.
2869 * If nsGkAtoms::list, the result may be <ul>, <ol> or
2871 * If nsGkAtoms::td, the result may be <td> or <th>.
2872 * If nsGkAtoms::href, the result may be <a> element
2873 * which has "href" attribute with non-empty value.
2874 * If nsGkAtoms::anchor, the result may be <a> which
2875 * has "name" attribute with non-empty value.
2876 * @param aContent Start node to look for the element. This should
2877 * not be an orphan node.
2878 * @return If an element which matches aTagName, returns
2879 * an Element. Otherwise, nullptr.
2881 Element
* GetInclusiveAncestorByTagNameInternal(
2882 const nsStaticAtom
& aTagName
, const nsIContent
& aContent
) const;
2885 * GetSelectedElement() returns a "selected" element node. "selected" means:
2886 * - there is only one selection range
2887 * - the range starts from an element node or in an element
2888 * - the range ends at immediately after same element
2889 * - and the range does not include any other element nodes.
2890 * Additionally, only when aTagName is nsGkAtoms::href, this thinks that an
2891 * <a> element which has non-empty "href" attribute includes the range, the
2892 * <a> element is selected.
2894 * NOTE: This method is implementation of nsIHTMLEditor.getSelectedElement()
2895 * and comm-central depends on this behavior. Therefore, if you need to use
2896 * this method internally but you need to change, perhaps, you should create
2897 * another method for avoiding breakage of comm-central apps.
2899 * @param aTagName The atom of tag name in lower case. Set this to
2900 * result of EditorUtils::GetTagNameAtom() if you have a
2901 * tag name with nsString.
2902 * If nullptr, this returns any element node or nullptr.
2903 * If nsGkAtoms::href, this returns an <a> element which
2904 * has non-empty "href" attribute or nullptr.
2905 * If nsGkAtoms::anchor, this returns an <a> element which
2906 * has non-empty "name" attribute or nullptr.
2907 * Otherwise, returns an element node whose name is
2908 * same as aTagName or nullptr.
2909 * @param aRv Returns error code.
2910 * @return A "selected" element.
2912 already_AddRefed
<Element
> GetSelectedElement(const nsAtom
* aTagName
,
2916 * GetFirstTableRowElement() returns the first <tr> element in the most
2917 * nearest ancestor of aTableOrElementInTable or itself.
2918 * When aTableOrElementInTable is neither <table> nor in a <table> element,
2919 * returns NS_ERROR_FAILURE. However, if <table> does not have <tr> element,
2922 * @param aTableOrElementInTable <table> element or another element.
2923 * If this is a <table> element, returns
2924 * first <tr> element in it. Otherwise,
2925 * returns first <tr> element in nearest
2926 * ancestor <table> element.
2928 Result
<RefPtr
<Element
>, nsresult
> GetFirstTableRowElement(
2929 const Element
& aTableOrElementInTable
) const;
2932 * GetNextTableRowElement() returns next <tr> element of aTableRowElement.
2933 * This won't cross <table> element boundary but may cross table section
2934 * elements like <tbody>.
2935 * Note that if given element is <tr> but there is no next <tr> element, this
2936 * returns nullptr but does not return error.
2938 * @param aTableRowElement A <tr> element.
2940 Result
<RefPtr
<Element
>, nsresult
> GetNextTableRowElement(
2941 const Element
& aTableRowElement
) const;
2946 * CellIndexes store both row index and column index of a table cell.
2948 struct MOZ_STACK_CLASS CellIndexes final
{
2953 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2956 * @param aCellElement An <td> or <th> element.
2958 MOZ_CAN_RUN_SCRIPT
CellIndexes(Element
& aCellElement
, PresShell
* aPresShell
)
2959 : mRow(-1), mColumn(-1) {
2960 Update(aCellElement
, aPresShell
);
2964 * Update mRowIndex and mColumnIndex with indexes of aCellElement.
2968 MOZ_CAN_RUN_SCRIPT
void Update(Element
& aCellElement
,
2969 PresShell
* aPresShell
);
2972 * This constructor initializes mRowIndex and mColumnIndex with indexes of
2973 * cell element which contains anchor of Selection.
2975 * @param aHTMLEditor The editor which creates the instance.
2976 * @param aSelection The Selection for the editor.
2978 MOZ_CAN_RUN_SCRIPT
CellIndexes(HTMLEditor
& aHTMLEditor
,
2979 Selection
& aSelection
)
2980 : mRow(-1), mColumn(-1) {
2981 Update(aHTMLEditor
, aSelection
);
2985 * Update mRowIndex and mColumnIndex with indexes of cell element which
2986 * contains anchor of Selection.
2990 MOZ_CAN_RUN_SCRIPT
void Update(HTMLEditor
& aHTMLEditor
,
2991 Selection
& aSelection
);
2993 bool operator==(const CellIndexes
& aOther
) const {
2994 return mRow
== aOther
.mRow
&& mColumn
== aOther
.mColumn
;
2996 bool operator!=(const CellIndexes
& aOther
) const {
2997 return mRow
!= aOther
.mRow
|| mColumn
!= aOther
.mColumn
;
3000 [[nodiscard
]] bool isErr() const { return mRow
< 0 || mColumn
< 0; }
3003 CellIndexes() : mRow(-1), mColumn(-1) {}
3004 CellIndexes(int32_t aRowIndex
, int32_t aColumnIndex
)
3005 : mRow(aRowIndex
), mColumn(aColumnIndex
) {}
3007 friend struct CellData
;
3010 struct MOZ_STACK_CLASS CellData final
{
3011 MOZ_KNOWN_LIVE RefPtr
<Element
> mElement
;
3012 // Current indexes which this is initialized with.
3013 CellIndexes mCurrent
;
3014 // First column/row indexes of the cell. When current position is spanned
3015 // from other column/row, this value becomes different from mCurrent.
3017 // Computed rowspan/colspan values which are specified to the cell.
3018 // Note that if the cell has larger rowspan/colspan value than actual
3019 // table size, these values are the larger values.
3020 int32_t mRowSpan
= -1;
3021 int32_t mColSpan
= -1;
3022 // Effective rowspan/colspan value at the index. For example, if first
3023 // cell element in first row has rowspan="3", then, if this is initialized
3024 // with 0-0 indexes, effective rowspan is 3. However, if this is
3025 // initialized with 1-0 indexes, effective rowspan is 2.
3026 int32_t mEffectiveRowSpan
= -1;
3027 int32_t mEffectiveColSpan
= -1;
3028 // mIsSelected is set to true if mElement itself or its parent <tr> or
3029 // <table> is selected. Otherwise, e.g., the cell just contains selection
3030 // range, this is set to false.
3031 bool mIsSelected
= false;
3033 CellData() = delete;
3036 * This returns an instance which is initialized with a <table> element and
3037 * both row and column index to specify a cell element.
3039 [[nodiscard
]] static CellData
AtIndexInTableElement(
3040 const HTMLEditor
& aHTMLEditor
, const Element
& aTableElement
,
3041 int32_t aRowIndex
, int32_t aColumnIndex
);
3042 [[nodiscard
]] static CellData
AtIndexInTableElement(
3043 const HTMLEditor
& aHTMLEditor
, const Element
& aTableElement
,
3044 const CellIndexes
& aIndexes
) {
3045 MOZ_ASSERT(!aIndexes
.isErr());
3046 return AtIndexInTableElement(aHTMLEditor
, aTableElement
, aIndexes
.mRow
,
3051 * Treated as error if fails to compute current index or first index of the
3052 * cell. Note that even if the cell is not found due to no corresponding
3053 * frame at current index, it's not an error situation.
3055 [[nodiscard
]] bool isOk() const { return !isErr(); }
3056 [[nodiscard
]] bool isErr() const { return mFirst
.isErr(); }
3059 * FailedOrNotFound() returns true if this failed to initialize/update
3060 * or succeeded but found no cell element.
3062 [[nodiscard
]] bool FailedOrNotFound() const { return isErr() || !mElement
; }
3065 * IsSpannedFromOtherRowOrColumn(), IsSpannedFromOtherColumn and
3066 * IsSpannedFromOtherRow() return true if there is no cell element
3067 * at the index because of spanning from other row and/or column.
3069 [[nodiscard
]] bool IsSpannedFromOtherRowOrColumn() const {
3070 return mElement
&& mCurrent
!= mFirst
;
3072 [[nodiscard
]] bool IsSpannedFromOtherColumn() const {
3073 return mElement
&& mCurrent
.mColumn
!= mFirst
.mColumn
;
3075 [[nodiscard
]] bool IsSpannedFromOtherRow() const {
3076 return mElement
&& mCurrent
.mRow
!= mFirst
.mRow
;
3078 [[nodiscard
]] bool IsNextColumnSpannedFromOtherColumn() const {
3079 return mElement
&& mCurrent
.mColumn
+ 1 < NextColumnIndex();
3083 * NextColumnIndex() and NextRowIndex() return column/row index of
3084 * next cell. Note that this does not check whether there is next
3085 * cell or not actually.
3087 [[nodiscard
]] int32_t NextColumnIndex() const {
3088 if (NS_WARN_IF(FailedOrNotFound())) {
3091 return mCurrent
.mColumn
+ mEffectiveColSpan
;
3093 [[nodiscard
]] int32_t NextRowIndex() const {
3094 if (NS_WARN_IF(FailedOrNotFound())) {
3097 return mCurrent
.mRow
+ mEffectiveRowSpan
;
3101 * LastColumnIndex() and LastRowIndex() return column/row index of
3102 * column/row which is spanned by the cell.
3104 [[nodiscard
]] int32_t LastColumnIndex() const {
3105 if (NS_WARN_IF(FailedOrNotFound())) {
3108 return NextColumnIndex() - 1;
3110 [[nodiscard
]] int32_t LastRowIndex() const {
3111 if (NS_WARN_IF(FailedOrNotFound())) {
3114 return NextRowIndex() - 1;
3118 * NumberOfPrecedingColmuns() and NumberOfPrecedingRows() return number of
3119 * preceding columns/rows if current index is spanned from other column/row.
3120 * Otherwise, i.e., current point is not spanned form other column/row,
3123 [[nodiscard
]] int32_t NumberOfPrecedingColmuns() const {
3124 if (NS_WARN_IF(FailedOrNotFound())) {
3127 return mCurrent
.mColumn
- mFirst
.mColumn
;
3129 [[nodiscard
]] int32_t NumberOfPrecedingRows() const {
3130 if (NS_WARN_IF(FailedOrNotFound())) {
3133 return mCurrent
.mRow
- mFirst
.mRow
;
3137 * NumberOfFollowingColumns() and NumberOfFollowingRows() return
3138 * number of remaining columns/rows if the cell spans to other
3141 [[nodiscard
]] int32_t NumberOfFollowingColumns() const {
3142 if (NS_WARN_IF(FailedOrNotFound())) {
3145 return mEffectiveColSpan
- 1;
3147 [[nodiscard
]] int32_t NumberOfFollowingRows() const {
3148 if (NS_WARN_IF(FailedOrNotFound())) {
3151 return mEffectiveRowSpan
- 1;
3155 explicit CellData(int32_t aCurrentRowIndex
, int32_t aCurrentColumnIndex
,
3156 int32_t aFirstRowIndex
, int32_t aFirstColumnIndex
)
3157 : mCurrent(aCurrentRowIndex
, aCurrentColumnIndex
),
3158 mFirst(aFirstRowIndex
, aFirstColumnIndex
) {}
3159 explicit CellData(Element
& aElement
, int32_t aRowIndex
,
3160 int32_t aColumnIndex
, nsTableCellFrame
& aTableCellFrame
,
3161 nsTableWrapperFrame
& aTableWrapperFrame
);
3163 [[nodiscard
]] static CellData
Error(int32_t aRowIndex
,
3164 int32_t aColumnIndex
) {
3165 return CellData(aRowIndex
, aColumnIndex
, -1, -1);
3167 [[nodiscard
]] static CellData
NotFound(int32_t aRowIndex
,
3168 int32_t aColumnIndex
) {
3169 return CellData(aRowIndex
, aColumnIndex
, aRowIndex
, aColumnIndex
);
3174 * TableSize stores and computes number of rows and columns of a <table>
3177 struct MOZ_STACK_CLASS TableSize final
{
3179 int32_t mColumnCount
;
3181 TableSize() = delete;
3184 * @param aHTMLEditor The editor which creates the instance.
3185 * @param aTableOrElementInTable If a <table> element, computes number
3186 * of rows and columns of it.
3187 * If another element in a <table> element,
3188 * computes number of rows and columns
3189 * of nearest ancestor <table> element.
3190 * Otherwise, i.e., non-<table> element
3191 * not in <table>, returns error.
3193 [[nodiscard
]] static Result
<TableSize
, nsresult
> Create(
3194 HTMLEditor
& aHTMLEditor
, Element
& aTableOrElementInTable
);
3196 [[nodiscard
]] bool IsEmpty() const { return !mRowCount
|| !mColumnCount
; }
3199 TableSize(int32_t aRowCount
, int32_t aColumCount
)
3200 : mRowCount(aRowCount
), mColumnCount(aColumCount
) {}
3204 * GetTableCellElementAt() returns a <td> or <th> element of aTableElement
3205 * if there is a cell at the indexes.
3207 * @param aTableElement Must be a <table> element.
3208 * @param aCellIndexes Indexes of cell which you want.
3209 * If rowspan and/or colspan is specified 2 or
3210 * larger, any indexes are allowed to retrieve
3211 * the cell in the area.
3212 * @return The cell element if there is in the <table>.
3213 * Returns nullptr without error if the indexes
3214 * are out of bounds.
3216 [[nodiscard
]] inline Element
* GetTableCellElementAt(
3217 Element
& aTableElement
, const CellIndexes
& aCellIndexes
) const;
3218 [[nodiscard
]] Element
* GetTableCellElementAt(Element
& aTableElement
,
3220 int32_t aColumnIndex
) const;
3223 * GetSelectedOrParentTableElement() returns <td>, <th>, <tr> or <table>
3225 * #1 if the first selection range selects a cell, returns it.
3226 * #2 if the first selection range does not select a cell and
3227 * the selection anchor refers a <table>, returns it.
3228 * #3 if the first selection range does not select a cell and
3229 * the selection anchor refers a <tr>, returns it.
3230 * #4 if the first selection range does not select a cell and
3231 * the selection anchor refers a <td>, returns it.
3232 * #5 otherwise, nearest ancestor <td> or <th> element of the
3233 * selection anchor if there is.
3234 * In #1 and #4, *aIsCellSelected will be set to true (i.e,, when
3235 * a selection range selects a cell element).
3237 Result
<RefPtr
<Element
>, nsresult
> GetSelectedOrParentTableElement(
3238 bool* aIsCellSelected
= nullptr) const;
3241 * GetFirstSelectedCellElementInTable() returns <td> or <th> element at
3242 * first selection (using GetSelectedOrParentTableElement). If found cell
3243 * element is not in <table> or <tr> element, this returns nullptr.
3245 Result
<RefPtr
<Element
>, nsresult
> GetFirstSelectedCellElementInTable() const;
3247 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3248 HandlePaste(AutoEditActionDataSetter
& aEditActionData
,
3249 nsIClipboard::ClipboardType aClipboardType
,
3250 DataTransfer
* aDataTransfer
) final
;
3251 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3252 HandlePasteAsQuotation(AutoEditActionDataSetter
& aEditActionData
,
3253 nsIClipboard::ClipboardType aClipboardType
,
3254 DataTransfer
* aDataTransfer
) final
;
3255 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3256 HandlePasteTransferable(AutoEditActionDataSetter
& aEditActionData
,
3257 nsITransferable
& aTransferable
) final
;
3260 * PasteInternal() pasts text with replacing selected content.
3261 * This tries to dispatch ePaste event first. If its defaultPrevent() is
3262 * called, this does nothing but returns NS_OK.
3264 * @param aClipboardType nsIClipboard::kGlobalClipboard or
3265 * nsIClipboard::kSelectionClipboard.
3266 * @param aEditingHost The editing host.
3268 MOZ_CAN_RUN_SCRIPT nsresult
3269 PasteInternal(nsIClipboard::ClipboardType aClipboardType
,
3270 DataTransfer
* aDataTransfer
, const Element
& aEditingHost
);
3272 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3273 InsertWithQuotationsAsSubAction(const nsAString
& aQuotedText
) final
;
3276 * InsertAsCitedQuotationInternal() inserts a <blockquote> element whose
3277 * cite attribute is aCitation and whose content is aQuotedText.
3278 * Note that this shouldn't be called when IsPlaintextMailComposer() is true.
3280 * @param aQuotedText HTML source if aInsertHTML is true. Otherwise,
3281 * plain text. This is inserted into new <blockquote>
3283 * @param aCitation cite attribute value of new <blockquote> element.
3284 * @param aInsertHTML true if aQuotedText should be treated as HTML
3286 * false if aQuotedText should be treated as plain
3288 * @param aEditingHost The editing host.
3289 * @param aNodeInserted [OUT] The new <blockquote> element.
3291 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertAsCitedQuotationInternal(
3292 const nsAString
& aQuotedText
, const nsAString
& aCitation
,
3293 bool aInsertHTML
, const Element
& aEditingHost
, nsINode
** aNodeInserted
);
3296 * InsertNodeIntoProperAncestorWithTransaction() attempts to insert aNode
3297 * into the document, at aPointToInsert. Checks with strict dtd to see if
3298 * containment is allowed. If not allowed, will attempt to find a parent
3299 * in the parent hierarchy of aPointToInsert.GetContainer() that will accept
3300 * aNode as a child. If such a parent is found, will split the document
3301 * tree from aPointToInsert up to parent, and then insert aNode.
3302 * aPointToInsert is then adjusted to point to the actual location that
3303 * aNode was inserted at. aSplitAtEdges specifies if the splitting process
3304 * is allowed to result in empty nodes.
3306 * @param aContent The content node to insert.
3307 * @param aPointToInsert Insertion point.
3308 * @param aSplitAtEdges Splitting can result in empty nodes?
3310 template <typename NodeType
>
3311 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT
3312 Result
<CreateNodeResultBase
<NodeType
>, nsresult
>
3313 InsertNodeIntoProperAncestorWithTransaction(
3314 NodeType
& aContent
, const EditorDOMPoint
& aPointToInsert
,
3315 SplitAtEdges aSplitAtEdges
);
3318 * InsertTextWithQuotationsInternal() replaces selection with new content.
3319 * First, this method splits aStringToInsert to multiple chunks which start
3320 * with non-linebreaker except first chunk and end with a linebreaker except
3321 * last chunk. Then, each chunk starting with ">" is inserted after wrapping
3322 * with <span _moz_quote="true">, and each chunk not starting with ">" is
3323 * inserted as normal text.
3325 MOZ_CAN_RUN_SCRIPT nsresult
InsertTextWithQuotationsInternal(
3326 const nsAString
& aStringToInsert
, const Element
& aEditingHost
);
3329 * ReplaceContainerWithTransactionInternal() is implementation of
3330 * ReplaceContainerWithTransaction() and
3331 * ReplaceContainerAndCloneAttributesWithTransaction().
3333 * @param aOldContainer The element which will be replaced with new
3335 * @param aTagName The name of new element node.
3336 * @param aAttribute Attribute name which will be set to the new
3337 * element. This will be ignored if
3338 * aCloneAllAttributes is set to true.
3339 * @param aAttributeValue Attribute value which will be set to
3341 * @param aCloneAllAttributes If true, all attributes of aOldContainer will
3342 * be copied to the new element.
3344 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
3345 ReplaceContainerWithTransactionInternal(Element
& aOldContainer
,
3346 const nsAtom
& aTagName
,
3347 const nsAtom
& aAttribute
,
3348 const nsAString
& aAttributeValue
,
3349 bool aCloneAllAttributes
);
3352 * DeleteSelectionAndCreateElement() creates a element whose name is aTag.
3353 * And insert it into the DOM tree after removing the selected content.
3355 * @param aTag The element name to be created.
3356 * @param aInitializer A function to initialize the new element before
3357 * or after (depends on the pref) connecting the
3358 * element into the DOM tree. Note that this should
3359 * not touch outside given element because doing it
3360 * would break range updater's result.
3362 MOZ_CAN_RUN_SCRIPT Result
<RefPtr
<Element
>, nsresult
>
3363 DeleteSelectionAndCreateElement(
3365 const InitializeInsertingElement
& aInitializer
= DoNothingForNewElement
);
3368 * This method first deletes the selection, if it's not collapsed. Then if
3369 * the selection lies in a CharacterData node, it splits it. If the
3370 * selection is at this point collapsed in a CharacterData node, it's
3371 * adjusted to be collapsed right before or after the node instead (which is
3372 * always possible, since the node was split).
3374 MOZ_CAN_RUN_SCRIPT nsresult
DeleteSelectionAndPrepareToCreateNode();
3377 * PrepareToInsertLineBreak() returns a point where a new line break node
3378 * should be inserted. If aPointToInsert points middle of a text node, this
3379 * method splits the text node and returns the point before right node.
3381 * @param aLineBreakType Whether you will insert <br> or a preformatted
3383 * @param aPointToInsert Candidate point to insert new line break node.
3384 * @return Computed point to insert new line break node.
3385 * If something failed, this return error.
3387 MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
> PrepareToInsertLineBreak(
3388 LineBreakType aLineBreakType
, const EditorDOMPoint
& aPointToInsert
);
3391 * If unnecessary line break is there immediately after aPoint, this deletes
3392 * the line break. Note that unnecessary line break means that the line break
3393 * is a padding line break for empty line immediately before a block boundary
3394 * and it's not a placeholder of ancestor inline elements.
3396 * @param aNextOrAfterModifiedPoint If you inserted something, this should
3397 * be next point or after the inserted
3399 * If you deleted something, this should be
3400 * end of the deleted range.
3402 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3403 EnsureNoFollowingUnnecessaryLineBreak(
3404 const EditorDOMPoint
& aNextOrAfterModifiedPoint
);
3407 * IndentAsSubAction() indents the content around Selection.
3409 * @param aEditingHost The editing host.
3411 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
3412 IndentAsSubAction(const Element
& aEditingHost
);
3415 * OutdentAsSubAction() outdents the content around Selection.
3417 * @param aEditingHost The editing host.
3419 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
3420 OutdentAsSubAction(const Element
& aEditingHost
);
3422 MOZ_CAN_RUN_SCRIPT nsresult
LoadHTML(const nsAString
& aInputString
);
3425 * UpdateMetaCharsetWithTransaction() scans all <meta> elements in the
3426 * document and if and only if there is a <meta> element having `httpEquiv`
3427 * attribute and whose value includes `content-type`, updates its `content`
3428 * attribute value to aCharacterSet.
3430 MOZ_CAN_RUN_SCRIPT
bool UpdateMetaCharsetWithTransaction(
3431 Document
& aDocument
, const nsACString
& aCharacterSet
);
3434 * SetInlinePropertiesAsSubAction() stores new styles with
3435 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3436 * applying the styles to all selected contents.
3438 * @param aStylesToSet The styles which should be applied to the
3440 * @param aEditingHost The editing host.
3443 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertiesAsSubAction(
3444 const AutoTArray
<EditorInlineStyleAndValue
, N
>& aStylesToSet
,
3445 const Element
& aEditingHost
);
3448 * SetInlinePropertiesAroundRanges() applying the styles to the ranges even if
3449 * the ranges are collapsed.
3452 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetInlinePropertiesAroundRanges(
3453 AutoClonedRangeArray
& aRanges
,
3454 const AutoTArray
<EditorInlineStyleAndValue
, N
>& aStylesToSet
);
3457 * RemoveInlinePropertiesAsSubAction() removes specified styles from
3458 * mPendingStylesToApplyToNewContent if `Selection` is collapsed. Otherwise,
3459 * removing the style.
3461 * @param aStylesToRemove Styles to remove from the selected contents.
3462 * @param aEditingHost The editing host.
3464 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
RemoveInlinePropertiesAsSubAction(
3465 const nsTArray
<EditorInlineStyle
>& aStylesToRemove
,
3466 const Element
& aEditingHost
);
3469 * Helper method to call RemoveInlinePropertiesAsSubAction(). If you want to
3470 * remove other elements to remove the style completely, this will append
3471 * related elements of aStyleToRemove and aStyleToRemove itself to the array.
3472 * E.g., nsGkAtoms::strong and nsGkAtoms::b will be appended if aStyleToRemove
3475 void AppendInlineStyleAndRelatedStyle(
3476 const EditorInlineStyle
& aStyleToRemove
,
3477 nsTArray
<EditorInlineStyle
>& aStylesToRemove
) const;
3480 * ReplaceHeadContentsWithSourceWithTransaction() replaces all children of
3481 * <head> element with given source code. This is undoable.
3483 * @param aSourceToInsert HTML source fragment to replace the children
3484 * of <head> element.
3486 MOZ_CAN_RUN_SCRIPT nsresult
ReplaceHeadContentsWithSourceWithTransaction(
3487 const nsAString
& aSourceToInsert
);
3489 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetCSSBackgroundColorState(
3490 bool* aMixed
, nsAString
& aOutColor
, bool aBlockLevel
);
3491 nsresult
GetHTMLBackgroundColorState(bool* aMixed
, nsAString
& outColor
);
3494 * This sets background on the appropriate container element (table, cell,)
3495 * or calls to set the page background.
3497 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3498 SetBlockBackgroundColorWithCSSAsSubAction(const nsAString
& aColor
);
3499 MOZ_CAN_RUN_SCRIPT nsresult
3500 SetHTMLBackgroundColorWithTransaction(const nsAString
& aColor
);
3502 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void InitializeSelectionAncestorLimit(
3503 Element
& aAncestorLimit
) const final
;
3506 * Make the given selection span the entire document.
3508 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SelectEntireDocument() final
;
3511 * Use this to assure that selection is set after attribute nodes when
3512 * trying to collapse selection at begining of a block node
3513 * e.g., when setting at beginning of a table cell
3514 * This will stop at a table, however, since we don't want to
3515 * "drill down" into nested tables.
3517 MOZ_CAN_RUN_SCRIPT
void CollapseSelectionToDeepestNonTableFirstChild(
3520 * MaybeCollapseSelectionAtFirstEditableNode() may collapse selection at
3521 * proper position to staring to edit. If there is a non-editable node
3522 * before any editable text nodes or inline elements which can have text
3523 * nodes as their children, collapse selection at start of the editing
3524 * host. If there is an editable text node which is not collapsed, collapses
3525 * selection at the start of the text node. If there is an editable inline
3526 * element which cannot have text nodes as its child, collapses selection at
3527 * before the element node. Otherwise, collapses selection at start of the
3530 * @param aIgnoreIfSelectionInEditingHost
3531 * This method does nothing if selection is in the
3532 * editing host except if it's collapsed at start of
3534 * Note that if selection ranges were outside of
3535 * current selection limiter, selection was collapsed
3536 * at the start of the editing host therefore, if
3537 * you call this with setting this to true, you can
3538 * keep selection ranges if user has already been
3541 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
3542 MaybeCollapseSelectionAtFirstEditableNode(
3543 bool aIgnoreIfSelectionInEditingHost
) const;
3545 class BlobReader final
{
3546 using AutoEditActionDataSetter
= EditorBase::AutoEditActionDataSetter
;
3549 MOZ_CAN_RUN_SCRIPT
BlobReader(dom::BlobImpl
* aBlob
, HTMLEditor
* aHTMLEditor
,
3550 SafeToInsertData aSafeToInsertData
,
3551 const EditorDOMPoint
& aPointToInsert
,
3552 DeleteSelectedContent aDeleteSelectedContent
,
3553 const Element
& aEditingHost
);
3555 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(BlobReader
)
3556 NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(BlobReader
)
3558 MOZ_CAN_RUN_SCRIPT nsresult
OnResult(const nsACString
& aResult
);
3559 nsresult
OnError(const nsAString
& aErrorName
);
3562 ~BlobReader() = default;
3564 RefPtr
<dom::BlobImpl
> mBlob
;
3565 RefPtr
<HTMLEditor
> mHTMLEditor
;
3566 RefPtr
<const Element
> mEditingHost
;
3567 RefPtr
<DataTransfer
> mDataTransfer
;
3568 EditorDOMPoint mPointToInsert
;
3569 EditAction mEditAction
;
3570 SafeToInsertData mSafeToInsertData
;
3571 DeleteSelectedContent mDeleteSelectedContent
;
3572 bool mNeedsToDispatchBeforeInputEvent
;
3575 void CreateEventListeners() final
;
3576 nsresult
InstallEventListeners() final
;
3578 bool ShouldReplaceRootElement() const;
3579 MOZ_CAN_RUN_SCRIPT
void NotifyRootChanged();
3580 Element
* GetBodyElement() const;
3583 * Get the focused node of this editor.
3584 * @return If the editor has focus, this returns the focused node.
3585 * Otherwise, returns null.
3587 nsINode
* GetFocusedNode() const;
3589 already_AddRefed
<Element
> GetInputEventTargetElement() const final
;
3592 * Return TRUE if aElement is a table-related elemet and caret was set.
3594 MOZ_CAN_RUN_SCRIPT
bool SetCaretInTableCell(dom::Element
* aElement
);
3597 * HandleTabKeyPressInTable() handles "Tab" key press in table if selection
3598 * is in a `<table>` element.
3600 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditActionResult
, nsresult
>
3601 HandleTabKeyPressInTable(WidgetKeyboardEvent
* aKeyboardEvent
);
3604 * InsertPosition is an enum to indicate where the method should insert to.
3606 enum class InsertPosition
{
3607 // Before selected cell or a cell containing first selection range.
3608 eBeforeSelectedCell
,
3609 // After selected cell or a cell containing first selection range.
3614 * InsertTableCellsWithTransaction() inserts <td> elements at aPointToInsert.
3615 * Note that this simply inserts <td> elements, i.e., colspan and rowspan
3616 * around the cell containing selection are not modified. So, for example,
3617 * adding a cell to rectangular table changes non-rectangular table.
3618 * And if the cell containing selection is at left of row-spanning cell,
3619 * it may be moved to right side of the row-spanning cell after inserting
3620 * some cell elements before it. Similarly, colspan won't be adjusted
3621 * for keeping table rectangle.
3622 * Finally, puts caret into previous cell of the insertion point or the
3623 * first inserted cell if aPointToInsert is start of the row.
3625 * @param aPointToInsert The place to insert one or more cell
3626 * elements. The container must be a
3628 * @param aNumberOfCellsToInsert Number of cells to insert.
3629 * @return The first inserted cell element and
3630 * start of the last inserted cell element
3631 * as a point to put caret.
3633 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<CreateElementResult
, nsresult
>
3634 InsertTableCellsWithTransaction(const EditorDOMPoint
& aPointToInsert
,
3635 int32_t aNumberOfCellsToInsert
);
3638 * InsertTableColumnsWithTransaction() inserts cell elements to every rows
3639 * at same column index as the cell specified by aPointToInsert.
3641 * @param aNumberOfColumnsToInsert Number of columns to insert.
3643 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertTableColumnsWithTransaction(
3644 const EditorDOMPoint
& aPointToInsert
, int32_t aNumberOfColumnsToInsert
);
3647 * InsertTableRowsWithTransaction() inserts <tr> elements before or after
3648 * aCellElement. When aCellElement spans rows and aInsertPosition is
3649 * eAfterSelectedCell, new rows will be inserted after the most-bottom row
3650 * which contains the cell.
3652 * @param aCellElement The cell element pinting where this will
3653 * insert a row before or after.
3654 * @param aNumberOfRowsToInsert Number of rows to insert.
3655 * @param aInsertPosition Before or after the target cell which
3656 * contains first selection range.
3658 MOZ_CAN_RUN_SCRIPT nsresult
InsertTableRowsWithTransaction(
3659 Element
& aCellElement
, int32_t aNumberOfRowsToInsert
,
3660 InsertPosition aInsertPosition
);
3663 * Insert a new cell after or before supplied aCell.
3664 * Optional: If aNewCell supplied, returns the newly-created cell (addref'd,
3666 * This doesn't change or use the current selection.
3668 MOZ_CAN_RUN_SCRIPT nsresult
InsertCell(Element
* aCell
, int32_t aRowSpan
,
3669 int32_t aColSpan
, bool aAfter
,
3670 bool aIsHeader
, Element
** aNewCell
);
3673 * DeleteSelectedTableColumnsWithTransaction() removes cell elements which
3674 * belong to same columns of selected cell elements.
3675 * If only one cell element is selected or first selection range is
3676 * in a cell, removes cell elements which belong to same column.
3677 * If 2 or more cell elements are selected, removes cell elements which
3678 * belong to any of all selected columns. In this case,
3679 * aNumberOfColumnsToDelete is ignored.
3680 * If there is no selection ranges, returns error.
3681 * If selection is not in a cell element, this does not return error,
3682 * just does nothing.
3683 * WARNING: This does not remove <col> nor <colgroup> elements.
3685 * @param aNumberOfColumnsToDelete Number of columns to remove. This is
3686 * ignored if 2 ore more cells are
3689 MOZ_CAN_RUN_SCRIPT nsresult
3690 DeleteSelectedTableColumnsWithTransaction(int32_t aNumberOfColumnsToDelete
);
3693 * DeleteTableColumnWithTransaction() removes cell elements which belong
3694 * to the specified column.
3695 * This method adjusts colspan attribute value if cells spanning the
3697 * WARNING: This does not remove <col> nor <colgroup> elements.
3699 * @param aTableElement The <table> element which contains the
3700 * column which you want to remove.
3701 * @param aRowIndex Index of the column which you want to remove.
3702 * 0 is the first column.
3704 MOZ_CAN_RUN_SCRIPT nsresult
DeleteTableColumnWithTransaction(
3705 Element
& aTableElement
, int32_t aColumnIndex
);
3708 * DeleteSelectedTableRowsWithTransaction() removes <tr> elements.
3709 * If only one cell element is selected or first selection range is
3710 * in a cell, removes <tr> elements starting from a <tr> element
3711 * containing the selected cell or first selection range.
3712 * If 2 or more cell elements are selected, all <tr> elements
3713 * which contains selected cell(s). In this case, aNumberOfRowsToDelete
3715 * If there is no selection ranges, returns error.
3716 * If selection is not in a cell element, this does not return error,
3717 * just does nothing.
3719 * @param aNumberOfRowsToDelete Number of rows to remove. This is ignored
3720 * if 2 or more cells are selected.
3722 MOZ_CAN_RUN_SCRIPT nsresult
3723 DeleteSelectedTableRowsWithTransaction(int32_t aNumberOfRowsToDelete
);
3726 * DeleteTableRowWithTransaction() removes a <tr> element whose index in
3727 * the <table> is aRowIndex.
3728 * This method adjusts rowspan attribute value if the <tr> element contains
3729 * cells which spans rows.
3731 * @param aTableElement The <table> element which contains the
3732 * <tr> element which you want to remove.
3733 * @param aRowIndex Index of the <tr> element which you want to
3734 * remove. 0 is the first row.
3736 MOZ_CAN_RUN_SCRIPT nsresult
3737 DeleteTableRowWithTransaction(Element
& aTableElement
, int32_t aRowIndex
);
3740 * DeleteTableCellWithTransaction() removes table cell elements. If two or
3741 * more cell elements are selected, this removes all selected cell elements.
3742 * Otherwise, this removes some cell elements starting from selected cell
3743 * element or a cell containing first selection range. When this removes
3744 * last cell element in <tr> or <table>, this removes the <tr> or the
3745 * <table> too. Note that when removing a cell causes number of its row
3746 * becomes less than the others, this method does NOT fill the place with
3747 * rowspan nor colspan. This does not return error even if selection is not
3748 * in cell element, just does nothing.
3750 * @param aNumberOfCellsToDelete Number of cells to remove. This is ignored
3751 * if 2 or more cells are selected.
3753 MOZ_CAN_RUN_SCRIPT nsresult
3754 DeleteTableCellWithTransaction(int32_t aNumberOfCellsToDelete
);
3757 * DeleteAllChildrenWithTransaction() removes all children of aElement from
3760 * @param aElement The element whose children you want to remove.
3762 MOZ_CAN_RUN_SCRIPT nsresult
3763 DeleteAllChildrenWithTransaction(Element
& aElement
);
3766 * Move all contents from aCellToMerge into aTargetCell (append at end).
3768 MOZ_CAN_RUN_SCRIPT nsresult
MergeCells(RefPtr
<Element
> aTargetCell
,
3769 RefPtr
<Element
> aCellToMerge
,
3770 bool aDeleteCellToMerge
);
3773 * DeleteTableElementAndChildren() removes aTableElement (and its children)
3774 * from the DOM tree with transaction.
3776 * @param aTableElement The <table> element which you want to remove.
3778 MOZ_CAN_RUN_SCRIPT nsresult
3779 DeleteTableElementAndChildrenWithTransaction(Element
& aTableElement
);
3781 MOZ_CAN_RUN_SCRIPT nsresult
SetColSpan(Element
* aCell
, int32_t aColSpan
);
3782 MOZ_CAN_RUN_SCRIPT nsresult
SetRowSpan(Element
* aCell
, int32_t aRowSpan
);
3785 * Helper used to get nsTableWrapperFrame for a table.
3787 static nsTableWrapperFrame
* GetTableFrame(const Element
* aTable
);
3790 * GetNumberOfCellsInRow() returns number of actual cell elements in the row.
3791 * If some cells appear by "rowspan" in other rows, they are ignored.
3793 * @param aTableElement The <table> element.
3794 * @param aRowIndex Valid row index in aTableElement. This method
3795 * counts cell elements in the row.
3796 * @return -1 if this meets unexpected error.
3797 * Otherwise, number of cells which this method found.
3799 int32_t GetNumberOfCellsInRow(Element
& aTableElement
, int32_t aRowIndex
);
3802 * Test if all cells in row or column at given index are selected.
3804 bool AllCellsInRowSelected(Element
* aTable
, int32_t aRowIndex
,
3805 int32_t aNumberOfColumns
);
3806 bool AllCellsInColumnSelected(Element
* aTable
, int32_t aColIndex
,
3807 int32_t aNumberOfRows
);
3809 bool IsEmptyCell(Element
* aCell
);
3812 * Most insert methods need to get the same basic context data.
3813 * Any of the pointers may be null if you don't need that datum (for more
3815 * Input: *aCell is a known cell,
3816 * if null, cell is obtained from the anchor node of the selection.
3817 * Returns NS_EDITOR_ELEMENT_NOT_FOUND if cell is not found even if aCell is
3820 MOZ_CAN_RUN_SCRIPT nsresult
GetCellContext(Element
** aTable
, Element
** aCell
,
3821 nsINode
** aCellParent
,
3822 int32_t* aCellOffset
,
3824 int32_t* aColIndex
);
3826 nsresult
GetCellSpansAt(Element
* aTable
, int32_t aRowIndex
, int32_t aColIndex
,
3827 int32_t& aActualRowSpan
, int32_t& aActualColSpan
);
3829 MOZ_CAN_RUN_SCRIPT nsresult
SplitCellIntoColumns(
3830 Element
* aTable
, int32_t aRowIndex
, int32_t aColIndex
,
3831 int32_t aColSpanLeft
, int32_t aColSpanRight
, Element
** aNewCell
);
3833 MOZ_CAN_RUN_SCRIPT nsresult
SplitCellIntoRows(
3834 Element
* aTable
, int32_t aRowIndex
, int32_t aColIndex
,
3835 int32_t aRowSpanAbove
, int32_t aRowSpanBelow
, Element
** aNewCell
);
3837 MOZ_CAN_RUN_SCRIPT nsresult
CopyCellBackgroundColor(Element
* aDestCell
,
3838 Element
* aSourceCell
);
3841 * Reduce rowspan/colspan when cells span into nonexistent rows/columns.
3843 MOZ_CAN_RUN_SCRIPT nsresult
FixBadRowSpan(Element
* aTable
, int32_t aRowIndex
,
3844 int32_t& aNewRowCount
);
3845 MOZ_CAN_RUN_SCRIPT nsresult
FixBadColSpan(Element
* aTable
, int32_t aColIndex
,
3846 int32_t& aNewColCount
);
3849 * XXX NormalizeTableInternal() is broken. If it meets a cell which has
3850 * bigger or smaller rowspan or colspan than actual number of cells,
3851 * this always failed to scan the table. Therefore, this does nothing
3852 * when the table should be normalized.
3854 * @param aTableOrElementInTable An element which is in a <table> element
3855 * or <table> element itself. Otherwise,
3856 * this returns NS_OK but does nothing.
3858 MOZ_CAN_RUN_SCRIPT nsresult
3859 NormalizeTableInternal(Element
& aTableOrElementInTable
);
3862 * Fallback method: Call this after using ClearSelection() and you
3863 * failed to set selection to some other content in the document.
3865 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetSelectionAtDocumentStart();
3867 // Methods for handling plaintext quotations
3868 MOZ_CAN_RUN_SCRIPT nsresult
PasteAsPlaintextQuotation(
3869 nsIClipboard::ClipboardType aSelectionType
, DataTransfer
* aDataTransfer
,
3870 const Element
& aEditingHost
);
3872 enum class AddCites
{ No
, Yes
};
3874 * Insert a string as quoted text, replacing the selected text (if any).
3875 * @param aQuotedText The string to insert.
3876 * @param aAddCites Whether to prepend extra ">" to each line
3877 * (usually true, unless those characters
3878 * have already been added.)
3879 * @param aEditingHost The editing host.
3880 * @return aNodeInserted The node spanning the insertion, if applicable.
3881 * If aAddCites is false, this will be null.
3883 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertAsPlaintextQuotation(
3884 const nsAString
& aQuotedText
, AddCites aAddCites
,
3885 const Element
& aEditingHost
, nsINode
** aNodeInserted
= nullptr);
3888 * InsertObject() inserts given object at aPointToInsert.
3890 * @param aType one of kFileMime, kJPEGImageMime, kJPGImageMime,
3891 * kPNGImageMime, kGIFImageMime.
3893 MOZ_CAN_RUN_SCRIPT nsresult
InsertObject(
3894 const nsACString
& aType
, nsISupports
* aObject
,
3895 SafeToInsertData aSafeToInsertData
, const EditorDOMPoint
& aPointToInsert
,
3896 DeleteSelectedContent aDeleteSelectedContent
,
3897 const Element
& aEditingHost
);
3899 class HTMLTransferablePreparer
;
3900 nsresult
PrepareHTMLTransferable(nsITransferable
** aTransferable
,
3901 const Element
* aEditingHost
) const;
3903 enum class HavePrivateHTMLFlavor
{ No
, Yes
};
3904 MOZ_CAN_RUN_SCRIPT nsresult
InsertFromTransferableAtSelection(
3905 nsITransferable
* aTransferable
, const nsAString
& aContextStr
,
3906 const nsAString
& aInfoStr
, HavePrivateHTMLFlavor aHavePrivateHTMLFlavor
,
3907 const Element
& aEditingHost
);
3910 * InsertFromDataTransfer() is called only when user drops data into
3911 * this editor. Don't use this method for other purposes.
3913 * @param aIndex index of aDataTransfer's item to insert.
3915 MOZ_CAN_RUN_SCRIPT nsresult
InsertFromDataTransfer(
3916 const DataTransfer
* aDataTransfer
, uint32_t aIndex
,
3917 nsIPrincipal
* aSourcePrincipal
, const EditorDOMPoint
& aDroppedAt
,
3918 DeleteSelectedContent aDeleteSelectedContent
,
3919 const Element
& aEditingHost
);
3921 static HavePrivateHTMLFlavor
DataTransferOrClipboardHasPrivateHTMLFlavor(
3922 DataTransfer
* aDataTransfer
, nsIClipboard
* clipboard
);
3926 * <https://docs.microsoft.com/en-us/windows/win32/dataxchg/html-clipboard-format>.
3928 * @param[in] aCfhtml a CF_HTML string as defined above.
3929 * @param[out] aStuffToPaste the fragment, excluding context.
3930 * @param[out] aCfcontext the context, excluding the fragment, including a
3931 * marker (`kInsertionCookie`) indicating where the
3934 nsresult
ParseCFHTML(const nsCString
& aCfhtml
, char16_t
** aStuffToPaste
,
3935 char16_t
** aCfcontext
);
3938 * AutoHTMLFragmentBoundariesFixer fixes both edges of topmost child contents
3939 * which are created with SubtreeContentIterator.
3941 class MOZ_STACK_CLASS AutoHTMLFragmentBoundariesFixer final
{
3944 * @param aArrayOfTopMostChildContents
3945 * [in/out] The topmost child contents which will be
3946 * inserted into the DOM tree. Both edges, i.e.,
3947 * first node and last node in this array will be
3948 * checked whether they can be inserted into
3949 * another DOM tree. If not, it'll replaces some
3950 * orphan nodes around nodes with proper parent.
3952 explicit AutoHTMLFragmentBoundariesFixer(
3953 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfTopMostChildContents
);
3957 * EnsureBeginsOrEndsWithValidContent() replaces some nodes starting from
3958 * start or end with proper element node if it's necessary.
3959 * If first or last node of aArrayOfTopMostChildContents is in list and/or
3960 * `<table>` element, looks for topmost list element or `<table>` element
3961 * with `CollectTableAndAnyListElementsOfInclusiveAncestorsAt()` and
3962 * `GetMostDistantAncestorListOrTableElement()`. Then, checks
3963 * whether some nodes are in aArrayOfTopMostChildContents are the topmost
3964 * list/table element or its descendant and if so, removes the nodes from
3965 * aArrayOfTopMostChildContents and inserts the list/table element instead.
3966 * Then, aArrayOfTopMostChildContents won't start/end with list-item nor
3969 enum class StartOrEnd
{ start
, end
};
3970 void EnsureBeginsOrEndsWithValidContent(
3971 StartOrEnd aStartOrEnd
,
3972 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfTopMostChildContents
)
3976 * CollectTableAndAnyListElementsOfInclusiveAncestorsAt() collects list
3977 * elements and table related elements from the inclusive ancestors
3978 * (https://dom.spec.whatwg.org/#concept-tree-inclusive-ancestor) of aNode.
3980 static void CollectTableAndAnyListElementsOfInclusiveAncestorsAt(
3981 nsIContent
& aContent
,
3982 nsTArray
<OwningNonNull
<Element
>>& aOutArrayOfListAndTableElements
);
3985 * GetMostDistantAncestorListOrTableElement() returns a list or a
3986 * `<table>` element which is in
3987 * aInclusiveAncestorsTableOrListElements and they are actually
3988 * valid ancestor of at least one of aArrayOfTopMostChildContents.
3990 static Element
* GetMostDistantAncestorListOrTableElement(
3991 const nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfTopMostChildContents
,
3992 const nsTArray
<OwningNonNull
<Element
>>&
3993 aInclusiveAncestorsTableOrListElements
);
3996 * FindReplaceableTableElement() is a helper method of
3997 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInTableElement is
3998 * a descendant of aTableElement, returns aNodeMaybeInTableElement or its
3999 * nearest ancestor whose tag name is `<td>`, `<th>`, `<tr>`, `<thead>`,
4000 * `<tfoot>`, `<tbody>` or `<caption>`.
4002 * @param aTableElement Must be a `<table>` element.
4003 * @param aContentMaybeInTableElement A node which may be in aTableElement.
4005 Element
* FindReplaceableTableElement(
4006 Element
& aTableElement
, nsIContent
& aContentMaybeInTableElement
) const;
4009 * IsReplaceableListElement() is a helper method of
4010 * EnsureBeginsOrEndsWithValidContent(). If aNodeMaybeInListElement is a
4011 * descendant of aListElement, returns true. Otherwise, false.
4013 * @param aListElement Must be a list element.
4014 * @param aContentMaybeInListElement A node which may be in aListElement.
4016 bool IsReplaceableListElement(Element
& aListElement
,
4017 nsIContent
& aContentMaybeInListElement
) const;
4021 * MakeDefinitionListItemWithTransaction() replaces parent list of current
4022 * selection with <dl> or create new <dl> element and creates a definition
4023 * list item whose name is aTagName.
4025 * @param aTagName Must be nsGkAtoms::dt or nsGkAtoms::dd.
4027 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4028 MakeDefinitionListItemWithTransaction(nsAtom
& aTagName
);
4031 * FormatBlockContainerAsSubAction() inserts a block element whose name
4032 * is aTagName at selection. If selection is not collapsed and aTagName is
4033 * nsGkAtoms::normal or nsGkAtoms::_empty, this removes block containers.
4035 * @param aTagName A block level element name. Must NOT be
4036 * nsGkAtoms::dt nor nsGkAtoms::dd.
4037 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4038 * paragraphState command.
4039 * @param aEditingHost The editing host.
4041 MOZ_CAN_RUN_SCRIPT nsresult
FormatBlockContainerAsSubAction(
4042 const nsStaticAtom
& aTagName
, FormatBlockMode aFormatBlockMode
,
4043 const Element
& aEditingHost
);
4046 * Increase/decrease the font size of selection.
4048 MOZ_CAN_RUN_SCRIPT nsresult
4049 IncrementOrDecrementFontSizeAsSubAction(FontSize aIncrementOrDecrement
);
4052 * Wrap aContent in <big> or <small> element and make children of
4053 * <font size=n> wrap with <big> or <small> too. Note that if there is
4054 * opposite element for aIncrementOrDecrement, their children will be just
4057 * @param aDir Whether increase or decrease the font size of aContent.
4058 * @param aContent The content node whose font size will be changed.
4059 * @return A suggest point to put caret.
4061 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
4062 SetFontSizeWithBigOrSmallElement(nsIContent
& aContent
,
4063 FontSize aIncrementOrDecrement
);
4066 * Adjust font size of font element children recursively with handling
4067 * <big> and <small> elements.
4069 * @param aDir Whether increase or decrease the font size of aContent.
4070 * @param aContent The content node whose font size will be changed.
4071 * All descendants will be handled recursively.
4072 * @return A suggest point to put caret.
4074 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
4075 SetFontSizeOfFontElementChildren(nsIContent
& aContent
,
4076 FontSize aIncrementOrDecrement
);
4079 * Get extended range to select element whose all children are selected by
4082 EditorRawDOMRange
GetExtendedRangeWrappingEntirelySelectedElements(
4083 const EditorRawDOMRange
& aRange
) const;
4086 * Get extended range to select ancestor <a name> elements.
4088 EditorRawDOMRange
GetExtendedRangeWrappingNamedAnchor(
4089 const EditorRawDOMRange
& aRange
) const;
4091 // Declared in HTMLEditorNestedClasses.h and defined in HTMLStyleEditor.cpp
4092 class AutoInlineStyleSetter
;
4095 * RemoveStyleInside() removes elements which represent aStyleToRemove
4096 * and removes CSS style. This handles aElement and all its descendants
4097 * (including leaf text nodes) recursively.
4098 * TODO: Rename this to explain that this maybe remove aElement from the DOM
4101 * @param aSpecifiedStyle Whether the class and style attributes should
4102 * be preserved or discarded.
4103 * @return A suggest point to put caret.
4105 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
4106 RemoveStyleInside(Element
& aElement
, const EditorInlineStyle
& aStyleToRemove
,
4107 SpecifiedStyle aSpecifiedStyle
);
4110 * CollectEditableLeafTextNodes() collects text nodes in aElement.
4112 void CollectEditableLeafTextNodes(
4113 Element
& aElement
, nsTArray
<OwningNonNull
<Text
>>& aLeafTextNodes
) const;
4116 * IsRemovableParentStyleWithNewSpanElement() checks whether aStyle of parent
4117 * block can be removed from aContent with creating `<span>` element. Note
4118 * that this does NOT check whether the specified style comes from parent
4120 * XXX This may destroy the editor, but using `Result<bool, nsresult>`
4121 * is not reasonable because code for accessing the result becomes
4122 * messy. However, anybody must forget to check `Destroyed()` after
4123 * calling this. Which is the way to smart to make every caller
4124 * must check the editor state?
4126 MOZ_CAN_RUN_SCRIPT Result
<bool, nsresult
>
4127 IsRemovableParentStyleWithNewSpanElement(
4128 nsIContent
& aContent
, const EditorInlineStyle
& aStyle
) const;
4131 * HasStyleOrIdOrClassAttribute() returns true when at least one of
4132 * `style`, `id` or `class` attribute value of aElement is not empty.
4134 static bool HasStyleOrIdOrClassAttribute(Element
& aElement
);
4137 * Whether the outer window of the DOM event target has focus or not.
4139 bool OurWindowHasFocus() const;
4141 class HTMLWithContextInserter
;
4144 * This function is used to insert a string of HTML input optionally with some
4145 * context information into the editable field. The HTML input either comes
4146 * from a transferable object created as part of a drop/paste operation, or
4147 * from the InsertHTML method. We may want the HTML input to be sanitized
4148 * (for example, if it's coming from a transferable object), in which case
4149 * aTrustedInput should be set to false, otherwise, the caller should set it
4150 * to true, which means that the HTML will be inserted in the DOM verbatim.
4152 enum class InlineStylesAtInsertionPoint
{
4153 Preserve
, // If you want the paste to be affected by local style, e.g.,
4154 // for the insertHTML command, use "Preserve"
4155 Clear
, // If you want the paste to be keep its own style, e.g., pasting
4156 // from clipboard, use "Clear"
4158 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
InsertHTMLWithContextAsSubAction(
4159 const nsAString
& aInputString
, const nsAString
& aContextStr
,
4160 const nsAString
& aInfoStr
, const nsAString
& aFlavor
,
4161 SafeToInsertData aSafeToInsertData
, const EditorDOMPoint
& aPointToInsert
,
4162 DeleteSelectedContent aDeleteSelectedContent
,
4163 InlineStylesAtInsertionPoint aInlineStylesAtInsertionPoint
,
4164 const Element
& aEditingHost
);
4167 * sets the position of an element; warning it does NOT check if the
4168 * element is already positioned or not and that's on purpose.
4169 * @param aStyledElement [IN] the element
4170 * @param aX [IN] the x position in pixels.
4171 * @param aY [IN] the y position in pixels.
4173 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetTopAndLeftWithTransaction(
4174 nsStyledElement
& aStyledElement
, int32_t aX
, int32_t aY
);
4177 * Reset a selected cell or collapsed selection (the caret) after table
4180 * @param aTable A table in the document.
4181 * @param aRow The row ...
4182 * @param aCol ... and column defining the cell where we will try to
4184 * @param aSelected If true, we select the whole cell instead of setting
4186 * @param aDirection If cell at (aCol, aRow) is not found, search for
4187 * previous cell in the same column (aPreviousColumn) or
4188 * row (ePreviousRow) or don't search for another cell
4189 * (aNoSearch). If no cell is found, caret is place just
4190 * before table; and if that fails, at beginning of
4191 * document. Thus we generally don't worry about the
4192 * return value and can use the
4193 * AutoSelectionSetterAfterTableEdit stack-based object to
4194 * insure we reset the caret in a table-editing method.
4196 MOZ_CAN_RUN_SCRIPT
void SetSelectionAfterTableEdit(Element
* aTable
,
4197 int32_t aRow
, int32_t aCol
,
4201 void RemoveListenerAndDeleteRef(const nsAString
& aEvent
,
4202 nsIDOMEventListener
* aListener
,
4203 bool aUseCapture
, ManualNACPtr aElement
,
4204 PresShell
* aPresShell
);
4205 void DeleteRefToAnonymousNode(ManualNACPtr aContent
, PresShell
* aPresShell
);
4208 * RefreshEditingUI() may refresh editing UIs for current Selection, focus,
4209 * etc. If this shows or hides some UIs, it causes reflow. So, this is
4212 MOZ_CAN_RUN_SCRIPT nsresult
RefreshEditingUI();
4215 * Returns the offset of an element's frame to its absolute containing block.
4217 nsresult
GetElementOrigin(Element
& aElement
, int32_t& aX
, int32_t& aY
);
4218 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
GetPositionAndDimensions(
4219 Element
& aElement
, int32_t& aX
, int32_t& aY
, int32_t& aW
, int32_t& aH
,
4220 int32_t& aBorderLeft
, int32_t& aBorderTop
, int32_t& aMarginLeft
,
4221 int32_t& aMarginTop
);
4223 bool IsInObservedSubtree(nsIContent
* aChild
);
4225 void UpdateRootElement();
4228 * SetAllResizersPosition() moves all resizers to proper position.
4229 * If the resizers are hidden or replaced with another set of resizers
4230 * while this is running, this returns error. So, callers shouldn't
4231 * keep handling the resizers if this returns error.
4233 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
SetAllResizersPosition();
4236 * Shows active resizers around an element's frame
4237 * @param aResizedElement [IN] a DOM Element
4239 MOZ_CAN_RUN_SCRIPT nsresult
ShowResizersInternal(Element
& aResizedElement
);
4242 * Hide resizers if they are visible. If this is called while there is no
4243 * visible resizers, this does not return error, but does nothing.
4245 nsresult
HideResizersInternal();
4248 * RefreshResizersInternal() moves resizers to proper position. This does
4249 * nothing if there is no resizing target.
4251 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
RefreshResizersInternal();
4253 ManualNACPtr
CreateResizer(int16_t aLocation
, nsIContent
& aParentContent
);
4254 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4255 SetAnonymousElementPositionWithoutTransaction(nsStyledElement
& aStyledElement
,
4256 int32_t aX
, int32_t aY
);
4258 ManualNACPtr
CreateShadow(nsIContent
& aParentContent
,
4259 Element
& aOriginalObject
);
4262 * SetShadowPosition() moves the shadow element to proper position.
4264 * @param aShadowElement Must be mResizingShadow or mPositioningShadow.
4265 * @param aElement The element which has the shadow.
4266 * @param aElementX Left of aElement.
4267 * @param aElementY Top of aElement.
4269 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4270 SetShadowPosition(Element
& aShadowElement
, Element
& aElement
,
4271 int32_t aElementLeft
, int32_t aElementTop
);
4273 ManualNACPtr
CreateResizingInfo(nsIContent
& aParentContent
);
4274 MOZ_CAN_RUN_SCRIPT nsresult
SetResizingInfoPosition(int32_t aX
, int32_t aY
,
4275 int32_t aW
, int32_t aH
);
4277 enum class ResizeAt
{
4283 [[nodiscard
]] int32_t GetNewResizingIncrement(int32_t aX
, int32_t aY
,
4284 ResizeAt aResizeAt
) const;
4286 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
StartResizing(Element
& aHandle
);
4287 int32_t GetNewResizingX(int32_t aX
, int32_t aY
);
4288 int32_t GetNewResizingY(int32_t aX
, int32_t aY
);
4289 int32_t GetNewResizingWidth(int32_t aX
, int32_t aY
);
4290 int32_t GetNewResizingHeight(int32_t aX
, int32_t aY
);
4291 void HideShadowAndInfo();
4292 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4293 SetFinalSizeWithTransaction(int32_t aX
, int32_t aY
);
4294 void SetResizeIncrements(int32_t aX
, int32_t aY
, int32_t aW
, int32_t aH
,
4295 bool aPreserveRatio
);
4298 * HideAnonymousEditingUIs() forcibly hides all editing UIs (resizers,
4299 * inline-table-editing UI, absolute positioning UI).
4301 void HideAnonymousEditingUIs();
4304 * HideAnonymousEditingUIsIfUnnecessary() hides all editing UIs if some of
4305 * visible UIs are now unnecessary.
4307 void HideAnonymousEditingUIsIfUnnecessary();
4310 * sets the z-index of an element.
4311 * @param aElement [IN] the element
4312 * @param aZorder [IN] the z-index
4314 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4315 SetZIndexWithTransaction(nsStyledElement
& aElement
, int32_t aZIndex
);
4318 * shows a grabber attached to an arbitrary element. The grabber is an image
4319 * positioned on the left hand side of the top border of the element. Draggin
4320 * and dropping it allows to change the element's absolute position in the
4321 * document. See chrome://editor/content/images/grabber.gif
4322 * @param aElement [IN] the element
4324 MOZ_CAN_RUN_SCRIPT nsresult
ShowGrabberInternal(Element
& aElement
);
4327 * Setting grabber to proper position for current mAbsolutelyPositionedObject.
4328 * For example, while an element has grabber, the element may be resized
4329 * or repositioned by script or something. Then, you need to reset grabber
4330 * position with this.
4332 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
RefreshGrabberInternal();
4335 * hide the grabber if it shown.
4337 void HideGrabberInternal();
4340 * CreateGrabberInternal() creates a grabber for moving aParentContent.
4341 * This sets mGrabber to the new grabber. If this returns true, it's
4342 * always non-nullptr. Otherwise, i.e., the grabber is hidden during
4343 * creation, this returns false.
4345 bool CreateGrabberInternal(nsIContent
& aParentContent
);
4347 MOZ_CAN_RUN_SCRIPT nsresult
StartMoving();
4348 MOZ_CAN_RUN_SCRIPT nsresult
SetFinalPosition(int32_t aX
, int32_t aY
);
4349 void SnapToGrid(int32_t& newX
, int32_t& newY
) const;
4350 nsresult
GrabberClicked();
4351 MOZ_CAN_RUN_SCRIPT nsresult
EndMoving();
4352 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4353 GetTemporaryStyleForFocusedPositionedElement(Element
& aElement
,
4354 nsAString
& aReturn
);
4357 * Shows inline table editing UI around a <table> element which contains
4358 * aCellElement. This returns error if creating UI is hidden during this,
4359 * or detects another set of UI during this. In such case, callers
4360 * shouldn't keep handling anything for the UI.
4362 * @param aCellElement Must be an <td> or <th> element.
4364 MOZ_CAN_RUN_SCRIPT nsresult
4365 ShowInlineTableEditingUIInternal(Element
& aCellElement
);
4368 * Hide all inline table editing UI.
4370 void HideInlineTableEditingUIInternal();
4373 * RefreshInlineTableEditingUIInternal() moves inline table editing UI to
4374 * proper position. This returns error if the UI is hidden or replaced
4377 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT nsresult
4378 RefreshInlineTableEditingUIInternal();
4380 enum class ContentNodeIs
{ Inserted
, Appended
};
4381 MOZ_CAN_RUN_SCRIPT
void DoContentInserted(nsIContent
* aChild
,
4382 ContentNodeIs aContentNodeIs
);
4385 * Returns an anonymous Element of type aTag,
4386 * child of aParentContent. If aIsCreatedHidden is true, the class
4387 * "hidden" is added to the created element. If aClass is not the empty
4388 * string, it becomes the value of the class attribute
4390 * @param aTag [IN] desired type of the element to create
4391 * @param aParentContent [IN] the parent node of the created anonymous
4393 * @param aClass [IN] contents of the _moz_anonclass attribute
4394 * @param aIsCreatedHidden [IN] a boolean specifying if the class "hidden"
4395 * is to be added to the created anonymous
4398 ManualNACPtr
CreateAnonymousElement(nsAtom
* aTag
, nsIContent
& aParentContent
,
4399 const nsAString
& aClass
,
4400 bool aIsCreatedHidden
);
4403 * Reads a blob into memory and notifies the BlobReader object when the read
4404 * operation is finished.
4406 * @param aBlob The input blob
4407 * @param aGlobal The global object under which the read should happen.
4408 * @param aBlobReader The blob reader object to be notified when finished.
4410 static nsresult
SlurpBlob(dom::Blob
* aBlob
, nsIGlobalObject
* aGlobal
,
4411 BlobReader
* aBlobReader
);
4414 * For saving allocation cost in the constructor of
4415 * EditorBase::TopLevelEditSubActionData, we should reuse same RangeItem
4416 * instance with all top level edit sub actions.
4417 * The instance is always cleared when TopLevelEditSubActionData is
4418 * destructed and the class is stack only class so that we don't need
4419 * to (and also should not) add the RangeItem into the cycle collection.
4421 [[nodiscard
]] inline already_AddRefed
<RangeItem
>
4422 GetSelectedRangeItemForTopLevelEditSubAction() const;
4425 * For saving allocation cost in the constructor of
4426 * EditorBase::TopLevelEditSubActionData, we should reuse same nsRange
4427 * instance with all top level edit sub actions.
4428 * The instance is always cleared when TopLevelEditSubActionData is
4429 * destructed, but AbstractRange::mOwner keeps grabbing the owner document
4430 * so that we need to make it in the cycle collection.
4432 [[nodiscard
]] inline already_AddRefed
<nsRange
>
4433 GetChangedRangeForTopLevelEditSubAction() const;
4435 MOZ_CAN_RUN_SCRIPT
void DidDoTransaction(
4436 TransactionManager
& aTransactionManager
, nsITransaction
& aTransaction
,
4437 nsresult aDoTransactionResult
) {
4438 if (mComposerCommandsUpdater
) {
4439 RefPtr
<ComposerCommandsUpdater
> updater(mComposerCommandsUpdater
);
4440 updater
->DidDoTransaction(aTransactionManager
);
4444 MOZ_CAN_RUN_SCRIPT
void DidUndoTransaction(
4445 TransactionManager
& aTransactionManager
, nsITransaction
& aTransaction
,
4446 nsresult aUndoTransactionResult
) {
4447 if (mComposerCommandsUpdater
) {
4448 RefPtr
<ComposerCommandsUpdater
> updater(mComposerCommandsUpdater
);
4449 updater
->DidUndoTransaction(aTransactionManager
);
4453 MOZ_CAN_RUN_SCRIPT
void DidRedoTransaction(
4454 TransactionManager
& aTransactionManager
, nsITransaction
& aTransaction
,
4455 nsresult aRedoTransactionResult
) {
4456 if (mComposerCommandsUpdater
) {
4457 RefPtr
<ComposerCommandsUpdater
> updater(mComposerCommandsUpdater
);
4458 updater
->DidRedoTransaction(aTransactionManager
);
4464 * IndentListChildWithTransaction() is a helper method of
4465 * Handle(CSS|HTML)IndentAtSelectionInternal().
4467 * @param aSubListElement [in/out] Specify a sub-list element of the
4468 * container of aPointInListElement or nullptr.
4469 * When there is no proper sub-list element to
4470 * move aContentMovingToSubList, this method
4471 * inserts a new sub-list element and update this
4473 * @param aPointInListElement A point in a list element whose child should
4474 * be indented. If this method creates new list
4475 * element into the list element, this inserts
4476 * the new list element to this point.
4477 * @param aContentMovingToSubList
4478 * A content node which is a child of a list
4479 * element and should be moved into a sub-list
4481 * @param aEditingHost The editing host.
4482 * @return A candidate caret position.
4484 [[nodiscard
]] MOZ_CAN_RUN_SCRIPT Result
<EditorDOMPoint
, nsresult
>
4485 IndentListChildWithTransaction(RefPtr
<Element
>* aSubListElement
,
4486 const EditorDOMPoint
& aPointInListElement
,
4487 nsIContent
& aContentMovingToSubList
,
4488 const Element
& aEditingHost
);
4491 * Stack based helper class for calling EditorBase::EndTransactionInternal().
4492 * NOTE: This does not suppress multiple input events. In most cases,
4493 * only one "input" event should be fired for an edit action rather
4494 * than per edit sub-action. In such case, you should use
4495 * EditorBase::AutoPlaceholderBatch instead.
4497 class MOZ_RAII AutoTransactionBatch final
{
4500 * @param aRequesterFuncName function name which wants to end the batch.
4501 * This won't be stored nor exposed to selection listeners etc, used only
4502 * for logging. This MUST be alive when the destructor runs.
4504 MOZ_CAN_RUN_SCRIPT
explicit AutoTransactionBatch(
4505 HTMLEditor
& aHTMLEditor
, const char* aRequesterFuncName
)
4506 : mHTMLEditor(aHTMLEditor
), mRequesterFuncName(aRequesterFuncName
) {
4507 MOZ_KnownLive(mHTMLEditor
).BeginTransactionInternal(mRequesterFuncName
);
4510 MOZ_CAN_RUN_SCRIPT
~AutoTransactionBatch() {
4511 MOZ_KnownLive(mHTMLEditor
).EndTransactionInternal(mRequesterFuncName
);
4515 // The lifetime must be guaranteed by the creator of this instance.
4516 MOZ_KNOWN_LIVE HTMLEditor
& mHTMLEditor
;
4517 const char* const mRequesterFuncName
;
4520 RefPtr
<PendingStyles
> mPendingStylesToApplyToNewContent
;
4521 RefPtr
<ComposerCommandsUpdater
> mComposerCommandsUpdater
;
4523 // Used by TopLevelEditSubActionData::mSelectedRange.
4524 mutable RefPtr
<RangeItem
> mSelectedRangeForTopLevelEditSubAction
;
4525 // Used by TopLevelEditSubActionData::mChangedRange.
4526 mutable RefPtr
<nsRange
> mChangedRangeForTopLevelEditSubAction
;
4528 RefPtr
<Runnable
> mPendingRootElementUpdatedRunner
;
4529 RefPtr
<DocumentModifiedEvent
> mPendingDocumentModifiedRunner
;
4531 // mPaddingBRElementForEmptyEditor should be used for placing caret
4532 // at proper position when editor is empty.
4533 RefPtr
<dom::HTMLBRElement
> mPaddingBRElementForEmptyEditor
;
4535 // This is set only when HandleInsertText appended a collapsible white-space.
4536 RefPtr
<dom::Text
> mLastCollapsibleWhiteSpaceAppendedTextNode
;
4538 bool mCRInParagraphCreatesParagraph
;
4541 bool mIsObjectResizingEnabled
;
4543 bool mPreserveRatio
;
4544 bool mResizedObjectIsAnImage
;
4546 // absolute positioning
4547 bool mIsAbsolutelyPositioningEnabled
;
4548 bool mResizedObjectIsAbsolutelyPositioned
;
4549 bool mGrabberClicked
;
4552 bool mSnapToGridEnabled
;
4554 // inline table editing
4555 bool mIsInlineTableEditingEnabled
;
4557 bool mIsCSSPrefChecked
;
4560 ManualNACPtr mTopLeftHandle
;
4561 ManualNACPtr mTopHandle
;
4562 ManualNACPtr mTopRightHandle
;
4563 ManualNACPtr mLeftHandle
;
4564 ManualNACPtr mRightHandle
;
4565 ManualNACPtr mBottomLeftHandle
;
4566 ManualNACPtr mBottomHandle
;
4567 ManualNACPtr mBottomRightHandle
;
4569 RefPtr
<Element
> mActivatedHandle
;
4571 ManualNACPtr mResizingShadow
;
4572 ManualNACPtr mResizingInfo
;
4574 RefPtr
<Element
> mResizedObject
;
4579 int32_t mResizedObjectX
;
4580 int32_t mResizedObjectY
;
4581 int32_t mResizedObjectWidth
;
4582 int32_t mResizedObjectHeight
;
4584 int32_t mResizedObjectMarginLeft
;
4585 int32_t mResizedObjectMarginTop
;
4586 int32_t mResizedObjectBorderLeft
;
4587 int32_t mResizedObjectBorderTop
;
4589 int32_t mXIncrementFactor
;
4590 int32_t mYIncrementFactor
;
4591 int32_t mWidthIncrementFactor
;
4592 int32_t mHeightIncrementFactor
;
4594 int8_t mInfoXIncrement
;
4595 int8_t mInfoYIncrement
;
4597 // absolute positioning
4598 int32_t mPositionedObjectX
;
4599 int32_t mPositionedObjectY
;
4600 int32_t mPositionedObjectWidth
;
4601 int32_t mPositionedObjectHeight
;
4603 int32_t mPositionedObjectMarginLeft
;
4604 int32_t mPositionedObjectMarginTop
;
4605 int32_t mPositionedObjectBorderLeft
;
4606 int32_t mPositionedObjectBorderTop
;
4608 RefPtr
<Element
> mAbsolutelyPositionedObject
;
4609 ManualNACPtr mGrabber
;
4610 ManualNACPtr mPositioningShadow
;
4614 // inline table editing
4615 RefPtr
<Element
> mInlineEditedCell
;
4617 ManualNACPtr mAddColumnBeforeButton
;
4618 ManualNACPtr mRemoveColumnButton
;
4619 ManualNACPtr mAddColumnAfterButton
;
4621 ManualNACPtr mAddRowBeforeButton
;
4622 ManualNACPtr mRemoveRowButton
;
4623 ManualNACPtr mAddRowAfterButton
;
4625 void AddPointerClickListener(Element
* aElement
);
4626 void RemovePointerClickListener(Element
* aElement
);
4628 bool mDisabledLinkHandling
= false;
4629 bool mOldLinkHandlingEnabled
= false;
4631 bool mHasBeforeInputBeenCanceled
= false;
4633 bool mHasFocus
= false;
4634 bool mIsInDesignMode
= false;
4636 ParagraphSeparator mDefaultParagraphSeparator
;
4638 friend class AlignStateAtSelection
; // CollectEditableTargetNodes,
4639 // CollectNonEditableNodes
4640 friend class AutoClonedRangeArray
; // RangeUpdaterRef,
4641 // SplitNodeWithTransaction,
4642 // SplitInlineAncestorsAtRangeBoundaries
4643 friend class AutoClonedSelectionRangeArray
; // RangeUpdaterRef,
4644 friend class AutoSelectionRestore
;
4645 friend class AutoSelectionSetterAfterTableEdit
; // SetSelectionAfterEdit
4646 friend class CSSEditUtils
; // DoTransactionInternal, HasAttributes,
4647 // RemoveContainerWithTransaction
4648 friend class EditorBase
; // ComputeTargetRanges,
4649 // GetChangedRangeForTopLevelEditSubAction,
4650 // GetSelectedRangeItemForTopLevelEditSubAction,
4651 // MaybeCreatePaddingBRElementForEmptyEditor,
4652 // PrepareToInsertBRElement,
4653 // ReflectPaddingBRElementForEmptyEditor,
4654 // RefreshEditingUI,
4655 // mComposerUpdater, mHasBeforeInputBeenCanceled
4656 friend class JoinNodesTransaction
; // DidJoinNodesTransaction, DoJoinNodes,
4657 // DoSplitNode, // RangeUpdaterRef
4658 friend class ListElementSelectionState
; // CollectEditTargetNodes,
4659 // CollectNonEditableNodes
4660 friend class ListItemElementSelectionState
; // CollectEditTargetNodes,
4661 // CollectNonEditableNodes
4662 friend class MoveNodeTransaction
; // AllowsTransactionsToChangeSelection,
4663 // CollapseSelectionTo, MarkElementDirty,
4665 friend class ParagraphStateAtSelection
; // CollectChildren,
4666 // CollectEditTargetNodes,
4667 // CollectListChildren,
4668 // CollectNonEditableNodes,
4669 // CollectTableChildren
4670 friend class SlurpBlobEventListener
; // BlobReader
4671 friend class SplitNodeTransaction
; // DoJoinNodes, DoSplitNode
4672 friend class TransactionManager
; // DidDoTransaction, DidRedoTransaction,
4673 // DidUndoTransaction
4675 WhiteSpaceVisibilityKeeper
; // AutoMoveOneLineHandler
4677 // ChangeListElementType,
4678 // DeleteNodeWithTransaction,
4679 // DeleteTextAndTextNodesWithTransaction,
4681 // JoinNearestEditableNodesWithTransaction,
4683 // MoveChildrenWithTransaction,
4684 // SplitAncestorStyledInlineElementsAt,
4685 // TreatEmptyTextNodes
4689 * ListElementSelectionState class gets which list element is selected right
4692 class MOZ_STACK_CLASS ListElementSelectionState final
{
4694 ListElementSelectionState() = delete;
4695 ListElementSelectionState(HTMLEditor
& aHTMLEditor
, ErrorResult
& aRv
);
4697 bool IsOLElementSelected() const { return mIsOLElementSelected
; }
4698 bool IsULElementSelected() const { return mIsULElementSelected
; }
4699 bool IsDLElementSelected() const { return mIsDLElementSelected
; }
4700 bool IsNotOneTypeListElementSelected() const {
4701 return (mIsOLElementSelected
+ mIsULElementSelected
+ mIsDLElementSelected
+
4702 mIsOtherContentSelected
) > 1;
4706 bool mIsOLElementSelected
= false;
4707 bool mIsULElementSelected
= false;
4708 bool mIsDLElementSelected
= false;
4709 bool mIsOtherContentSelected
= false;
4713 * ListItemElementSelectionState class gets which list item element is selected
4716 class MOZ_STACK_CLASS ListItemElementSelectionState final
{
4718 ListItemElementSelectionState() = delete;
4719 ListItemElementSelectionState(HTMLEditor
& aHTMLEditor
, ErrorResult
& aRv
);
4721 bool IsLIElementSelected() const { return mIsLIElementSelected
; }
4722 bool IsDTElementSelected() const { return mIsDTElementSelected
; }
4723 bool IsDDElementSelected() const { return mIsDDElementSelected
; }
4724 bool IsNotOneTypeDefinitionListItemElementSelected() const {
4725 return (mIsDTElementSelected
+ mIsDDElementSelected
+
4726 mIsOtherElementSelected
) > 1;
4730 bool mIsLIElementSelected
= false;
4731 bool mIsDTElementSelected
= false;
4732 bool mIsDDElementSelected
= false;
4733 bool mIsOtherElementSelected
= false;
4737 * AlignStateAtSelection class gets alignment at selection.
4738 * XXX This currently returns only first alignment.
4740 class MOZ_STACK_CLASS AlignStateAtSelection final
{
4742 AlignStateAtSelection() = delete;
4743 MOZ_CAN_RUN_SCRIPT
AlignStateAtSelection(HTMLEditor
& aHTMLEditor
,
4746 nsIHTMLEditor::EAlignment
AlignmentAtSelectionStart() const {
4749 bool IsSelectionRangesFound() const { return mFoundSelectionRanges
; }
4752 nsIHTMLEditor::EAlignment mFirstAlign
= nsIHTMLEditor::eLeft
;
4753 bool mFoundSelectionRanges
= false;
4757 * ParagraphStateAtSelection class gets format block types around selection.
4759 class MOZ_STACK_CLASS ParagraphStateAtSelection final
{
4761 using FormatBlockMode
= HTMLEditor::FormatBlockMode
;
4763 ParagraphStateAtSelection() = delete;
4765 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4766 * paragraphState command.
4768 ParagraphStateAtSelection(HTMLEditor
& aHTMLEditor
,
4769 FormatBlockMode aFormatBlockMode
, ErrorResult
& aRv
);
4772 * GetFirstParagraphStateAtSelection() returns:
4773 * - nullptr if there is no format blocks nor inline nodes.
4774 * - nsGkAtoms::_empty if first node is not in any format block.
4775 * - a tag name of format block at first node.
4776 * XXX See the private method explanations. If selection ranges contains
4777 * non-format block first, it'll be check after its siblings. Therefore,
4778 * this may return non-first paragraph state.
4780 nsAtom
* GetFirstParagraphStateAtSelection() const {
4781 return mIsMixed
&& mIsInDLElement
? nsGkAtoms::dl
4782 : mFirstParagraphState
.get();
4786 * If selected nodes are not in same format node nor only in no-format blocks,
4787 * this returns true.
4789 bool IsMixed() const { return mIsMixed
&& !mIsInDLElement
; }
4792 using EditorType
= EditorBase::EditorType
;
4794 [[nodiscard
]] static bool IsFormatElement(FormatBlockMode aFormatBlockMode
,
4795 const nsIContent
& aContent
);
4798 * AppendDescendantFormatNodesAndFirstInlineNode() appends descendant
4799 * format blocks and first inline child node in aNonFormatBlockElement to
4800 * the last of the array (not inserting where aNonFormatBlockElement is,
4801 * so that the node order becomes randomly).
4803 * @param aArrayOfContents [in/out] Found descendant format blocks
4804 * and first inline node in each non-format
4805 * block will be appended to this.
4806 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4807 * paragraphState command.
4808 * @param aNonFormatBlockElement Must be a non-format block element.
4810 static void AppendDescendantFormatNodesAndFirstInlineNode(
4811 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
,
4812 FormatBlockMode aFormatBlockMode
, dom::Element
& aNonFormatBlockElement
);
4815 * CollectEditableFormatNodesInSelection() collects only editable nodes
4816 * around selection ranges (with
4817 * AutoClonedRangeArray::ExtendRangesToWrapLines() and
4818 * HTMLEditor::CollectEditTargetNodes(), see its document for the detail).
4819 * If it includes list, list item or table related elements, they will be
4820 * replaced their children.
4822 * @param aFormatBlockMode Whether HTML formatBlock command or XUL
4823 * paragraphState command.
4825 static nsresult
CollectEditableFormatNodesInSelection(
4826 HTMLEditor
& aHTMLEditor
, FormatBlockMode aFormatBlockMode
,
4827 const dom::Element
& aEditingHost
,
4828 nsTArray
<OwningNonNull
<nsIContent
>>& aArrayOfContents
);
4830 RefPtr
<nsAtom
> mFirstParagraphState
;
4831 bool mIsInDLElement
= false;
4832 bool mIsMixed
= false;
4835 } // namespace mozilla
4837 mozilla::HTMLEditor
* nsIEditor::AsHTMLEditor() {
4838 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4839 return static_cast<mozilla::HTMLEditor
*>(this);
4842 const mozilla::HTMLEditor
* nsIEditor::AsHTMLEditor() const {
4843 MOZ_DIAGNOSTIC_ASSERT(IsHTMLEditor());
4844 return static_cast<const mozilla::HTMLEditor
*>(this);
4847 mozilla::HTMLEditor
* nsIEditor::GetAsHTMLEditor() {
4848 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4851 const mozilla::HTMLEditor
* nsIEditor::GetAsHTMLEditor() const {
4852 return AsEditorBase()->IsHTMLEditor() ? AsHTMLEditor() : nullptr;
4855 #endif // #ifndef mozilla_HTMLEditor_h