/src/mozilla-central/editor/libeditor/HTMLEditRules.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #ifndef HTMLEditRules_h |
7 | | #define HTMLEditRules_h |
8 | | |
9 | | #include "TypeInState.h" |
10 | | #include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint |
11 | | #include "mozilla/SelectionState.h" |
12 | | #include "mozilla/TextEditRules.h" |
13 | | #include "nsCOMPtr.h" |
14 | | #include "nsIEditor.h" |
15 | | #include "nsIHTMLEditor.h" |
16 | | #include "nsISupportsImpl.h" |
17 | | #include "nsTArray.h" |
18 | | #include "nscore.h" |
19 | | |
20 | | class nsAtom; |
21 | | class nsIEditor; |
22 | | class nsINode; |
23 | | class nsRange; |
24 | | |
25 | | namespace mozilla { |
26 | | |
27 | | class EditActionResult; |
28 | | class HTMLEditor; |
29 | | class SplitNodeResult; |
30 | | class TextEditor; |
31 | | enum class EditSubAction : int32_t; |
32 | | |
33 | | namespace dom { |
34 | | class Element; |
35 | | class Selection; |
36 | | } // namespace dom |
37 | | |
38 | | struct StyleCache final : public PropItem |
39 | | { |
40 | | bool mPresent; |
41 | | |
42 | | StyleCache() |
43 | | : PropItem() |
44 | | , mPresent(false) |
45 | 0 | { |
46 | 0 | MOZ_COUNT_CTOR(StyleCache); |
47 | 0 | } |
48 | | |
49 | | StyleCache(nsAtom* aTag, |
50 | | nsAtom* aAttr, |
51 | | const nsAString& aValue) |
52 | | : PropItem(aTag, aAttr, aValue) |
53 | | , mPresent(false) |
54 | 0 | { |
55 | 0 | MOZ_COUNT_CTOR(StyleCache); |
56 | 0 | } |
57 | | |
58 | | StyleCache(nsAtom* aTag, |
59 | | nsAtom* aAttr) |
60 | | : PropItem(aTag, aAttr, EmptyString()) |
61 | | , mPresent(false) |
62 | 0 | { |
63 | 0 | MOZ_COUNT_CTOR(StyleCache); |
64 | 0 | } |
65 | | |
66 | | ~StyleCache() |
67 | 0 | { |
68 | 0 | MOZ_COUNT_DTOR(StyleCache); |
69 | 0 | } |
70 | | }; |
71 | | |
72 | | /** |
73 | | * Same as TextEditRules, any methods which may modify the DOM tree or |
74 | | * Selection should be marked as MOZ_MUST_USE and return nsresult directly |
75 | | * or with simple class like EditActionResult. And every caller of them |
76 | | * has to check whether the result is NS_ERROR_EDITOR_DESTROYED and if it is, |
77 | | * its callers should stop handling edit action since after mutation event |
78 | | * listener or selectionchange event listener disables the editor, we should |
79 | | * not modify the DOM tree nor Selection anymore. And also when methods of |
80 | | * this class call methods of other classes like HTMLEditor and WSRunObject, |
81 | | * they should check whether CanHandleEditAtion() returns false immediately |
82 | | * after the calls. If it returns false, they should return |
83 | | * NS_ERROR_EDITOR_DESTROYED. |
84 | | */ |
85 | | |
86 | 0 | #define SIZE_STYLE_TABLE 19 |
87 | | |
88 | | class HTMLEditRules : public TextEditRules |
89 | | { |
90 | | public: |
91 | | NS_DECL_ISUPPORTS_INHERITED |
92 | | NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLEditRules, TextEditRules) |
93 | | |
94 | | HTMLEditRules(); |
95 | | |
96 | | // TextEditRules methods |
97 | | virtual nsresult Init(TextEditor* aTextEditor) override; |
98 | | virtual nsresult DetachEditor() override; |
99 | | virtual nsresult BeforeEdit(EditSubAction aEditSubAction, |
100 | | nsIEditor::EDirection aDirection) override; |
101 | | virtual nsresult AfterEdit(EditSubAction aEditSubAction, |
102 | | nsIEditor::EDirection aDirection) override; |
103 | | virtual nsresult WillDoAction(Selection* aSelection, |
104 | | EditSubActionInfo& aInfo, |
105 | | bool* aCancel, |
106 | | bool* aHandled) override; |
107 | | virtual nsresult DidDoAction(Selection* aSelection, |
108 | | EditSubActionInfo& aInfo, |
109 | | nsresult aResult) override; |
110 | | virtual bool DocumentIsEmpty() override; |
111 | | virtual nsresult DocumentModified() override; |
112 | | |
113 | | nsresult GetListState(bool* aMixed, bool* aOL, bool* aUL, bool* aDL); |
114 | | nsresult GetListItemState(bool* aMixed, bool* aLI, bool* aDT, bool* aDD); |
115 | | nsresult GetAlignment(bool* aMixed, nsIHTMLEditor::EAlignment* aAlign); |
116 | | nsresult GetParagraphState(bool* aMixed, nsAString& outFormat); |
117 | | |
118 | | /** |
119 | | * MakeSureElemStartsAndEndsOnCR() inserts <br> element at start (and/or end) |
120 | | * of aNode if neither: |
121 | | * - first (last) editable child of aNode is a block or a <br>, |
122 | | * - previous (next) sibling of aNode is block or a <br> |
123 | | * - nor no previous (next) sibling of aNode. |
124 | | * |
125 | | * @param aNode The node which may be inserted <br> elements. |
126 | | */ |
127 | | MOZ_MUST_USE nsresult MakeSureElemStartsAndEndsOnCR(nsINode& aNode); |
128 | | |
129 | | void DidCreateNode(Selection& aSelection, Element& aNewElement); |
130 | | void DidInsertNode(Selection& aSelection, nsIContent& aNode); |
131 | | void WillDeleteNode(Selection& aSelection, nsINode& aChild); |
132 | | void DidSplitNode(Selection& aSelection, |
133 | | nsINode& aExistingRightNode, |
134 | | nsINode& aNewLeftNode); |
135 | | void WillJoinNodes(nsINode& aLeftNode, nsINode& aRightNode); |
136 | | void DidJoinNodes(Selection& aSelection, |
137 | | nsINode& aLeftNode, nsINode& aRightNode); |
138 | | void DidInsertText(Selection& aSelection, |
139 | | nsINode& aTextNode, int32_t aOffset, |
140 | | const nsAString& aString); |
141 | | void DidDeleteText(Selection& aSelection, |
142 | | nsINode& aTextNode, int32_t aOffset, int32_t aLength); |
143 | | void WillDeleteSelection(Selection& aSelection); |
144 | | |
145 | 0 | void StartToListenToEditSubActions() { mListenerEnabled = true; } |
146 | 0 | void EndListeningToEditSubActions() { mListenerEnabled = false; } |
147 | | |
148 | | protected: |
149 | | virtual ~HTMLEditRules(); |
150 | | |
151 | | HTMLEditor& HTMLEditorRef() const |
152 | 0 | { |
153 | 0 | MOZ_ASSERT(mData); |
154 | 0 | return mData->HTMLEditorRef(); |
155 | 0 | } |
156 | | |
157 | | static bool IsBlockNode(const nsINode& aNode) |
158 | 0 | { |
159 | 0 | return HTMLEditor::NodeIsBlockStatic(&aNode); |
160 | 0 | } |
161 | | static bool IsInlineNode(const nsINode& aNode) |
162 | 0 | { |
163 | 0 | return !IsBlockNode(aNode); |
164 | 0 | } |
165 | | |
166 | | enum RulesEndpoint |
167 | | { |
168 | | kStart, |
169 | | kEnd |
170 | | }; |
171 | | |
172 | | void InitFields(); |
173 | | |
174 | | /** |
175 | | * Called before inserting something into the editor. |
176 | | * This method may removes mBougsNode if there is. Therefore, this method |
177 | | * might cause destroying the editor. |
178 | | * |
179 | | * @param aCancel Returns true if the operation is canceled. |
180 | | * This can be nullptr. |
181 | | */ |
182 | | MOZ_MUST_USE nsresult WillInsert(bool* aCancel = nullptr); |
183 | | |
184 | | /** |
185 | | * Called before inserting text. |
186 | | * This method may actually inserts text into the editor. Therefore, this |
187 | | * might cause destroying the editor. |
188 | | * |
189 | | * @param aEditSubAction Must be EditSubAction::eInsertTextComingFromIME |
190 | | * or EditSubAction::eInsertText. |
191 | | * @param aCancel Returns true if the operation is canceled. |
192 | | * @param aHandled Returns true if the edit action is handled. |
193 | | * @param inString String to be inserted. |
194 | | * @param outString String actually inserted. |
195 | | * @param aMaxLength The maximum string length which the editor |
196 | | * allows to set. |
197 | | */ |
198 | | MOZ_MUST_USE nsresult |
199 | | WillInsertText(EditSubAction aEditSubAction, bool* aCancel, bool* aHandled, |
200 | | const nsAString* inString, nsAString* outString, |
201 | | int32_t aMaxLength); |
202 | | |
203 | | /** |
204 | | * WillLoadHTML() is called before loading enter document from source. |
205 | | * This removes bogus node if there is. |
206 | | */ |
207 | | MOZ_MUST_USE nsresult WillLoadHTML(); |
208 | | |
209 | | /** |
210 | | * WillInsertBreak() is called when insertParagraph command is executed |
211 | | * or something equivalent. This method actually tries to insert new |
212 | | * paragraph or <br> element, etc. |
213 | | * |
214 | | * @param aCancel Returns true if target node is not editable. |
215 | | * @param aHandled Returns true if actually insert new break. |
216 | | */ |
217 | | nsresult WillInsertBreak(bool* aCancel, bool* aHandled); |
218 | | |
219 | | /** |
220 | | * If aNode is a text node that contains only collapsed whitespace, delete |
221 | | * it. It doesn't serve any useful purpose, and we don't want it to confuse |
222 | | * code that doesn't correctly skip over it. |
223 | | * |
224 | | * If deleting the node fails (like if it's not editable), the caller should |
225 | | * proceed as usual, so don't return any errors. |
226 | | */ |
227 | | MOZ_MUST_USE nsresult DeleteNodeIfCollapsedText(nsINode& aNode); |
228 | | |
229 | | /** |
230 | | * InsertBRElement() inserts a <br> element into aInsertToBreak. |
231 | | * |
232 | | * @param aInsertToBreak The point where new <br> element will be |
233 | | * inserted before. |
234 | | */ |
235 | | MOZ_MUST_USE nsresult InsertBRElement(const EditorDOMPoint& aInsertToBreak); |
236 | | |
237 | | /** |
238 | | * SplitMailCites() splits mail-cite elements at start of Selection if |
239 | | * Selection starts from inside a mail-cite element. Of course, if it's |
240 | | * necessary, this inserts <br> node to new left nodes or existing right |
241 | | * nodes. |
242 | | * |
243 | | * @param aHandled Returns true if succeeded to split mail-cite |
244 | | * elements. |
245 | | */ |
246 | | MOZ_MUST_USE nsresult SplitMailCites(bool* aHandled); |
247 | | |
248 | | /** |
249 | | * Called before deleting selected contents. This method actually removes |
250 | | * selected contents. |
251 | | * |
252 | | * @param aAction Direction of the deletion. |
253 | | * @param aStripWrappers Must be eStrip or eNoStrip. |
254 | | * @param aCancel Returns true if the operation is canceled. |
255 | | * @param aHandled Returns true if the edit action is handled. |
256 | | */ |
257 | | MOZ_MUST_USE nsresult |
258 | | WillDeleteSelection(nsIEditor::EDirection aAction, |
259 | | nsIEditor::EStripWrappers aStripWrappers, |
260 | | bool* aCancel, bool* aHandled); |
261 | | |
262 | | /** |
263 | | * Called after deleting selected content. |
264 | | * This method removes unnecessary empty nodes and/or inserts <br> if |
265 | | * necessary. |
266 | | */ |
267 | | MOZ_MUST_USE nsresult DidDeleteSelection(); |
268 | | |
269 | | /** |
270 | | * InsertBRIfNeeded() determines if a br is needed for current selection to |
271 | | * not be spastic. If so, it inserts one. Callers responsibility to only |
272 | | * call with collapsed selection. |
273 | | */ |
274 | | MOZ_MUST_USE nsresult InsertBRIfNeeded(); |
275 | | |
276 | | /** |
277 | | * CanContainParagraph() returns true if aElement can have a <p> element as |
278 | | * its child or its descendant. |
279 | | */ |
280 | | bool CanContainParagraph(Element& aElement) const; |
281 | | |
282 | | /** |
283 | | * Insert normal <br> element into aNode when aNode is a block and it has |
284 | | * no children. |
285 | | */ |
286 | | MOZ_MUST_USE nsresult InsertBRIfNeeded(nsINode& aNode) |
287 | 0 | { |
288 | 0 | return InsertBRIfNeededInternal(aNode, false); |
289 | 0 | } |
290 | | |
291 | | /** |
292 | | * Insert moz-<br> element (<br type="_moz">) into aNode when aNode is a |
293 | | * block and it has no children. |
294 | | */ |
295 | | MOZ_MUST_USE nsresult InsertMozBRIfNeeded(nsINode& aNode) |
296 | 0 | { |
297 | 0 | return InsertBRIfNeededInternal(aNode, true); |
298 | 0 | } |
299 | | |
300 | | /** |
301 | | * Insert a normal <br> element or a moz-<br> element to aNode when |
302 | | * aNode is a block and it has no children. Use InsertBRIfNeeded() or |
303 | | * InsertMozBRIfNeeded() instead. |
304 | | * |
305 | | * @param aNode Reference to a block parent. |
306 | | * @param aInsertMozBR true if this should insert a moz-<br> element. |
307 | | * Otherwise, i.e., this should insert a normal <br> |
308 | | * element, false. |
309 | | */ |
310 | | MOZ_MUST_USE nsresult |
311 | | InsertBRIfNeededInternal(nsINode& aNode, bool aInsertMozBR); |
312 | | |
313 | | /** |
314 | | * GetGoodSelPointForNode() finds where at a node you would want to set the |
315 | | * selection if you were trying to have a caret next to it. Always returns a |
316 | | * valid value (unless mHTMLEditor has gone away). |
317 | | * |
318 | | * @param aNode The node |
319 | | * @param aAction Which edge to find: |
320 | | * eNext/eNextWord/eToEndOfLine indicates beginning, |
321 | | * ePrevious/PreviousWord/eToBeginningOfLine ending. |
322 | | */ |
323 | | EditorDOMPoint GetGoodSelPointForNode(nsINode& aNode, |
324 | | nsIEditor::EDirection aAction); |
325 | | |
326 | | /** |
327 | | * TryToJoinBlocksWithTransaction() tries to join two block elements. The |
328 | | * right element is always joined to the left element. If the elements are |
329 | | * the same type and not nested within each other, |
330 | | * JoinEditableNodesWithTransaction() is called (example, joining two list |
331 | | * items together into one). If the elements are not the same type, or one |
332 | | * is a descendant of the other, we instead destroy the right block placing |
333 | | * its children into leftblock. DTD containment rules are followed |
334 | | * throughout. |
335 | | * |
336 | | * @return Sets canceled to true if the operation should do |
337 | | * nothing anymore even if this doesn't join the blocks. |
338 | | * Sets handled to true if this actually handles the |
339 | | * request. Note that this may set it to true even if this |
340 | | * does not join the block. E.g., if the blocks shouldn't |
341 | | * be joined or it's impossible to join them but it's not |
342 | | * unexpected case, this returns true with this. |
343 | | */ |
344 | | MOZ_MUST_USE EditActionResult |
345 | | TryToJoinBlocksWithTransaction(nsIContent& aLeftNode, |
346 | | nsIContent& aRightNode); |
347 | | |
348 | | /** |
349 | | * MoveBlock() moves the content from aRightBlock starting from aRightOffset |
350 | | * into aLeftBlock at aLeftOffset. Note that the "block" can be inline nodes |
351 | | * between <br>s, or between blocks, etc. DTD containment rules are followed |
352 | | * throughout. |
353 | | * |
354 | | * @return Sets handled to true if this actually joins the nodes. |
355 | | * canceled is always false. |
356 | | */ |
357 | | MOZ_MUST_USE EditActionResult |
358 | | MoveBlock(Element& aLeftBlock, Element& aRightBlock, |
359 | | int32_t aLeftOffset, int32_t aRightOffset); |
360 | | |
361 | | /** |
362 | | * MoveNodeSmart() moves aNode to (aDestElement, aInOutDestOffset). |
363 | | * DTD containment rules are followed throughout. |
364 | | * |
365 | | * @param aOffset returns the point after inserted content. |
366 | | * @return Sets true to handled if this actually moves |
367 | | * the nodes. |
368 | | * canceled is always false. |
369 | | */ |
370 | | MOZ_MUST_USE EditActionResult |
371 | | MoveNodeSmart(nsIContent& aNode, Element& aDestElement, |
372 | | int32_t* aInOutDestOffset); |
373 | | |
374 | | /** |
375 | | * MoveContents() moves the contents of aElement to (aDestElement, |
376 | | * aInOutDestOffset). DTD containment rules are followed throughout. |
377 | | * |
378 | | * @param aInOutDestOffset updated to point after inserted content. |
379 | | * @return Sets true to handled if this actually moves |
380 | | * the nodes. |
381 | | * canceled is always false. |
382 | | */ |
383 | | MOZ_MUST_USE EditActionResult |
384 | | MoveContents(Element& aElement, Element& aDestElement, |
385 | | int32_t* aInOutDestOffset); |
386 | | |
387 | | /** |
388 | | * DeleteElementsExceptTableRelatedElements() removes elements except |
389 | | * table related elements (except <table> itself) and their contents |
390 | | * from the DOM tree. |
391 | | * |
392 | | * @param aNode If this is not a table related element, this |
393 | | * node will be removed from the DOM tree. |
394 | | * Otherwise, this method calls itself recursively |
395 | | * with its children. |
396 | | * |
397 | | */ |
398 | | MOZ_MUST_USE nsresult |
399 | | DeleteElementsExceptTableRelatedElements(nsINode& aNode); |
400 | | |
401 | | /** |
402 | | * XXX Should document what this does. |
403 | | */ |
404 | | MOZ_MUST_USE nsresult |
405 | | WillMakeList(const nsAString* aListType, bool aEntireList, |
406 | | const nsAString* aBulletType, |
407 | | bool* aCancel, bool* aHandled, |
408 | | const nsAString* aItemType = nullptr); |
409 | | |
410 | | /** |
411 | | * Called before removing a list element. This method actually removes |
412 | | * list elements and list item elements at Selection. And move contents |
413 | | * in them where the removed list was. |
414 | | * |
415 | | * @param aCancel Returns true if the operation is canceled. |
416 | | * @param aHandled Returns true if the edit action is handled. |
417 | | */ |
418 | | MOZ_MUST_USE nsresult WillRemoveList(bool* aCancel, bool* aHandled); |
419 | | |
420 | | /** |
421 | | * Called before indenting around Selection. This method actually tries to |
422 | | * indent the contents. |
423 | | * |
424 | | * @param aCancel Returns true if the operation is canceled. |
425 | | * @param aHandled Returns true if the edit action is handled. |
426 | | */ |
427 | | MOZ_MUST_USE nsresult WillIndent(bool* aCancel, bool* aHandled); |
428 | | |
429 | | /** |
430 | | * Called before indenting around Selection and it's in CSS mode. |
431 | | * This method actually tries to indent the contents. |
432 | | * |
433 | | * @param aCancel Returns true if the operation is canceled. |
434 | | * @param aHandled Returns true if the edit action is handled. |
435 | | */ |
436 | | MOZ_MUST_USE nsresult WillCSSIndent(bool* aCancel, bool* aHandled); |
437 | | |
438 | | /** |
439 | | * Called before indenting around Selection and it's not in CSS mode. |
440 | | * This method actually tries to indent the contents. |
441 | | * |
442 | | * @param aCancel Returns true if the operation is canceled. |
443 | | * @param aHandled Returns true if the edit action is handled. |
444 | | */ |
445 | | MOZ_MUST_USE nsresult WillHTMLIndent(bool* aCancel, bool* aHandled); |
446 | | |
447 | | /** |
448 | | * Called before outdenting around Selection. This method actually tries |
449 | | * to indent the contents. |
450 | | * |
451 | | * @param aCancel Returns true if the operation is canceled. |
452 | | * @param aHandled Returns true if the edit action is handled. |
453 | | */ |
454 | | MOZ_MUST_USE nsresult WillOutdent(bool* aCancel, bool* aHandled); |
455 | | |
456 | | /** |
457 | | * Called before aligning contents around Selection. This method actually |
458 | | * sets align attributes to align contents. |
459 | | * |
460 | | * @param aAlignType New align attribute value where the contents |
461 | | * should be aligned to. |
462 | | * @param aCancel Returns true if the operation is canceled. |
463 | | * @param aHandled Returns true if the edit action is handled. |
464 | | */ |
465 | | nsresult WillAlign(const nsAString& aAlignType, |
466 | | bool* aCancel, bool* aHandled); |
467 | | |
468 | | /** |
469 | | * Called before changing absolute positioned element to static positioned. |
470 | | * This method actually changes the position property of nearest absolute |
471 | | * positioned element. Therefore, this might cause destroying the HTML |
472 | | * editor. |
473 | | * |
474 | | * @param aCancel Returns true if the operation is canceled. |
475 | | * @param aHandled Returns true if the edit action is handled. |
476 | | */ |
477 | | MOZ_MUST_USE nsresult |
478 | | WillRemoveAbsolutePosition(bool* aCancel, bool* aHandled); |
479 | | |
480 | | /** |
481 | | * Called before changing z-index. |
482 | | * This method actually changes z-index of nearest absolute positioned |
483 | | * element relatively. Therefore, this might cause destroying the HTML |
484 | | * editor. |
485 | | * |
486 | | * @param aChange Amount to change z-index. |
487 | | * @param aCancel Returns true if the operation is canceled. |
488 | | * @param aHandled Returns true if the edit action is handled. |
489 | | */ |
490 | | MOZ_MUST_USE nsresult |
491 | | WillRelativeChangeZIndex(int32_t aChange, bool* aCancel, bool* aHandled); |
492 | | |
493 | | /** |
494 | | * Called before creating aDefinitionListItemTag around Selection. This |
495 | | * method just calls WillMakeList() with "dl" as aListType and |
496 | | * aDefinitionListItemTag as aItemType. |
497 | | * |
498 | | * @param aDefinitionListItemTag Should be "dt" or "dd". |
499 | | * @param aEntireList XXX not sure |
500 | | * @param aCancel Returns true if the operation is canceled. |
501 | | * @param aHandled Returns true if the edit action is handled. |
502 | | */ |
503 | | MOZ_MUST_USE nsresult |
504 | | WillMakeDefListItem(const nsAString* aBlockType, bool aEntireList, |
505 | | bool* aCancel, bool* aHandled); |
506 | | |
507 | | /** |
508 | | * WillMakeBasicBlock() called before changing block style around Selection. |
509 | | * This method actually does something with calling MakeBasicBlock(). |
510 | | * |
511 | | * @param aBlockType Necessary block style as string. |
512 | | * @param aCancel Returns true if the operation is canceled. |
513 | | * @param aHandled Returns true if the edit action is handled. |
514 | | */ |
515 | | MOZ_MUST_USE nsresult WillMakeBasicBlock(const nsAString& aBlockType, |
516 | | bool* aCancel, bool* aHandled); |
517 | | |
518 | | /** |
519 | | * MakeBasicBlock() applies or clears block style around Selection. |
520 | | * This method creates AutoSelectionRestorer. Therefore, each caller |
521 | | * need to check if the editor is still available even if this returns |
522 | | * NS_OK. |
523 | | * |
524 | | * @param aBlockType New block tag name. |
525 | | * If nsGkAtoms::normal or nsGkAtoms::_empty, |
526 | | * RemoveBlockStyle() will be called. |
527 | | * If nsGkAtoms::blockquote, MakeBlockquote() |
528 | | * will be called. |
529 | | * Otherwise, ApplyBlockStyle() will be called. |
530 | | */ |
531 | | MOZ_MUST_USE nsresult MakeBasicBlock(nsAtom& aBlockType); |
532 | | |
533 | | /** |
534 | | * Called after creating a basic block, indenting, outdenting or aligning |
535 | | * contents. This method inserts moz-<br> element if start container of |
536 | | * Selection needs it. |
537 | | */ |
538 | | MOZ_MUST_USE nsresult DidMakeBasicBlock(); |
539 | | |
540 | | /** |
541 | | * Called before changing an element to absolute positioned. |
542 | | * This method only prepares the operation since DidAbsolutePosition() will |
543 | | * change it actually later. mNewBlock is set to the target element and |
544 | | * if necessary, some ancestor nodes of selection may be split. |
545 | | * |
546 | | * @param aCancel Returns true if the operation is canceled. |
547 | | * @param aHandled Returns true if the edit action is handled. |
548 | | */ |
549 | | MOZ_MUST_USE nsresult WillAbsolutePosition(bool* aCancel, bool* aHandled); |
550 | | |
551 | | /** |
552 | | * PrepareToMakeElementAbsolutePosition() is helper method of |
553 | | * WillAbsolutePosition() since in some cases, needs to restore selection |
554 | | * with AutoSelectionRestorer. So, all callers have to check if |
555 | | * CanHandleEditAction() still returns true after a call of this method. |
556 | | * XXX Should be documented outline of this method. |
557 | | * |
558 | | * @param aHandled Returns true if the edit action is handled. |
559 | | * @param aTargetElement Returns target element which should be |
560 | | * changed to absolute positioned. |
561 | | */ |
562 | | MOZ_MUST_USE nsresult |
563 | | PrepareToMakeElementAbsolutePosition(bool* aHandled, |
564 | | RefPtr<Element>* aTargetElement); |
565 | | |
566 | | /** |
567 | | * Called if nobody handles the edit action to make an element absolute |
568 | | * positioned. |
569 | | * This method actually changes the element which is computed by |
570 | | * WillAbsolutePosition() to absolute positioned. |
571 | | * Therefore, this might cause destroying the HTML editor. |
572 | | */ |
573 | | MOZ_MUST_USE nsresult DidAbsolutePosition(); |
574 | | |
575 | | /** |
576 | | * AlignInnerBlocks() calls AlignBlockContents() for every list item element |
577 | | * and table cell element in aNode. |
578 | | * |
579 | | * @param aNode The node whose descendants should be aligned |
580 | | * to aAlignType. |
581 | | * @param aAlignType New value of align attribute of <div>. |
582 | | */ |
583 | | MOZ_MUST_USE nsresult |
584 | | AlignInnerBlocks(nsINode& aNode, const nsAString& aAlignType); |
585 | | |
586 | | /** |
587 | | * AlignBlockContents() sets align attribute of <div> element which is |
588 | | * only child of aNode to aAlignType. If aNode has 2 or more children or |
589 | | * does not have a <div> element has only child, inserts a <div> element |
590 | | * into aNode and move all children of aNode into the new <div> element. |
591 | | * |
592 | | * @param aNode The node whose contents should be aligned |
593 | | * to aAlignType. |
594 | | * @param aAlignType New value of align attribute of <div> which |
595 | | * is only child of aNode. |
596 | | */ |
597 | | MOZ_MUST_USE nsresult |
598 | | AlignBlockContents(nsINode& aNode, const nsAString& aAlignType); |
599 | | |
600 | | /** |
601 | | * AlignContentsAtSelection() aligns contents around Selection to aAlignType. |
602 | | * This creates AutoSelectionRestorer. Therefore, even if this returns |
603 | | * NS_OK, CanHandleEditAction() may return false if the editor is destroyed |
604 | | * during restoring the Selection. So, every caller needs to check if |
605 | | * CanHandleEditAction() returns true before modifying the DOM tree or |
606 | | * changing Selection. |
607 | | * |
608 | | * @param aAlignType New align attribute value where the contents |
609 | | * should be aligned to. |
610 | | */ |
611 | | MOZ_MUST_USE nsresult |
612 | | AlignContentsAtSelection(const nsAString& aAlignType); |
613 | | |
614 | | nsresult AppendInnerFormatNodes(nsTArray<OwningNonNull<nsINode>>& aArray, |
615 | | nsINode* aNode); |
616 | | nsresult GetFormatString(nsINode* aNode, nsAString &outFormat); |
617 | | |
618 | | /** |
619 | | * aLists and aTables allow the caller to specify what kind of content to |
620 | | * "look inside". If aTables is Tables::yes, look inside any table content, |
621 | | * and insert the inner content into the supplied nsTArray at offset |
622 | | * aIndex. Similarly with aLists and list content. aIndex is updated to |
623 | | * point past inserted elements. |
624 | | */ |
625 | | enum class Lists { no, yes }; |
626 | | enum class Tables { no, yes }; |
627 | | void GetInnerContent(nsINode& aNode, |
628 | | nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes, |
629 | | int32_t* aIndex, Lists aLists = Lists::yes, |
630 | | Tables aTables = Tables::yes); |
631 | | |
632 | | /** |
633 | | * If aNode is the descendant of a listitem, return that li. But table |
634 | | * element boundaries are stoppers on the search. Also stops on the active |
635 | | * editor host (contenteditable). Also test if aNode is an li itself. |
636 | | */ |
637 | | Element* IsInListItem(nsINode* aNode); |
638 | | |
639 | | nsAtom& DefaultParagraphSeparator(); |
640 | | |
641 | | /** |
642 | | * ReturnInHeader() handles insertParagraph command (i.e., handling Enter |
643 | | * key press) in a heading element. This splits aHeader element at |
644 | | * aOffset in aNode. Then, if right heading element is empty, it'll be |
645 | | * removed and new paragraph is created (its type is decided with default |
646 | | * paragraph separator). |
647 | | * |
648 | | * @param aHeader The heading element to be split. |
649 | | * @param aNode Typically, Selection start container, |
650 | | * where to be split. |
651 | | * @param aOffset Typically, Selection start offset in the |
652 | | * start container, where to be split. |
653 | | */ |
654 | | MOZ_MUST_USE nsresult |
655 | | ReturnInHeader(Element& aHeader, nsINode& aNode, int32_t aOffset); |
656 | | |
657 | | /** |
658 | | * ReturnInParagraph() does the right thing for Enter key press or |
659 | | * 'insertParagraph' command in aParentDivOrP. aParentDivOrP will be |
660 | | * split at start of first selection range. |
661 | | * |
662 | | * @param aParentDivOrP The parent block. This must be <p> or <div> |
663 | | * element. |
664 | | * @return Returns with NS_OK if this doesn't meat any |
665 | | * unexpected situation. If this method tries to |
666 | | * split the paragraph, marked as handled. |
667 | | */ |
668 | | MOZ_MUST_USE EditActionResult ReturnInParagraph(Element& aParentDivOrP); |
669 | | |
670 | | /** |
671 | | * SplitParagraph() splits the parent block, aPara, at aSelNode - aOffset. |
672 | | * |
673 | | * @param aParentDivOrP The parent block to be split. This must be <p> |
674 | | * or <div> element. |
675 | | * @param aStartOfRightNode The point to be start of right node after |
676 | | * split. This must be descendant of |
677 | | * aParentDivOrP. |
678 | | * @param aNextBRNode Next <br> node if there is. Otherwise, nullptr. |
679 | | * If this is not nullptr, the <br> node may be |
680 | | * removed. |
681 | | */ |
682 | | template<typename PT, typename CT> |
683 | | MOZ_MUST_USE nsresult |
684 | | SplitParagraph(Element& aParentDivOrP, |
685 | | const EditorDOMPointBase<PT, CT>& aStartOfRightNode, |
686 | | nsIContent* aBRNode); |
687 | | |
688 | | /** |
689 | | * ReturnInListItem() handles insertParagraph command (i.e., handling |
690 | | * Enter key press) in a list item element. |
691 | | * |
692 | | * @param aListItem The list item which has the following point. |
693 | | * @param aNode Typically, Selection start container, where to |
694 | | * insert a break. |
695 | | * @param aOffset Typically, Selection start offset in the |
696 | | * start container, where to insert a break. |
697 | | */ |
698 | | MOZ_MUST_USE nsresult |
699 | | ReturnInListItem(Element& aListItem, nsINode& aNode, int32_t aOffset); |
700 | | |
701 | | /** |
702 | | * Called after handling edit action. This may adjust Selection, remove |
703 | | * unnecessary empty nodes, create <br> elements if needed, etc. |
704 | | */ |
705 | | MOZ_MUST_USE nsresult |
706 | | AfterEditInner(EditSubAction aEditSubAction, |
707 | | nsIEditor::EDirection aDirection); |
708 | | |
709 | | /** |
710 | | * IndentAroundSelectionWithCSS() indents around Selection with CSS. |
711 | | * This method creates AutoSelectionRestorer. Therefore, each caller |
712 | | * need to check if the editor is still available even if this returns |
713 | | * NS_OK. |
714 | | */ |
715 | | MOZ_MUST_USE nsresult IndentAroundSelectionWithCSS(); |
716 | | |
717 | | /** |
718 | | * IndentAroundSelectionWithHTML() indents around Selection with HTML. |
719 | | * This method creates AutoSelectionRestorer. Therefore, each caller |
720 | | * need to check if the editor is still available even if this returns |
721 | | * NS_OK. |
722 | | */ |
723 | | MOZ_MUST_USE nsresult IndentAroundSelectionWithHTML(); |
724 | | |
725 | | /** |
726 | | * OutdentAroundSelection() outdents contents around Selection. |
727 | | * This method creates AutoSelectionRestorer. Therefore, each caller |
728 | | * need to check if the editor is still available even if this returns |
729 | | * NS_OK. |
730 | | * |
731 | | * @return The left content is left content of last |
732 | | * outdented element. |
733 | | * The right content is right content of last |
734 | | * outdented element. |
735 | | * The middle content is middle content of last |
736 | | * outdented element. |
737 | | */ |
738 | | MOZ_MUST_USE SplitRangeOffFromNodeResult OutdentAroundSelection(); |
739 | | |
740 | | /** |
741 | | * SplitRangeOffFromBlockAndRemoveMiddleContainer() splits the nodes |
742 | | * between aStartOfRange and aEndOfRange, then, removes the middle element |
743 | | * and moves its content to where the middle element was. |
744 | | * |
745 | | * @param aBlockElement The node which will be split. |
746 | | * @param aStartOfRange The first node which will be unwrapped |
747 | | * from aBlockElement. |
748 | | * @param aEndOfRange The last node which will be unwrapped from |
749 | | * aBlockElement. |
750 | | * @return The left content is new created left |
751 | | * element of aBlockElement. |
752 | | * The right content is split element, |
753 | | * i.e., must be aBlockElement. |
754 | | * The middle content is nullptr since |
755 | | * removing it is the job of this method. |
756 | | */ |
757 | | MOZ_MUST_USE SplitRangeOffFromNodeResult |
758 | | SplitRangeOffFromBlockAndRemoveMiddleContainer(Element& aBlockElement, |
759 | | nsIContent& aStartOfRange, |
760 | | nsIContent& aEndOfRange); |
761 | | |
762 | | /** |
763 | | * SplitRangeOffFromBlock() splits aBlock at two points, before aStartChild |
764 | | * and after aEndChild. If they are very start or very end of aBlcok, this |
765 | | * won't create empty block. |
766 | | * |
767 | | * @param aBlockElement A block element which will be split. |
768 | | * @param aStartOfMiddleElement Start node of middle block element. |
769 | | * @param aEndOfMiddleElement End node of middle block element. |
770 | | */ |
771 | | MOZ_MUST_USE SplitRangeOffFromNodeResult |
772 | | SplitRangeOffFromBlock(Element& aBlockElement, |
773 | | nsIContent& aStartOfMiddleElement, |
774 | | nsIContent& aEndOfMiddleElement); |
775 | | |
776 | | /** |
777 | | * OutdentPartOfBlock() outdents the nodes between aStartOfOutdent and |
778 | | * aEndOfOutdent. This splits the range off from aBlockElement first. |
779 | | * Then, removes the middle element if aIsBlockIndentedWithCSS is false. |
780 | | * Otherwise, decreases the margin of the middle element. |
781 | | * |
782 | | * @param aBlockElement A block element which includes both |
783 | | * aStartOfOutdent and aEndOfOutdent. |
784 | | * @param aStartOfOutdent First node which is descendant of |
785 | | * aBlockElement will be outdented. |
786 | | * @param aEndOfOutdent Last node which is descandant of |
787 | | * aBlockElement will be outdented. |
788 | | * @param aIsBlockIndentedWithCSS true if aBlockElement is indented with |
789 | | * CSS margin property. |
790 | | * false if aBlockElement is <blockquote> |
791 | | * or something. |
792 | | * @return The left content is new created element |
793 | | * splitting before aStartOfOutdent. |
794 | | * The right content is existing element. |
795 | | * The middle content is outdented element |
796 | | * if aIsBlockIndentedWithCSS is true. |
797 | | * Otherwise, nullptr. |
798 | | */ |
799 | | MOZ_MUST_USE SplitRangeOffFromNodeResult |
800 | | OutdentPartOfBlock(Element& aBlockElement, |
801 | | nsIContent& aStartOfOutdent, nsIContent& aEndOutdent, |
802 | | bool aIsBlockIndentedWithCSS); |
803 | | |
804 | | /** |
805 | | * XXX Should document what this does. |
806 | | * This method creates AutoSelectionRestorer. Therefore, each caller |
807 | | * need to check if the editor is still available even if this returns |
808 | | * NS_OK. |
809 | | */ |
810 | | MOZ_MUST_USE nsresult |
811 | | MakeList(nsAtom& aListType, bool aEntireList, const nsAString* aBulletType, |
812 | | bool* aCancel, nsAtom& aItemType); |
813 | | |
814 | | /** |
815 | | * ConvertListType() replaces child list items of aListElement with |
816 | | * new list item element whose tag name is aNewListItemTag. |
817 | | * Note that if there are other list elements as children of aListElement, |
818 | | * this calls itself recursively even though it's invalid structure. |
819 | | * |
820 | | * @param aListElement The list element whose list items will be |
821 | | * replaced. |
822 | | * @param aNewListTag New list tag name. |
823 | | * @param aNewListItemTag New list item tag name. |
824 | | * @return New list element or an error code if it fails. |
825 | | * New list element may be aListElement if its |
826 | | * tag name is same as aNewListTag. |
827 | | */ |
828 | | MOZ_MUST_USE CreateElementResult |
829 | | ConvertListType(Element& aListElement, nsAtom& aListType, nsAtom& aItemType); |
830 | | |
831 | | /** |
832 | | * CreateStyleForInsertText() sets CSS properties which are stored in |
833 | | * TypeInState to proper element node. |
834 | | * |
835 | | * @param aDocument The document of the editor. |
836 | | */ |
837 | | MOZ_MUST_USE nsresult CreateStyleForInsertText(nsIDocument& aDocument); |
838 | | |
839 | | /** |
840 | | * IsEmptyBlockElement() returns true if aElement is a block level element |
841 | | * and it doesn't have any visible content. |
842 | | */ |
843 | | enum class IgnoreSingleBR |
844 | | { |
845 | | eYes, |
846 | | eNo |
847 | | }; |
848 | | bool IsEmptyBlockElement(Element& aElement, |
849 | | IgnoreSingleBR aIgnoreSingleBR); |
850 | | |
851 | | /** |
852 | | * MaybeDeleteTopMostEmptyAncestor() looks for top most empty block ancestor |
853 | | * of aStartNode in aEditingHostElement. |
854 | | * If found empty ancestor is a list item element, inserts a <br> element |
855 | | * before its parent element if grand parent is a list element. Then, |
856 | | * collapse Selection to after the empty block. |
857 | | * If found empty ancestor is not a list item element, collapse Selection to |
858 | | * somewhere depending on aAction. |
859 | | * Finally, removes the empty block ancestor. |
860 | | * |
861 | | * @param aStartNode Start node to look for empty ancestors. |
862 | | * @param aEditingHostElement Current editing host. |
863 | | * @param aAction If found empty ancestor block is a list item |
864 | | * element, this is ignored. Otherwise: |
865 | | * - If eNext, eNextWord or eToEndOfLine, collapse |
866 | | * Selection to after found empty ancestor. |
867 | | * - If ePrevious, ePreviousWord or |
868 | | * eToBeginningOfLine, collapse Selection to |
869 | | * end of previous editable node. |
870 | | * Otherwise, eNone is allowed but does nothing. |
871 | | * @param aHandled Returns true if this method removes an empty |
872 | | * block ancestor of aStartNode. |
873 | | */ |
874 | | MOZ_MUST_USE nsresult |
875 | | MaybeDeleteTopMostEmptyAncestor(nsINode& aStartNode, |
876 | | Element& aEditingHostElement, |
877 | | nsIEditor::EDirection aAction, |
878 | | bool* aHandled); |
879 | | |
880 | | enum class BRLocation { beforeBlock, blockEnd }; |
881 | | Element* CheckForInvisibleBR(Element& aBlock, BRLocation aWhere, |
882 | | int32_t aOffset = 0); |
883 | | |
884 | | /** |
885 | | * ExpandSelectionForDeletion() may expand Selection range if it's not |
886 | | * collapsed and there is only one range. This may expand to include |
887 | | * invisible <br> element for preventing delete action handler to keep |
888 | | * unexpected nodes. |
889 | | */ |
890 | | MOZ_MUST_USE nsresult ExpandSelectionForDeletion(); |
891 | | |
892 | | /** |
893 | | * NormalizeSelection() adjust Selection if it's not collapsed and there is |
894 | | * only one range. If range start and/or end point is <br> node or something |
895 | | * non-editable point, they should be moved to nearest text node or something |
896 | | * where the other methods easier to handle edit action. |
897 | | */ |
898 | | MOZ_MUST_USE nsresult NormalizeSelection(); |
899 | | |
900 | | /** |
901 | | * GetPromotedPoint() figures out where a start or end point for a block |
902 | | * operation really is. |
903 | | */ |
904 | | EditorDOMPoint |
905 | | GetPromotedPoint(RulesEndpoint aWhere, nsINode& aNode, int32_t aOffset, |
906 | | EditSubAction aEditSubAction); |
907 | | |
908 | | /** |
909 | | * GetPromotedRanges() runs all the selection range endpoint through |
910 | | * GetPromotedPoint(). |
911 | | */ |
912 | | void GetPromotedRanges(nsTArray<RefPtr<nsRange>>& outArrayOfRanges, |
913 | | EditSubAction aEditSubAction); |
914 | | |
915 | | /** |
916 | | * PromoteRange() expands a range to include any parents for which all |
917 | | * editable children are already in range. |
918 | | */ |
919 | | void PromoteRange(nsRange& aRange, EditSubAction aEditSubAction); |
920 | | |
921 | | /** |
922 | | * GetNodesForOperation() runs through the ranges in the array and construct a |
923 | | * new array of nodes to be acted on. |
924 | | * |
925 | | * XXX This name stats with "Get" but actually this modifies the DOM tree with |
926 | | * transaction. We should rename this to making clearer what this does. |
927 | | */ |
928 | | enum class TouchContent { no, yes }; |
929 | | MOZ_MUST_USE nsresult |
930 | | GetNodesForOperation(nsTArray<RefPtr<nsRange>>& aArrayOfRanges, |
931 | | nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes, |
932 | | EditSubAction aEditSubAction, |
933 | | TouchContent aTouchContent); |
934 | | |
935 | | void GetChildNodesForOperation( |
936 | | nsINode& aNode, |
937 | | nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes); |
938 | | |
939 | | /** |
940 | | * GetNodesFromPoint() constructs a list of nodes from a point that will be |
941 | | * operated on. |
942 | | */ |
943 | | MOZ_MUST_USE nsresult |
944 | | GetNodesFromPoint(const EditorDOMPoint& aPoint, EditSubAction aEditSubAction, |
945 | | nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes, |
946 | | TouchContent aTouchContent); |
947 | | |
948 | | /** |
949 | | * GetNodesFromSelection() constructs a list of nodes from the selection that |
950 | | * will be operated on. |
951 | | */ |
952 | | MOZ_MUST_USE nsresult |
953 | | GetNodesFromSelection(EditSubAction aEditSubAction, |
954 | | nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes, |
955 | | TouchContent aTouchContent); |
956 | | |
957 | | enum class EntireList { no, yes }; |
958 | | MOZ_MUST_USE nsresult |
959 | | GetListActionNodes(nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes, |
960 | | EntireList aEntireList, TouchContent aTouchContent); |
961 | | void GetDefinitionListItemTypes(Element* aElement, bool* aDT, bool* aDD); |
962 | | nsresult |
963 | | GetParagraphFormatNodes(nsTArray<OwningNonNull<nsINode>>& outArrayOfNodes); |
964 | | void LookInsideDivBQandList(nsTArray<OwningNonNull<nsINode>>& aNodeArray); |
965 | | |
966 | | /** |
967 | | * BustUpInlinesAtRangeEndpoints() splits nodes at both start and end of |
968 | | * aRangeItem. If this splits at every point, this modifies aRangeItem |
969 | | * to point each split point (typically, right node). Note that this splits |
970 | | * nodes only in highest inline element at every point. |
971 | | * |
972 | | * @param aRangeItem One or two DOM points where should be split. |
973 | | * Will be modified to split point if they're |
974 | | * split. |
975 | | */ |
976 | | MOZ_MUST_USE nsresult BustUpInlinesAtRangeEndpoints(RangeItem& aRangeItem); |
977 | | |
978 | | /** |
979 | | * BustUpInlinesAtBRs() splits before all <br> elements in aNode. All <br> |
980 | | * nodes will be moved before right node at splitting its parent. Finally, |
981 | | * this returns all <br> elements, every left node and aNode with |
982 | | * aOutArrayNodes. |
983 | | * |
984 | | * @param aNode An inline container element. |
985 | | * @param aOutArrayOfNodes All found <br> elements, left nodes (may not |
986 | | * be set if <br> is at start edge of aNode) and |
987 | | * aNode itself. |
988 | | */ |
989 | | MOZ_MUST_USE nsresult |
990 | | BustUpInlinesAtBRs(nsIContent& aNode, |
991 | | nsTArray<OwningNonNull<nsINode>>& aOutArrayOfNodes); |
992 | | |
993 | | /** |
994 | | * GetHiestInlineParent() returns the highest inline node parent between |
995 | | * aNode and the editing host. Even if the editing host is an inline |
996 | | * element, this method never returns the editing host as the result. |
997 | | */ |
998 | | nsIContent* GetHighestInlineParent(nsINode& aNode); |
999 | | |
1000 | | /** |
1001 | | * MakeTransitionList() detects all the transitions in the array, where a |
1002 | | * transition means that adjacent nodes in the array don't have the same |
1003 | | * parent. |
1004 | | */ |
1005 | | void MakeTransitionList(nsTArray<OwningNonNull<nsINode>>& aNodeArray, |
1006 | | nsTArray<bool>& aTransitionArray); |
1007 | | |
1008 | | /** |
1009 | | * RemoveBlockStyle() removes all format blocks, table related element, |
1010 | | * etc in aNodeArray. |
1011 | | * If aNodeArray has a format node, it will be removed and its contents |
1012 | | * will be moved to where it was. |
1013 | | * If aNodeArray has a table related element, <li>, <blockquote> or <div>, |
1014 | | * it will removed and its contents will be moved to where it was. |
1015 | | */ |
1016 | | nsresult RemoveBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray); |
1017 | | |
1018 | | /** |
1019 | | * ApplyBlockStyle() formats all nodes in aNodeArray with block elements |
1020 | | * whose name is aBlockTag. |
1021 | | * If aNodeArray has an inline element, a block element is created and the |
1022 | | * inline element and following inline elements are moved into the new block |
1023 | | * element. |
1024 | | * If aNodeArray has <br> elements, they'll be removed from the DOM tree and |
1025 | | * new block element will be created when there are some remaining inline |
1026 | | * elements. |
1027 | | * If aNodeArray has a block element, this calls itself with children of |
1028 | | * the block element. Then, new block element will be created when there |
1029 | | * are some remaining inline elements. |
1030 | | * |
1031 | | * @param aNodeArray Must be descendants of a node. |
1032 | | * @param aBlockTag The element name of new block elements. |
1033 | | */ |
1034 | | MOZ_MUST_USE nsresult |
1035 | | ApplyBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray, |
1036 | | nsAtom& aBlockTag); |
1037 | | |
1038 | | /** |
1039 | | * MakeBlockquote() inserts at least one <blockquote> element and moves |
1040 | | * nodes in aNodeArray into new <blockquote> elements. If aNodeArray |
1041 | | * includes a table related element except <table>, this calls itself |
1042 | | * recursively to insert <blockquote> into the cell. |
1043 | | * |
1044 | | * @param aNodeArray Nodes which will be moved into created |
1045 | | * <blockquote> elements. |
1046 | | */ |
1047 | | MOZ_MUST_USE nsresult |
1048 | | MakeBlockquote(nsTArray<OwningNonNull<nsINode>>& aNodeArray); |
1049 | | |
1050 | | /** |
1051 | | * MaybeSplitAncestorsForInsertWithTransaction() does nothing if container of |
1052 | | * aStartOfDeepestRightNode can have an element whose tag name is aTag. |
1053 | | * Otherwise, looks for an ancestor node which is or is in active editing |
1054 | | * host and can have an element whose name is aTag. If there is such |
1055 | | * ancestor, its descendants are split. |
1056 | | * |
1057 | | * Note that this may create empty elements while splitting ancestors. |
1058 | | * |
1059 | | * @param aTag The name of element to be inserted |
1060 | | * after calling this method. |
1061 | | * @param aStartOfDeepestRightNode The start point of deepest right node. |
1062 | | * This point must be descendant of |
1063 | | * active editing host. |
1064 | | * @return When succeeded, SplitPoint() returns |
1065 | | * the point to insert the element. |
1066 | | */ |
1067 | | template<typename PT, typename CT> |
1068 | | MOZ_MUST_USE SplitNodeResult |
1069 | | MaybeSplitAncestorsForInsertWithTransaction( |
1070 | | nsAtom& aTag, const EditorDOMPointBase<PT, CT>& aStartOfDeepestRightNode); |
1071 | | |
1072 | | /** |
1073 | | * JoinNearestEditableNodesWithTransaction() joins two editable nodes which |
1074 | | * are themselves or the nearest editable node of aLeftNode and aRightNode. |
1075 | | * XXX This method's behavior is odd. For example, if user types Backspace |
1076 | | * key at the second editable paragraph in this case: |
1077 | | * <div contenteditable> |
1078 | | * <p>first editable paragraph</p> |
1079 | | * <p contenteditable="false">non-editable paragraph</p> |
1080 | | * <p>second editable paragraph</p> |
1081 | | * </div> |
1082 | | * The first editable paragraph's content will be moved into the second |
1083 | | * editable paragraph and the non-editable paragraph becomes the first |
1084 | | * paragraph of the editor. I don't think that it's expected behavior of |
1085 | | * any users... |
1086 | | * |
1087 | | * @param aLeftNode The node which will be removed. |
1088 | | * @param aRightNode The node which will be inserted the content of |
1089 | | * aLeftNode. |
1090 | | * @param aNewFirstChildOfRightNode |
1091 | | * The point at the first child of aRightNode. |
1092 | | */ |
1093 | | MOZ_MUST_USE nsresult |
1094 | | JoinNearestEditableNodesWithTransaction( |
1095 | | nsIContent& aLeftNode, nsIContent& aRightNode, |
1096 | | EditorDOMPoint* aNewFirstChildOfRightNode); |
1097 | | |
1098 | | Element* GetTopEnclosingMailCite(nsINode& aNode); |
1099 | | |
1100 | | /** |
1101 | | * PopListItem() tries to move aListItem outside its parent. If it's |
1102 | | * in a middle of a list element, the parent list element is split before |
1103 | | * aListItem. Then, moves aListItem to before its parent list element. |
1104 | | * I.e., moves aListItem between the 2 list elements if original parent |
1105 | | * was split. Then, if new parent is not a list element, the list item |
1106 | | * element is removed and its contents are moved to where the list item |
1107 | | * element was. |
1108 | | * |
1109 | | * @param aListItem Should be a <li>, <dt> or <dd> element. |
1110 | | * If it's not so, returns NS_ERROR_FAILURE. |
1111 | | * @param aOutOfList Returns true if the list item element is |
1112 | | * removed (i.e., unwrapped contents of |
1113 | | * aListItem). Otherwise, false. |
1114 | | */ |
1115 | | MOZ_MUST_USE nsresult |
1116 | | PopListItem(nsIContent& aListItem, bool* aOutOfList = nullptr); |
1117 | | |
1118 | | /** |
1119 | | * RemoveListStructure() destroys the list structure of aListElement. |
1120 | | * If aListElement has <li>, <dl> or <dt> as a child, the element is removed |
1121 | | * but its descendants are moved to where the list item element was. |
1122 | | * If aListElement has another <ul>, <ol> or <dl> as a child, this method |
1123 | | * is called recursively. |
1124 | | * If aListElement has other nodes as its child, they are just removed. |
1125 | | * Finally, aListElement is removed. and its all children are moved to |
1126 | | * where the aListElement was. |
1127 | | * |
1128 | | * @param aListElement A <ul>, <ol> or <dl> element. |
1129 | | */ |
1130 | | MOZ_MUST_USE nsresult RemoveListStructure(Element& aListElement); |
1131 | | |
1132 | | /** |
1133 | | * CacheInlineStyles() caches style of aNode into mCachedStyles. |
1134 | | * This may cause flushing layout at retrieving computed value of CSS |
1135 | | * properties. |
1136 | | */ |
1137 | | MOZ_MUST_USE nsresult CacheInlineStyles(nsINode* aNode); |
1138 | | |
1139 | | /** |
1140 | | * ReapplyCachedStyles() restores some styles which are disappeared during |
1141 | | * handling edit action and it should be restored. This may cause flushing |
1142 | | * layout at retrieving computed value of CSS properties. |
1143 | | */ |
1144 | | MOZ_MUST_USE nsresult ReapplyCachedStyles(); |
1145 | | |
1146 | | void ClearCachedStyles(); |
1147 | | |
1148 | | /** |
1149 | | * InsertBRElementToEmptyListItemsAndTableCellsInChangedRange() inserts |
1150 | | * <br> element into empty list item or table cell elements. |
1151 | | */ |
1152 | | MOZ_MUST_USE nsresult |
1153 | | InsertBRElementToEmptyListItemsAndTableCellsInChangedRange(); |
1154 | | |
1155 | | /** |
1156 | | * AdjustWhitespace() may replace whitespaces with NBSP or something. |
1157 | | * See WSRunObject::AdjustWhitespace() for the detail. |
1158 | | */ |
1159 | | MOZ_MUST_USE nsresult AdjustWhitespace(); |
1160 | | |
1161 | | /** |
1162 | | * PinSelectionToNewBlock() may collapse Selection around mNewNode if it's |
1163 | | * necessary, |
1164 | | */ |
1165 | | MOZ_MUST_USE nsresult PinSelectionToNewBlock(); |
1166 | | |
1167 | | void CheckInterlinePosition(); |
1168 | | |
1169 | | /** |
1170 | | * AdjustSelection() may adjust Selection range to nearest editable content. |
1171 | | * Despite of the name, this may change the DOM tree. If it needs to create |
1172 | | * a <br> to put caret, this tries to create a <br> element. |
1173 | | * |
1174 | | * @param aAction Maybe used to look for a good point to put caret. |
1175 | | */ |
1176 | | MOZ_MUST_USE nsresult AdjustSelection(nsIEditor::EDirection aAction); |
1177 | | |
1178 | | /** |
1179 | | * FindNearEditableNode() tries to find an editable node near aPoint. |
1180 | | * |
1181 | | * @param aPoint The DOM point where to start to search from. |
1182 | | * @param aDirection If nsIEditor::ePrevious is set, this searches an |
1183 | | * editable node from next nodes. Otherwise, from |
1184 | | * previous nodes. |
1185 | | * @return If found, returns non-nullptr. Otherwise, nullptr. |
1186 | | * Note that if found node is in different table element, |
1187 | | * this returns nullptr. |
1188 | | * And also if aDirection is not nsIEditor::ePrevious, |
1189 | | * the result may be the node pointed by aPoint. |
1190 | | */ |
1191 | | template<typename PT, typename CT> |
1192 | | nsIContent* FindNearEditableNode(const EditorDOMPointBase<PT, CT>& aPoint, |
1193 | | nsIEditor::EDirection aDirection); |
1194 | | /** |
1195 | | * Returns true if aNode1 or aNode2 or both is the descendant of some type of |
1196 | | * table element, but their nearest table element ancestors differ. "Table |
1197 | | * element" here includes not just <table> but also <td>, <tbody>, <tr>, etc. |
1198 | | * The nodes count as being their own descendants for this purpose, so a |
1199 | | * table element is its own nearest table element ancestor. |
1200 | | */ |
1201 | | bool InDifferentTableElements(nsINode* aNode1, nsINode* aNode2); |
1202 | | |
1203 | | /** |
1204 | | * RemoveEmptyNodesInChangedRange() removes all empty nodes in |
1205 | | * mDocChangeRange. However, if mail-cite node has only a <br> element, |
1206 | | * the node will be removed but <br> element is moved to where the |
1207 | | * mail-cite node was. |
1208 | | * XXX This method is expensive if mDocChangeRange is too wide and may |
1209 | | * remove unexpected empty element, e.g., it was created by JS, but |
1210 | | * we haven't touched it. Cannot we remove this method and make |
1211 | | * guarantee that empty nodes won't be created? |
1212 | | */ |
1213 | | MOZ_MUST_USE nsresult RemoveEmptyNodesInChangedRange(); |
1214 | | |
1215 | | nsresult SelectionEndpointInNode(nsINode* aNode, bool* aResult); |
1216 | | nsresult UpdateDocChangeRange(nsRange* aRange); |
1217 | | |
1218 | | /** |
1219 | | * ConfirmSelectionInBody() makes sure that Selection is in editor root |
1220 | | * element typically <body> element (see HTMLEditor::UpdateRootElement()) |
1221 | | * and only one Selection range. |
1222 | | * XXX This method is not necessary because even if selection is outside the |
1223 | | * <body> element, elements outside the <body> element should be |
1224 | | * editable, e.g., any element can be inserted siblings as <body> element |
1225 | | * and other browsers allow to edit such elements. |
1226 | | */ |
1227 | | MOZ_MUST_USE nsresult ConfirmSelectionInBody(); |
1228 | | |
1229 | | /** |
1230 | | * IsEmptyInline: Return true if aNode is an empty inline container |
1231 | | */ |
1232 | | bool IsEmptyInline(nsINode& aNode); |
1233 | | |
1234 | | bool ListIsEmptyLine(nsTArray<OwningNonNull<nsINode>>& arrayOfNodes); |
1235 | | |
1236 | | /** |
1237 | | * RemoveAlignment() removes align attributes, text-align properties and |
1238 | | * <center> elements in aNode. |
1239 | | * |
1240 | | * @param aNode Alignment information of the node and/or its |
1241 | | * descendants will be removed. |
1242 | | * @param aAlignType New align value to be set only when it's in |
1243 | | * CSS mode and this method meets <table> or <hr>. |
1244 | | * XXX This is odd and not clear when you see |
1245 | | * caller of this method. Do you have better |
1246 | | * idea? |
1247 | | * @param aDescendantsOnly true if align information of aNode itself |
1248 | | * shouldn't be removed. Otherwise, false. |
1249 | | */ |
1250 | | MOZ_MUST_USE nsresult |
1251 | | RemoveAlignment(nsINode& aNode, const nsAString& aAlignType, |
1252 | | bool aDescendantsOnly); |
1253 | | |
1254 | | /** |
1255 | | * MakeSureElemStartsOrEndsOnCR() inserts <br> element at start (end) of |
1256 | | * aNode if neither: |
1257 | | * - first (last) editable child of aNode is a block or a <br>, |
1258 | | * - previous (next) sibling of aNode is block or a <br> |
1259 | | * - nor no previous (next) sibling of aNode. |
1260 | | * |
1261 | | * @param aNode The node which may be inserted <br> element. |
1262 | | * @param aStarts true for trying to insert <br> to the start. |
1263 | | * false for trying to insert <br> to the end. |
1264 | | */ |
1265 | | MOZ_MUST_USE nsresult |
1266 | | MakeSureElemStartsOrEndsOnCR(nsINode& aNode, bool aStarts); |
1267 | | |
1268 | | /** |
1269 | | * AlignBlock() resets align attribute, text-align property, etc first. |
1270 | | * Then, aligns contents of aElement on aAlignType. |
1271 | | * |
1272 | | * @param aElement The element whose contents will be aligned. |
1273 | | * @param aAlignType Boundary or "center" which contents should be |
1274 | | * aligned on. |
1275 | | * @param aResetAlignOf Resets align of whether element and its |
1276 | | * descendants or only descendants. |
1277 | | */ |
1278 | | enum class ResetAlignOf { ElementAndDescendants, OnlyDescendants }; |
1279 | | MOZ_MUST_USE nsresult |
1280 | | AlignBlock(Element& aElement, const nsAString& aAlignType, |
1281 | | ResetAlignOf aResetAlignOf); |
1282 | | |
1283 | | /** |
1284 | | * IncreaseMarginToIndent() increases the margin of aElement. See the |
1285 | | * document of ChangeMarginStart() for the detail. |
1286 | | * XXX This is not aware of vertical writing-mode. |
1287 | | * |
1288 | | * @param aElement The element to be indented. |
1289 | | */ |
1290 | | MOZ_MUST_USE nsresult IncreaseMarginToIndent(Element& aElement) |
1291 | 0 | { |
1292 | 0 | return ChangeMarginStart(aElement, true); |
1293 | 0 | } |
1294 | | |
1295 | | /** |
1296 | | * DecreaseMarginToOutdent() decreases the margin of aElement. See the |
1297 | | * document of ChangeMarginStart() for the detail. |
1298 | | * XXX This is not aware of vertical writing-mode. |
1299 | | * |
1300 | | * @param aElement The element to be outdented. |
1301 | | */ |
1302 | | MOZ_MUST_USE nsresult DecreaseMarginToOutdent(Element& aElement) |
1303 | 0 | { |
1304 | 0 | return ChangeMarginStart(aElement, false); |
1305 | 0 | } |
1306 | | |
1307 | | /** |
1308 | | * ChangeMarginStart() changes margin of aElement to indent or outdent. |
1309 | | * However, use IncreaseMarginToIndent() and DecreaseMarginToOutdent() |
1310 | | * instead. If it's rtl text, margin-right will be changed. Otherwise, |
1311 | | * margin-left. |
1312 | | * XXX This is not aware of vertical writing-mode. |
1313 | | * |
1314 | | * @param aElement The element to be indented or outdented. |
1315 | | * @param aIncrease true for indent, false for outdent. |
1316 | | */ |
1317 | | MOZ_MUST_USE nsresult ChangeMarginStart(Element& aElement, bool aIncrease); |
1318 | | |
1319 | | void DocumentModifiedWorker(); |
1320 | | |
1321 | | /** |
1322 | | * InitStyleCacheArray() initializes aStyleCache for usable with |
1323 | | * GetInlineStyles(). |
1324 | | */ |
1325 | | void InitStyleCacheArray(StyleCache aStyleCache[SIZE_STYLE_TABLE]); |
1326 | | |
1327 | | /** |
1328 | | * GetInlineStyles() retrieves the style of aNode and modifies each item of |
1329 | | * aStyleCache. This might cause flushing layout at retrieving computed |
1330 | | * values of CSS properties. |
1331 | | */ |
1332 | | MOZ_MUST_USE nsresult |
1333 | | GetInlineStyles(nsINode* aNode, StyleCache aStyleCache[SIZE_STYLE_TABLE]); |
1334 | | |
1335 | | protected: |
1336 | | HTMLEditor* mHTMLEditor; |
1337 | | RefPtr<nsRange> mDocChangeRange; |
1338 | | bool mListenerEnabled; |
1339 | | bool mReturnInEmptyLIKillsList; |
1340 | | bool mDidDeleteSelection; |
1341 | | bool mDidRangedDelete; |
1342 | | bool mRestoreContentEditableCount; |
1343 | | RefPtr<nsRange> mUtilRange; |
1344 | | // Need to remember an int across willJoin/didJoin... |
1345 | | uint32_t mJoinOffset; |
1346 | | RefPtr<Element> mNewBlock; |
1347 | | RefPtr<RangeItem> mRangeItem; |
1348 | | |
1349 | | // XXX In strict speaking, mCachedStyles isn't enough to cache inline styles |
1350 | | // because inline style can be specified with "style" attribute and/or |
1351 | | // CSS in <style> elements or CSS files. So, we need to look for better |
1352 | | // implementation about this. |
1353 | | StyleCache mCachedStyles[SIZE_STYLE_TABLE]; |
1354 | | }; |
1355 | | |
1356 | | } // namespace mozilla |
1357 | | |
1358 | | #endif // #ifndef HTMLEditRules_h |
1359 | | |