| 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 |