OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 // We should calculate visible range in list item because inserting new | 82 // We should calculate visible range in list item because inserting new |
83 // list element will change visibility of list item, e.g. :first-child | 83 // list element will change visibility of list item, e.g. :first-child |
84 // CSS selector. | 84 // CSS selector. |
85 RefPtrWillBeRawPtr<HTMLElement> newList = toHTMLElement(document().createEle
ment(listElement->tagQName(), false).get()); | 85 RefPtrWillBeRawPtr<HTMLElement> newList = toHTMLElement(document().createEle
ment(listElement->tagQName(), false).get()); |
86 insertNodeBefore(newList, selectedListItem.get()); | 86 insertNodeBefore(newList, selectedListItem.get()); |
87 | 87 |
88 // We should clone all the children of the list item for indenting purposes.
However, in case the current | 88 // We should clone all the children of the list item for indenting purposes.
However, in case the current |
89 // selection does not encompass all its children, we need to explicitally ha
ndle the same. The original | 89 // selection does not encompass all its children, we need to explicitally ha
ndle the same. The original |
90 // list item too would require proper deletion in that case. | 90 // list item too would require proper deletion in that case. |
91 if (end.anchorNode() == selectedListItem.get() || end.anchorNode()->isDescen
dantOf(selectedListItem->lastChild())) { | 91 if (end.anchorNode() == selectedListItem.get() || end.anchorNode()->isDescen
dantOf(selectedListItem->lastChild())) { |
92 moveParagraphWithClones(VisiblePosition(start), VisiblePosition(end), ne
wList.get(), selectedListItem.get()); | 92 moveParagraphWithClones(createVisiblePosition(start), createVisiblePosit
ion(end), newList.get(), selectedListItem.get()); |
93 } else { | 93 } else { |
94 moveParagraphWithClones(VisiblePosition(start), VisiblePosition(position
AfterNode(selectedListItem->lastChild())), newList.get(), selectedListItem.get()
); | 94 moveParagraphWithClones(createVisiblePosition(start), createVisiblePosit
ion(positionAfterNode(selectedListItem->lastChild())), newList.get(), selectedLi
stItem.get()); |
95 removeNode(selectedListItem.get()); | 95 removeNode(selectedListItem.get()); |
96 } | 96 } |
97 | 97 |
98 if (canMergeLists(previousList.get(), newList.get())) | 98 if (canMergeLists(previousList.get(), newList.get())) |
99 mergeIdenticalElements(previousList.get(), newList.get()); | 99 mergeIdenticalElements(previousList.get(), newList.get()); |
100 if (canMergeLists(newList.get(), nextList.get())) | 100 if (canMergeLists(newList.get(), nextList.get())) |
101 mergeIdenticalElements(newList.get(), nextList.get()); | 101 mergeIdenticalElements(newList.get(), nextList.get()); |
102 | 102 |
103 return true; | 103 return true; |
104 } | 104 } |
105 | 105 |
106 void IndentOutdentCommand::indentIntoBlockquote(const Position& start, const Pos
ition& end, RefPtrWillBeRawPtr<HTMLElement>& targetBlockquote) | 106 void IndentOutdentCommand::indentIntoBlockquote(const Position& start, const Pos
ition& end, RefPtrWillBeRawPtr<HTMLElement>& targetBlockquote) |
107 { | 107 { |
108 Element* enclosingCell = toElement(enclosingNodeOfType(start, &isTableCell))
; | 108 Element* enclosingCell = toElement(enclosingNodeOfType(start, &isTableCell))
; |
109 Element* elementToSplitTo; | 109 Element* elementToSplitTo; |
110 if (enclosingCell) | 110 if (enclosingCell) |
111 elementToSplitTo = enclosingCell; | 111 elementToSplitTo = enclosingCell; |
112 else if (enclosingList(start.computeContainerNode())) | 112 else if (enclosingList(start.computeContainerNode())) |
113 elementToSplitTo = enclosingBlock(start.computeContainerNode()); | 113 elementToSplitTo = enclosingBlock(start.computeContainerNode()); |
114 else | 114 else |
115 elementToSplitTo = editableRootForPosition(start); | 115 elementToSplitTo = editableRootForPosition(start); |
116 | 116 |
117 if (!elementToSplitTo) | 117 if (!elementToSplitTo) |
118 return; | 118 return; |
119 | 119 |
120 RefPtrWillBeRawPtr<Node> outerBlock = (start.computeContainerNode() == eleme
ntToSplitTo) ? start.computeContainerNode() : splitTreeToNode(start.computeConta
inerNode(), elementToSplitTo).get(); | 120 RefPtrWillBeRawPtr<Node> outerBlock = (start.computeContainerNode() == eleme
ntToSplitTo) ? start.computeContainerNode() : splitTreeToNode(start.computeConta
inerNode(), elementToSplitTo).get(); |
121 | 121 |
122 VisiblePosition startOfContents(start); | 122 VisiblePosition startOfContents = createVisiblePosition(start); |
123 if (!targetBlockquote) { | 123 if (!targetBlockquote) { |
124 // Create a new blockquote and insert it as a child of the root editable
element. We accomplish | 124 // Create a new blockquote and insert it as a child of the root editable
element. We accomplish |
125 // this by splitting all parents of the current paragraph up to that poi
nt. | 125 // this by splitting all parents of the current paragraph up to that poi
nt. |
126 targetBlockquote = createBlockElement(); | 126 targetBlockquote = createBlockElement(); |
127 if (outerBlock == start.computeContainerNode()) | 127 if (outerBlock == start.computeContainerNode()) |
128 insertNodeAt(targetBlockquote, start); | 128 insertNodeAt(targetBlockquote, start); |
129 else | 129 else |
130 insertNodeBefore(targetBlockquote, outerBlock); | 130 insertNodeBefore(targetBlockquote, outerBlock); |
131 startOfContents = VisiblePosition(positionInParentAfterNode(*targetBlock
quote)); | 131 startOfContents = createVisiblePosition(positionInParentAfterNode(*targe
tBlockquote)); |
132 } | 132 } |
133 | 133 |
134 VisiblePosition endOfContents(end); | 134 VisiblePosition endOfContents = createVisiblePosition(end); |
135 if (startOfContents.isNull() || endOfContents.isNull()) | 135 if (startOfContents.isNull() || endOfContents.isNull()) |
136 return; | 136 return; |
137 moveParagraphWithClones(startOfContents, endOfContents, targetBlockquote.get
(), outerBlock.get()); | 137 moveParagraphWithClones(startOfContents, endOfContents, targetBlockquote.get
(), outerBlock.get()); |
138 } | 138 } |
139 | 139 |
140 void IndentOutdentCommand::outdentParagraph() | 140 void IndentOutdentCommand::outdentParagraph() |
141 { | 141 { |
142 VisiblePosition visibleStartOfParagraph = startOfParagraph(endingSelection()
.visibleStart()); | 142 VisiblePosition visibleStartOfParagraph = startOfParagraph(endingSelection()
.visibleStart()); |
143 VisiblePosition visibleEndOfParagraph = endOfParagraph(visibleStartOfParagra
ph); | 143 VisiblePosition visibleEndOfParagraph = endOfParagraph(visibleStartOfParagra
ph); |
144 | 144 |
145 HTMLElement* enclosingElement = toHTMLElement(enclosingNodeOfType(visibleSta
rtOfParagraph.deepEquivalent(), &isHTMLListOrBlockquoteElement)); | 145 HTMLElement* enclosingElement = toHTMLElement(enclosingNodeOfType(visibleSta
rtOfParagraph.deepEquivalent(), &isHTMLListOrBlockquoteElement)); |
146 if (!enclosingElement || !enclosingElement->parentNode()->hasEditableStyle()
) // We can't outdent if there is no place to go! | 146 if (!enclosingElement || !enclosingElement->parentNode()->hasEditableStyle()
) // We can't outdent if there is no place to go! |
147 return; | 147 return; |
148 | 148 |
149 // Use InsertListCommand to remove the selection from the list | 149 // Use InsertListCommand to remove the selection from the list |
150 if (isHTMLOListElement(*enclosingElement)) { | 150 if (isHTMLOListElement(*enclosingElement)) { |
151 applyCommandToComposite(InsertListCommand::create(document(), InsertList
Command::OrderedList)); | 151 applyCommandToComposite(InsertListCommand::create(document(), InsertList
Command::OrderedList)); |
152 return; | 152 return; |
153 } | 153 } |
154 if (isHTMLUListElement(*enclosingElement)) { | 154 if (isHTMLUListElement(*enclosingElement)) { |
155 applyCommandToComposite(InsertListCommand::create(document(), InsertList
Command::UnorderedList)); | 155 applyCommandToComposite(InsertListCommand::create(document(), InsertList
Command::UnorderedList)); |
156 return; | 156 return; |
157 } | 157 } |
158 | 158 |
159 // The selection is inside a blockquote i.e. enclosingNode is a blockquote | 159 // The selection is inside a blockquote i.e. enclosingNode is a blockquote |
160 VisiblePosition positionInEnclosingBlock = VisiblePosition(firstPositionInNo
de(enclosingElement)); | 160 VisiblePosition positionInEnclosingBlock = createVisiblePosition(firstPositi
onInNode(enclosingElement)); |
161 // If the blockquote is inline, the start of the enclosing block coincides w
ith | 161 // If the blockquote is inline, the start of the enclosing block coincides w
ith |
162 // positionInEnclosingBlock. | 162 // positionInEnclosingBlock. |
163 VisiblePosition startOfEnclosingBlock = (enclosingElement->layoutObject() &&
enclosingElement->layoutObject()->isInline()) ? positionInEnclosingBlock : star
tOfBlock(positionInEnclosingBlock); | 163 VisiblePosition startOfEnclosingBlock = (enclosingElement->layoutObject() &&
enclosingElement->layoutObject()->isInline()) ? positionInEnclosingBlock : star
tOfBlock(positionInEnclosingBlock); |
164 VisiblePosition lastPositionInEnclosingBlock = VisiblePosition(lastPositionI
nNode(enclosingElement)); | 164 VisiblePosition lastPositionInEnclosingBlock = createVisiblePosition(lastPos
itionInNode(enclosingElement)); |
165 VisiblePosition endOfEnclosingBlock = endOfBlock(lastPositionInEnclosingBloc
k); | 165 VisiblePosition endOfEnclosingBlock = endOfBlock(lastPositionInEnclosingBloc
k); |
166 if (visibleStartOfParagraph.deepEquivalent() == startOfEnclosingBlock.deepEq
uivalent() | 166 if (visibleStartOfParagraph.deepEquivalent() == startOfEnclosingBlock.deepEq
uivalent() |
167 && visibleEndOfParagraph.deepEquivalent() == endOfEnclosingBlock.deepEqu
ivalent()) { | 167 && visibleEndOfParagraph.deepEquivalent() == endOfEnclosingBlock.deepEqu
ivalent()) { |
168 // The blockquote doesn't contain anything outside the paragraph, so it
can be totally removed. | 168 // The blockquote doesn't contain anything outside the paragraph, so it
can be totally removed. |
169 Node* splitPoint = enclosingElement->nextSibling(); | 169 Node* splitPoint = enclosingElement->nextSibling(); |
170 removeNodePreservingChildren(enclosingElement); | 170 removeNodePreservingChildren(enclosingElement); |
171 // outdentRegion() assumes it is operating on the first paragraph of an
enclosing blockquote, but if there are multiply nested blockquotes and we've | 171 // outdentRegion() assumes it is operating on the first paragraph of an
enclosing blockquote, but if there are multiply nested blockquotes and we've |
172 // just removed one, then this assumption isn't true. By splitting the n
ext containing blockquote after this node, we keep this assumption true | 172 // just removed one, then this assumption isn't true. By splitting the n
ext containing blockquote after this node, we keep this assumption true |
173 if (splitPoint) { | 173 if (splitPoint) { |
174 if (Element* splitPointParent = splitPoint->parentElement()) { | 174 if (Element* splitPointParent = splitPoint->parentElement()) { |
175 if (splitPointParent->hasTagName(blockquoteTag) | 175 if (splitPointParent->hasTagName(blockquoteTag) |
176 && !splitPoint->hasTagName(blockquoteTag) | 176 && !splitPoint->hasTagName(blockquoteTag) |
177 && splitPointParent->parentNode()->hasEditableStyle()) // We
can't outdent if there is no place to go! | 177 && splitPointParent->parentNode()->hasEditableStyle()) // We
can't outdent if there is no place to go! |
178 splitElement(splitPointParent, splitPoint); | 178 splitElement(splitPointParent, splitPoint); |
179 } | 179 } |
180 } | 180 } |
181 | 181 |
182 document().updateLayoutIgnorePendingStylesheets(); | 182 document().updateLayoutIgnorePendingStylesheets(); |
183 visibleStartOfParagraph = VisiblePosition(visibleStartOfParagraph.deepEq
uivalent()); | 183 visibleStartOfParagraph = createVisiblePosition(visibleStartOfParagraph.
deepEquivalent()); |
184 visibleEndOfParagraph = VisiblePosition(visibleEndOfParagraph.deepEquiva
lent()); | 184 visibleEndOfParagraph = createVisiblePosition(visibleEndOfParagraph.deep
Equivalent()); |
185 if (visibleStartOfParagraph.isNotNull() && !isStartOfParagraph(visibleSt
artOfParagraph)) | 185 if (visibleStartOfParagraph.isNotNull() && !isStartOfParagraph(visibleSt
artOfParagraph)) |
186 insertNodeAt(createBreakElement(document()), visibleStartOfParagraph
.deepEquivalent()); | 186 insertNodeAt(createBreakElement(document()), visibleStartOfParagraph
.deepEquivalent()); |
187 if (visibleEndOfParagraph.isNotNull() && !isEndOfParagraph(visibleEndOfP
aragraph)) | 187 if (visibleEndOfParagraph.isNotNull() && !isEndOfParagraph(visibleEndOfP
aragraph)) |
188 insertNodeAt(createBreakElement(document()), visibleEndOfParagraph.d
eepEquivalent()); | 188 insertNodeAt(createBreakElement(document()), visibleEndOfParagraph.d
eepEquivalent()); |
189 | 189 |
190 return; | 190 return; |
191 } | 191 } |
192 RefPtrWillBeRawPtr<Node> splitBlockquoteNode = enclosingElement; | 192 RefPtrWillBeRawPtr<Node> splitBlockquoteNode = enclosingElement; |
193 if (Element* enclosingBlockFlow = enclosingBlock(visibleStartOfParagraph.dee
pEquivalent().anchorNode())) { | 193 if (Element* enclosingBlockFlow = enclosingBlock(visibleStartOfParagraph.dee
pEquivalent().anchorNode())) { |
194 if (enclosingBlockFlow != enclosingElement) { | 194 if (enclosingBlockFlow != enclosingElement) { |
195 splitBlockquoteNode = splitTreeToNode(enclosingBlockFlow, enclosingE
lement, true); | 195 splitBlockquoteNode = splitTreeToNode(enclosingBlockFlow, enclosingE
lement, true); |
196 } else { | 196 } else { |
197 // We split the blockquote at where we start outdenting. | 197 // We split the blockquote at where we start outdenting. |
198 Node* highestInlineNode = highestEnclosingNodeOfType(visibleStartOfP
aragraph.deepEquivalent(), isInline, CannotCrossEditingBoundary, enclosingBlockF
low); | 198 Node* highestInlineNode = highestEnclosingNodeOfType(visibleStartOfP
aragraph.deepEquivalent(), isInline, CannotCrossEditingBoundary, enclosingBlockF
low); |
199 splitElement(enclosingElement, highestInlineNode ? highestInlineNode
: visibleStartOfParagraph.deepEquivalent().anchorNode()); | 199 splitElement(enclosingElement, highestInlineNode ? highestInlineNode
: visibleStartOfParagraph.deepEquivalent().anchorNode()); |
200 } | 200 } |
201 } | 201 } |
202 VisiblePosition startOfParagraphToMove(startOfParagraph(visibleStartOfParagr
aph)); | 202 VisiblePosition startOfParagraphToMove = startOfParagraph(visibleStartOfPara
graph); |
203 VisiblePosition endOfParagraphToMove(endOfParagraph(visibleEndOfParagraph)); | 203 VisiblePosition endOfParagraphToMove = endOfParagraph(visibleEndOfParagraph)
; |
204 if (startOfParagraphToMove.isNull() || endOfParagraphToMove.isNull()) | 204 if (startOfParagraphToMove.isNull() || endOfParagraphToMove.isNull()) |
205 return; | 205 return; |
206 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBreakElement(document(
)); | 206 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBreakElement(document(
)); |
207 insertNodeBefore(placeholder, splitBlockquoteNode); | 207 insertNodeBefore(placeholder, splitBlockquoteNode); |
208 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, VisiblePosition(
positionBeforeNode(placeholder.get())), true); | 208 moveParagraph(startOfParagraphToMove, endOfParagraphToMove, createVisiblePos
ition(positionBeforeNode(placeholder.get())), true); |
209 } | 209 } |
210 | 210 |
211 // FIXME: We should merge this function with ApplyBlockElementCommand::formatSel
ection | 211 // FIXME: We should merge this function with ApplyBlockElementCommand::formatSel
ection |
212 void IndentOutdentCommand::outdentRegion(const VisiblePosition& startOfSelection
, const VisiblePosition& endOfSelection) | 212 void IndentOutdentCommand::outdentRegion(const VisiblePosition& startOfSelection
, const VisiblePosition& endOfSelection) |
213 { | 213 { |
214 VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection); | 214 VisiblePosition endOfCurrentParagraph = endOfParagraph(startOfSelection); |
215 VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection); | 215 VisiblePosition endOfLastParagraph = endOfParagraph(endOfSelection); |
216 | 216 |
217 if (endOfCurrentParagraph.deepEquivalent() == endOfLastParagraph.deepEquival
ent()) { | 217 if (endOfCurrentParagraph.deepEquivalent() == endOfLastParagraph.deepEquival
ent()) { |
218 outdentParagraph(); | 218 outdentParagraph(); |
(...skipping 12 matching lines...) Expand all Loading... |
231 | 231 |
232 outdentParagraph(); | 232 outdentParagraph(); |
233 | 233 |
234 // outdentParagraph could move more than one paragraph if the paragraph | 234 // outdentParagraph could move more than one paragraph if the paragraph |
235 // is in a list item. As a result, endAfterSelection and endOfNextParagr
aph | 235 // is in a list item. As a result, endAfterSelection and endOfNextParagr
aph |
236 // could refer to positions no longer in the document. | 236 // could refer to positions no longer in the document. |
237 if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent()
.inDocument()) | 237 if (endAfterSelection.isNotNull() && !endAfterSelection.deepEquivalent()
.inDocument()) |
238 break; | 238 break; |
239 | 239 |
240 if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent
().inDocument()) { | 240 if (endOfNextParagraph.isNotNull() && !endOfNextParagraph.deepEquivalent
().inDocument()) { |
241 endOfCurrentParagraph = VisiblePosition(endingSelection().end()); | 241 endOfCurrentParagraph = createVisiblePosition(endingSelection().end(
)); |
242 endOfNextParagraph = endOfParagraph(nextPositionOf(endOfCurrentParag
raph)); | 242 endOfNextParagraph = endOfParagraph(nextPositionOf(endOfCurrentParag
raph)); |
243 } | 243 } |
244 endOfCurrentParagraph = endOfNextParagraph; | 244 endOfCurrentParagraph = endOfNextParagraph; |
245 } | 245 } |
246 } | 246 } |
247 | 247 |
248 void IndentOutdentCommand::formatSelection(const VisiblePosition& startOfSelecti
on, const VisiblePosition& endOfSelection) | 248 void IndentOutdentCommand::formatSelection(const VisiblePosition& startOfSelecti
on, const VisiblePosition& endOfSelection) |
249 { | 249 { |
250 if (m_typeOfAction == Indent) | 250 if (m_typeOfAction == Indent) |
251 ApplyBlockElementCommand::formatSelection(startOfSelection, endOfSelecti
on); | 251 ApplyBlockElementCommand::formatSelection(startOfSelection, endOfSelecti
on); |
252 else | 252 else |
253 outdentRegion(startOfSelection, endOfSelection); | 253 outdentRegion(startOfSelection, endOfSelection); |
254 } | 254 } |
255 | 255 |
256 void IndentOutdentCommand::formatRange(const Position& start, const Position& en
d, const Position&, RefPtrWillBeRawPtr<HTMLElement>& blockquoteForNextIndent) | 256 void IndentOutdentCommand::formatRange(const Position& start, const Position& en
d, const Position&, RefPtrWillBeRawPtr<HTMLElement>& blockquoteForNextIndent) |
257 { | 257 { |
258 if (tryIndentingAsListItem(start, end)) | 258 if (tryIndentingAsListItem(start, end)) |
259 blockquoteForNextIndent = nullptr; | 259 blockquoteForNextIndent = nullptr; |
260 else | 260 else |
261 indentIntoBlockquote(start, end, blockquoteForNextIndent); | 261 indentIntoBlockquote(start, end, blockquoteForNextIndent); |
262 } | 262 } |
263 | 263 |
264 } | 264 } |
OLD | NEW |