OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2006, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2010 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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 using namespace HTMLNames; | 44 using namespace HTMLNames; |
45 | 45 |
46 static Node* enclosingListChild(Node* node, Node* listNode) | 46 static Node* enclosingListChild(Node* node, Node* listNode) |
47 { | 47 { |
48 Node* listChild = enclosingListChild(node); | 48 Node* listChild = enclosingListChild(node); |
49 while (listChild && enclosingList(listChild) != listNode) | 49 while (listChild && enclosingList(listChild) != listNode) |
50 listChild = enclosingListChild(listChild->parentNode()); | 50 listChild = enclosingListChild(listChild->parentNode()); |
51 return listChild; | 51 return listChild; |
52 } | 52 } |
53 | 53 |
54 HTMLElement* InsertListCommand::fixOrphanedListChild(Node* node) | 54 HTMLUListElement* InsertListCommand::fixOrphanedListChild(Node* node) |
55 { | 55 { |
56 RefPtrWillBeRawPtr<HTMLUListElement> listElement = createUnorderedListElemen
t(document()); | 56 RefPtrWillBeRawPtr<HTMLUListElement> listElement = createUnorderedListElemen
t(document()); |
57 insertNodeBefore(listElement, node); | 57 insertNodeBefore(listElement, node); |
58 removeNode(node); | 58 removeNode(node); |
59 appendNode(node, listElement); | 59 appendNode(node, listElement); |
60 m_listElement = listElement; | 60 m_listElement = listElement; |
61 return listElement.get(); | 61 return listElement.get(); |
62 } | 62 } |
63 | 63 |
64 PassRefPtrWillBeRawPtr<HTMLElement> InsertListCommand::mergeWithNeighboringLists
(PassRefPtrWillBeRawPtr<HTMLElement> passedList) | 64 PassRefPtrWillBeRawPtr<HTMLElement> InsertListCommand::mergeWithNeighboringLists
(PassRefPtrWillBeRawPtr<HTMLElement> passedList) |
(...skipping 20 matching lines...) Expand all Loading... |
85 | 85 |
86 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
, const HTMLQualifiedName& listTag) | 86 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
, const HTMLQualifiedName& listTag) |
87 { | 87 { |
88 VisiblePosition start = selection.visibleStart(); | 88 VisiblePosition start = selection.visibleStart(); |
89 | 89 |
90 if (!enclosingList(start.deepEquivalent().deprecatedNode())) | 90 if (!enclosingList(start.deepEquivalent().deprecatedNode())) |
91 return false; | 91 return false; |
92 | 92 |
93 VisiblePosition end = startOfParagraph(selection.visibleEnd()); | 93 VisiblePosition end = startOfParagraph(selection.visibleEnd()); |
94 while (start.isNotNull() && start != end) { | 94 while (start.isNotNull() && start != end) { |
95 Element* listNode = enclosingList(start.deepEquivalent().deprecatedNode(
)); | 95 HTMLElement* listElement = enclosingList(start.deepEquivalent().deprecat
edNode()); |
96 if (!listNode || !listNode->hasTagName(listTag)) | 96 if (!listElement || !listElement->hasTagName(listTag)) |
97 return false; | 97 return false; |
98 start = startOfNextParagraph(start); | 98 start = startOfNextParagraph(start); |
99 } | 99 } |
100 | 100 |
101 return true; | 101 return true; |
102 } | 102 } |
103 | 103 |
104 InsertListCommand::InsertListCommand(Document& document, Type type) | 104 InsertListCommand::InsertListCommand(Document& document, Type type) |
105 : CompositeEditCommand(document), m_type(type) | 105 : CompositeEditCommand(document), m_type(type) |
106 { | 106 { |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const HT
MLQualifiedName& listTag, Range& currentSelection) | 203 void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const HT
MLQualifiedName& listTag, Range& currentSelection) |
204 { | 204 { |
205 // FIXME: This will produce unexpected results for a selection that starts j
ust before a | 205 // FIXME: This will produce unexpected results for a selection that starts j
ust before a |
206 // table and ends inside the first cell, selectionForParagraphIteration shou
ld probably | 206 // table and ends inside the first cell, selectionForParagraphIteration shou
ld probably |
207 // be renamed and deployed inside setEndingSelection(). | 207 // be renamed and deployed inside setEndingSelection(). |
208 Node* selectionNode = endingSelection().start().deprecatedNode(); | 208 Node* selectionNode = endingSelection().start().deprecatedNode(); |
209 Node* listChildNode = enclosingListChild(selectionNode); | 209 Node* listChildNode = enclosingListChild(selectionNode); |
210 bool switchListType = false; | 210 bool switchListType = false; |
211 if (listChildNode) { | 211 if (listChildNode) { |
212 // Remove the list chlild. | 212 // Remove the list chlild. |
213 RefPtrWillBeRawPtr<HTMLElement> listNode = enclosingList(listChildNode); | 213 RefPtrWillBeRawPtr<HTMLElement> listElement = enclosingList(listChildNod
e); |
214 if (!listNode) { | 214 if (!listElement) { |
215 listNode = fixOrphanedListChild(listChildNode); | 215 listElement = fixOrphanedListChild(listChildNode); |
216 listNode = mergeWithNeighboringLists(listNode); | 216 listElement = mergeWithNeighboringLists(listElement); |
217 } | 217 } |
218 if (!listNode->hasTagName(listTag)) | 218 if (!listElement->hasTagName(listTag)) |
219 // listChildNode will be removed from the list and a list of type m_
type will be created. | 219 // listChildNode will be removed from the list and a list of type m_
type will be created. |
220 switchListType = true; | 220 switchListType = true; |
221 | 221 |
222 // If the list is of the desired type, and we are not removing the list,
then exit early. | 222 // If the list is of the desired type, and we are not removing the list,
then exit early. |
223 if (!switchListType && forceCreateList) | 223 if (!switchListType && forceCreateList) |
224 return; | 224 return; |
225 | 225 |
226 // If the entire list is selected, then convert the whole list. | 226 // If the entire list is selected, then convert the whole list. |
227 if (switchListType && isNodeVisiblyContainedWithin(*listNode, currentSel
ection)) { | 227 if (switchListType && isNodeVisiblyContainedWithin(*listElement, current
Selection)) { |
228 bool rangeStartIsInList = visiblePositionBeforeNode(*listNode) == Vi
siblePosition(currentSelection.startPosition()); | 228 bool rangeStartIsInList = visiblePositionBeforeNode(*listElement) ==
VisiblePosition(currentSelection.startPosition()); |
229 bool rangeEndIsInList = visiblePositionAfterNode(*listNode) == Visib
lePosition(currentSelection.endPosition()); | 229 bool rangeEndIsInList = visiblePositionAfterNode(*listElement) == Vi
siblePosition(currentSelection.endPosition()); |
230 | 230 |
231 RefPtrWillBeRawPtr<HTMLElement> newList = createHTMLElement(document
(), listTag); | 231 RefPtrWillBeRawPtr<HTMLElement> newList = createHTMLElement(document
(), listTag); |
232 insertNodeBefore(newList, listNode); | 232 insertNodeBefore(newList, listElement); |
233 | 233 |
234 Node* firstChildInList = enclosingListChild(VisiblePosition(firstPos
itionInNode(listNode.get())).deepEquivalent().deprecatedNode(), listNode.get()); | 234 Node* firstChildInList = enclosingListChild(VisiblePosition(firstPos
itionInNode(listElement.get())).deepEquivalent().deprecatedNode(), listElement.g
et()); |
235 Node* outerBlock = firstChildInList && firstChildInList->isBlockFlow
Element() ? firstChildInList : listNode.get(); | 235 Element* outerBlock = firstChildInList && firstChildInList->isBlockF
lowElement() ? toElement(firstChildInList) : listElement.get(); |
236 | 236 |
237 moveParagraphWithClones(VisiblePosition(firstPositionInNode(listNode
.get())), VisiblePosition(lastPositionInNode(listNode.get())), newList.get(), ou
terBlock); | 237 moveParagraphWithClones(VisiblePosition(firstPositionInNode(listElem
ent.get())), VisiblePosition(lastPositionInNode(listElement.get())), newList.get
(), outerBlock); |
238 | 238 |
239 // Manually remove listNode because moveParagraphWithClones sometime
s leaves it behind in the document. | 239 // Manually remove listNode because moveParagraphWithClones sometime
s leaves it behind in the document. |
240 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it
em-with-nested-lists.html. | 240 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it
em-with-nested-lists.html. |
241 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe
lection. | 241 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe
lection. |
242 if (listNode && listNode->inDocument()) | 242 if (listElement && listElement->inDocument()) |
243 removeNode(listNode); | 243 removeNode(listElement); |
244 | 244 |
245 newList = mergeWithNeighboringLists(newList); | 245 newList = mergeWithNeighboringLists(newList); |
246 | 246 |
247 // Restore the start and the end of current selection if they starte
d inside listNode | 247 // Restore the start and the end of current selection if they starte
d inside listNode |
248 // because moveParagraphWithClones could have removed them. | 248 // because moveParagraphWithClones could have removed them. |
249 if (rangeStartIsInList && newList) | 249 if (rangeStartIsInList && newList) |
250 currentSelection.setStart(newList, 0, IGNORE_EXCEPTION); | 250 currentSelection.setStart(newList, 0, IGNORE_EXCEPTION); |
251 if (rangeEndIsInList && newList) | 251 if (rangeEndIsInList && newList) |
252 currentSelection.setEnd(newList, lastOffsetInNode(newList.get())
, IGNORE_EXCEPTION); | 252 currentSelection.setEnd(newList, lastOffsetInNode(newList.get())
, IGNORE_EXCEPTION); |
253 | 253 |
254 setEndingSelection(VisiblePosition(firstPositionInNode(newList.get()
))); | 254 setEndingSelection(VisiblePosition(firstPositionInNode(newList.get()
))); |
255 | 255 |
256 return; | 256 return; |
257 } | 257 } |
258 | 258 |
259 unlistifyParagraph(endingSelection().visibleStart(), listNode.get(), lis
tChildNode); | 259 unlistifyParagraph(endingSelection().visibleStart(), listElement.get(),
listChildNode); |
260 } | 260 } |
261 | 261 |
262 if (!listChildNode || switchListType || forceCreateList) | 262 if (!listChildNode || switchListType || forceCreateList) |
263 m_listElement = listifyParagraph(endingSelection().visibleStart(), listT
ag); | 263 m_listElement = listifyParagraph(endingSelection().visibleStart(), listT
ag); |
264 } | 264 } |
265 | 265 |
266 void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
HTMLElement* listNode, Node* listChildNode) | 266 void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
HTMLElement* listElement, Node* listChildNode) |
267 { | 267 { |
268 Node* nextListChild; | 268 Node* nextListChild; |
269 Node* previousListChild; | 269 Node* previousListChild; |
270 VisiblePosition start; | 270 VisiblePosition start; |
271 VisiblePosition end; | 271 VisiblePosition end; |
272 ASSERT(listChildNode); | 272 ASSERT(listChildNode); |
273 if (isHTMLLIElement(*listChildNode)) { | 273 if (isHTMLLIElement(*listChildNode)) { |
274 start = VisiblePosition(firstPositionInNode(listChildNode)); | 274 start = VisiblePosition(firstPositionInNode(listChildNode)); |
275 end = VisiblePosition(lastPositionInNode(listChildNode)); | 275 end = VisiblePosition(lastPositionInNode(listChildNode)); |
276 nextListChild = listChildNode->nextSibling(); | 276 nextListChild = listChildNode->nextSibling(); |
277 previousListChild = listChildNode->previousSibling(); | 277 previousListChild = listChildNode->previousSibling(); |
278 } else { | 278 } else { |
279 // A paragraph is visually a list item minus a list marker. The paragra
ph will be moved. | 279 // A paragraph is visually a list item minus a list marker. The paragra
ph will be moved. |
280 start = startOfParagraph(originalStart, CanSkipOverEditingBoundary); | 280 start = startOfParagraph(originalStart, CanSkipOverEditingBoundary); |
281 end = endOfParagraph(start, CanSkipOverEditingBoundary); | 281 end = endOfParagraph(start, CanSkipOverEditingBoundary); |
282 nextListChild = enclosingListChild(end.next().deepEquivalent().deprecate
dNode(), listNode); | 282 nextListChild = enclosingListChild(end.next().deepEquivalent().deprecate
dNode(), listElement); |
283 ASSERT(nextListChild != listChildNode); | 283 ASSERT(nextListChild != listChildNode); |
284 previousListChild = enclosingListChild(start.previous().deepEquivalent()
.deprecatedNode(), listNode); | 284 previousListChild = enclosingListChild(start.previous().deepEquivalent()
.deprecatedNode(), listElement); |
285 ASSERT(previousListChild != listChildNode); | 285 ASSERT(previousListChild != listChildNode); |
286 } | 286 } |
287 // When removing a list, we must always create a placeholder to act as a poi
nt of insertion | 287 // When removing a list, we must always create a placeholder to act as a poi
nt of insertion |
288 // for the list content being removed. | 288 // for the list content being removed. |
289 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBreakElement(document(
)); | 289 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBreakElement(document(
)); |
290 RefPtrWillBeRawPtr<HTMLElement> elementToInsert = placeholder; | 290 RefPtrWillBeRawPtr<HTMLElement> elementToInsert = placeholder; |
291 // If the content of the list item will be moved into another list, put it i
n a list item | 291 // If the content of the list item will be moved into another list, put it i
n a list item |
292 // so that we don't create an orphaned list child. | 292 // so that we don't create an orphaned list child. |
293 if (enclosingList(listNode)) { | 293 if (enclosingList(listElement)) { |
294 elementToInsert = createListItemElement(document()); | 294 elementToInsert = createListItemElement(document()); |
295 appendNode(placeholder, elementToInsert); | 295 appendNode(placeholder, elementToInsert); |
296 } | 296 } |
297 | 297 |
298 if (nextListChild && previousListChild) { | 298 if (nextListChild && previousListChild) { |
299 // We want to pull listChildNode out of listNode, and place it before ne
xtListChild | 299 // We want to pull listChildNode out of listNode, and place it before ne
xtListChild |
300 // and after previousListChild, so we split listNode and insert it betwe
en the two lists. | 300 // and after previousListChild, so we split listNode and insert it betwe
en the two lists. |
301 // But to split listNode, we must first split ancestors of listChildNode
between it and listNode, | 301 // But to split listNode, we must first split ancestors of listChildNode
between it and listNode, |
302 // if any exist. | 302 // if any exist. |
303 // FIXME: We appear to split at nextListChild as opposed to listChildNod
e so that when we remove | 303 // FIXME: We appear to split at nextListChild as opposed to listChildNod
e so that when we remove |
304 // listChildNode below in moveParagraphs, previousListChild will be remo
ved along with it if it is | 304 // listChildNode below in moveParagraphs, previousListChild will be remo
ved along with it if it is |
305 // unrendered. But we ought to remove nextListChild too, if it is unrend
ered. | 305 // unrendered. But we ought to remove nextListChild too, if it is unrend
ered. |
306 splitElement(listNode, splitTreeToNode(nextListChild, listNode)); | 306 splitElement(listElement, splitTreeToNode(nextListChild, listElement)); |
307 insertNodeBefore(elementToInsert, listNode); | 307 insertNodeBefore(elementToInsert, listElement); |
308 } else if (nextListChild || listChildNode->parentNode() != listNode) { | 308 } else if (nextListChild || listChildNode->parentNode() != listElement) { |
309 // Just because listChildNode has no previousListChild doesn't mean ther
e isn't any content | 309 // Just because listChildNode has no previousListChild doesn't mean ther
e isn't any content |
310 // in listNode that comes before listChildNode, as listChildNode could h
ave ancestors | 310 // in listNode that comes before listChildNode, as listChildNode could h
ave ancestors |
311 // between it and listNode. So, we split up to listNode before inserting
the placeholder | 311 // between it and listNode. So, we split up to listNode before inserting
the placeholder |
312 // where we're about to move listChildNode to. | 312 // where we're about to move listChildNode to. |
313 if (listChildNode->parentNode() != listNode) | 313 if (listChildNode->parentNode() != listElement) |
314 splitElement(listNode, splitTreeToNode(listChildNode, listNode).get(
)); | 314 splitElement(listElement, splitTreeToNode(listChildNode, listElement
).get()); |
315 insertNodeBefore(elementToInsert, listNode); | 315 insertNodeBefore(elementToInsert, listElement); |
316 } else { | 316 } else { |
317 insertNodeAfter(elementToInsert, listNode); | 317 insertNodeAfter(elementToInsert, listElement); |
318 } | 318 } |
319 | 319 |
320 VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placehol
der.get())); | 320 VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placehol
der.get())); |
321 moveParagraphs(start, end, insertionPoint, /* preserveSelection */ true, /*
preserveStyle */ true, listChildNode); | 321 moveParagraphs(start, end, insertionPoint, /* preserveSelection */ true, /*
preserveStyle */ true, listChildNode); |
322 } | 322 } |
323 | 323 |
324 static Element* adjacentEnclosingList(const VisiblePosition& pos, const VisibleP
osition& adjacentPos, const HTMLQualifiedName& listTag) | 324 static HTMLElement* adjacentEnclosingList(const VisiblePosition& pos, const Visi
blePosition& adjacentPos, const HTMLQualifiedName& listTag) |
325 { | 325 { |
326 Element* listNode = outermostEnclosingList(adjacentPos.deepEquivalent().depr
ecatedNode()); | 326 HTMLElement* listElement = outermostEnclosingList(adjacentPos.deepEquivalent
().deprecatedNode()); |
327 | 327 |
328 if (!listNode) | 328 if (!listElement) |
329 return 0; | 329 return 0; |
330 | 330 |
331 Element* previousCell = enclosingTableCell(pos.deepEquivalent()); | 331 Element* previousCell = enclosingTableCell(pos.deepEquivalent()); |
332 Element* currentCell = enclosingTableCell(adjacentPos.deepEquivalent()); | 332 Element* currentCell = enclosingTableCell(adjacentPos.deepEquivalent()); |
333 | 333 |
334 if (!listNode->hasTagName(listTag) | 334 if (!listElement->hasTagName(listTag) |
335 || listNode->contains(pos.deepEquivalent().deprecatedNode()) | 335 || listElement->contains(pos.deepEquivalent().deprecatedNode()) |
336 || previousCell != currentCell | 336 || previousCell != currentCell |
337 || enclosingList(listNode) != enclosingList(pos.deepEquivalent().depreca
tedNode())) | 337 || enclosingList(listElement) != enclosingList(pos.deepEquivalent().depr
ecatedNode())) |
338 return 0; | 338 return 0; |
339 | 339 |
340 return listNode; | 340 return listElement; |
341 } | 341 } |
342 | 342 |
343 PassRefPtrWillBeRawPtr<HTMLElement> InsertListCommand::listifyParagraph(const Vi
siblePosition& originalStart, const HTMLQualifiedName& listTag) | 343 PassRefPtrWillBeRawPtr<HTMLElement> InsertListCommand::listifyParagraph(const Vi
siblePosition& originalStart, const HTMLQualifiedName& listTag) |
344 { | 344 { |
345 VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBo
undary); | 345 VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBo
undary); |
346 VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary); | 346 VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary); |
347 | 347 |
348 if (start.isNull() || end.isNull()) | 348 if (start.isNull() || end.isNull()) |
349 return nullptr; | 349 return nullptr; |
350 | 350 |
351 // Check for adjoining lists. | 351 // Check for adjoining lists. |
352 RefPtrWillBeRawPtr<HTMLElement> listItemElement = createListItemElement(docu
ment()); | 352 RefPtrWillBeRawPtr<HTMLElement> listItemElement = createListItemElement(docu
ment()); |
353 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBreakElement(document(
)); | 353 RefPtrWillBeRawPtr<HTMLBRElement> placeholder = createBreakElement(document(
)); |
354 appendNode(placeholder, listItemElement); | 354 appendNode(placeholder, listItemElement); |
355 | 355 |
356 // Place list item into adjoining lists. | 356 // Place list item into adjoining lists. |
357 Element* previousList = adjacentEnclosingList(start, start.previous(CannotCr
ossEditingBoundary), listTag); | 357 HTMLElement* previousList = adjacentEnclosingList(start, start.previous(Cann
otCrossEditingBoundary), listTag); |
358 Element* nextList = adjacentEnclosingList(start, end.next(CannotCrossEditing
Boundary), listTag); | 358 HTMLElement* nextList = adjacentEnclosingList(start, end.next(CannotCrossEdi
tingBoundary), listTag); |
359 RefPtrWillBeRawPtr<HTMLElement> listElement = nullptr; | 359 RefPtrWillBeRawPtr<HTMLElement> listElement = nullptr; |
360 if (previousList) | 360 if (previousList) |
361 appendNode(listItemElement, previousList); | 361 appendNode(listItemElement, previousList); |
362 else if (nextList) | 362 else if (nextList) |
363 insertNodeAt(listItemElement, positionBeforeNode(nextList)); | 363 insertNodeAt(listItemElement, positionBeforeNode(nextList)); |
364 else { | 364 else { |
365 // Create the list. | 365 // Create the list. |
366 listElement = createHTMLElement(document(), listTag); | 366 listElement = createHTMLElement(document(), listTag); |
367 appendNode(listItemElement, listElement); | 367 appendNode(listItemElement, listElement); |
368 | 368 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 return listElement; | 412 return listElement; |
413 } | 413 } |
414 | 414 |
415 void InsertListCommand::trace(Visitor* visitor) | 415 void InsertListCommand::trace(Visitor* visitor) |
416 { | 416 { |
417 visitor->trace(m_listElement); | 417 visitor->trace(m_listElement); |
418 CompositeEditCommand::trace(visitor); | 418 CompositeEditCommand::trace(visitor); |
419 } | 419 } |
420 | 420 |
421 } | 421 } |
OLD | NEW |