| 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 22 matching lines...) Expand all Loading... |
| 33 #include "core/editing/VisibleUnits.h" | 33 #include "core/editing/VisibleUnits.h" |
| 34 #include "core/editing/htmlediting.h" | 34 #include "core/editing/htmlediting.h" |
| 35 #include "core/html/HTMLElement.h" | 35 #include "core/html/HTMLElement.h" |
| 36 | 36 |
| 37 namespace WebCore { | 37 namespace WebCore { |
| 38 | 38 |
| 39 using namespace HTMLNames; | 39 using namespace HTMLNames; |
| 40 | 40 |
| 41 static Node* enclosingListChild(Node* node, Node* listNode) | 41 static Node* enclosingListChild(Node* node, Node* listNode) |
| 42 { | 42 { |
| 43 Node* listChild = enclosingListChild(node); | 43 Handle<Node> listChild = enclosingListChild(adoptRawResult(node)); |
| 44 while (listChild && enclosingList(listChild) != listNode) { | 44 while (listChild && enclosingList(listChild) != listNode) { |
| 45 HandleScope scope; | 45 HandleScope scope; |
| 46 listChild = enclosingListChild(listChild->parentNode().handle().raw()); | 46 listChild = enclosingListChild(listChild->parentNode()); |
| 47 } | 47 } |
| 48 return listChild; | 48 return listChild.raw(); |
| 49 } | 49 } |
| 50 | 50 |
| 51 Result<HTMLElement> InsertListCommand::insertList(const Handle<Document>& docume
nt, Type type) | 51 Result<HTMLElement> InsertListCommand::insertList(const Handle<Document>& docume
nt, Type type) |
| 52 { | 52 { |
| 53 RefPtr<InsertListCommand> insertCommand = create(document, type); | 53 RefPtr<InsertListCommand> insertCommand = create(document, type); |
| 54 insertCommand->apply(); | 54 insertCommand->apply(); |
| 55 return insertCommand->m_listElement; | 55 return insertCommand->m_listElement; |
| 56 } | 56 } |
| 57 | 57 |
| 58 Result<HTMLElement> InsertListCommand::fixOrphanedListChild(Node* node) | 58 Result<HTMLElement> InsertListCommand::fixOrphanedListChild(Node* node) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 79 mergeIdenticalElements(list, nextList); | 79 mergeIdenticalElements(list, nextList); |
| 80 return nextList; | 80 return nextList; |
| 81 } | 81 } |
| 82 return list; | 82 return list; |
| 83 } | 83 } |
| 84 | 84 |
| 85 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
, const QualifiedName& listTag) | 85 bool InsertListCommand::selectionHasListOfType(const VisibleSelection& selection
, const QualifiedName& listTag) |
| 86 { | 86 { |
| 87 VisiblePosition start = selection.visibleStart(); | 87 VisiblePosition start = selection.visibleStart(); |
| 88 | 88 |
| 89 if (!enclosingList(start.deepEquivalent().deprecatedNode().handle().raw())) | 89 if (!enclosingList(start.deepEquivalent().deprecatedNode())) |
| 90 return false; | 90 return false; |
| 91 | 91 |
| 92 VisiblePosition end = startOfParagraph(selection.visibleEnd()); | 92 VisiblePosition end = startOfParagraph(selection.visibleEnd()); |
| 93 while (start.isNotNull() && start != end) { | 93 while (start.isNotNull() && start != end) { |
| 94 HandleScope scope; | 94 HandleScope scope; |
| 95 Handle<Element> listNode = enclosingList(start.deepEquivalent().deprecat
edNode().handle().raw()); | 95 Handle<Element> listNode = enclosingList(start.deepEquivalent().deprecat
edNode()); |
| 96 if (!listNode || !listNode->hasTagName(listTag)) | 96 if (!listNode || !listNode->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(const Handle<Document>& document, Type type
) | 104 InsertListCommand::InsertListCommand(const Handle<Document>& document, Type type
) |
| 105 : CompositeEditCommand(document), m_type(type) | 105 : CompositeEditCommand(document), m_type(type) |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 189 | 189 |
| 190 doApplyForSingleParagraph(false, listTag, endingSelection().firstRange()); | 190 doApplyForSingleParagraph(false, listTag, endingSelection().firstRange()); |
| 191 } | 191 } |
| 192 | 192 |
| 193 void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu
alifiedName& listTag, const Handle<Range>& currentSelection) | 193 void InsertListCommand::doApplyForSingleParagraph(bool forceCreateList, const Qu
alifiedName& listTag, const Handle<Range>& currentSelection) |
| 194 { | 194 { |
| 195 // FIXME: This will produce unexpected results for a selection that starts j
ust before a | 195 // FIXME: This will produce unexpected results for a selection that starts j
ust before a |
| 196 // table and ends inside the first cell, selectionForParagraphIteration shou
ld probably | 196 // table and ends inside the first cell, selectionForParagraphIteration shou
ld probably |
| 197 // be renamed and deployed inside setEndingSelection(). | 197 // be renamed and deployed inside setEndingSelection(). |
| 198 Handle<Node> selectionNode = endingSelection().start().deprecatedNode(); | 198 Handle<Node> selectionNode = endingSelection().start().deprecatedNode(); |
| 199 Node* listChildNode = enclosingListChild(selectionNode.raw()); | 199 Handle<Node> listChildNode = enclosingListChild(selectionNode); |
| 200 bool switchListType = false; | 200 bool switchListType = false; |
| 201 if (listChildNode) { | 201 if (listChildNode) { |
| 202 // Remove the list chlild. | 202 // Remove the list chlild. |
| 203 Handle<HTMLElement> listNode = enclosingList(listChildNode); | 203 Handle<HTMLElement> listNode = enclosingList(listChildNode); |
| 204 if (!listNode) { | 204 if (!listNode) { |
| 205 listNode = fixOrphanedListChild(listChildNode); | 205 listNode = fixOrphanedListChild(listChildNode.raw()); |
| 206 listNode = mergeWithNeighboringLists(listNode); | 206 listNode = mergeWithNeighboringLists(listNode); |
| 207 } | 207 } |
| 208 if (!listNode->hasTagName(listTag)) | 208 if (!listNode->hasTagName(listTag)) |
| 209 // listChildNode will be removed from the list and a list of type m_
type will be created. | 209 // listChildNode will be removed from the list and a list of type m_
type will be created. |
| 210 switchListType = true; | 210 switchListType = true; |
| 211 | 211 |
| 212 // If the list is of the desired type, and we are not removing the list,
then exit early. | 212 // If the list is of the desired type, and we are not removing the list,
then exit early. |
| 213 if (!switchListType && forceCreateList) | 213 if (!switchListType && forceCreateList) |
| 214 return; | 214 return; |
| 215 | 215 |
| 216 // If the entire list is selected, then convert the whole list. | 216 // If the entire list is selected, then convert the whole list. |
| 217 if (switchListType && isNodeVisiblyContainedWithin(listNode.raw(), curre
ntSelection)) { | 217 if (switchListType && isNodeVisiblyContainedWithin(listNode, currentSele
ction)) { |
| 218 bool rangeStartIsInList = visiblePositionBeforeNode(listNode.raw())
== currentSelection->startPosition(); | 218 bool rangeStartIsInList = visiblePositionBeforeNode(listNode) == cur
rentSelection->startPosition(); |
| 219 bool rangeEndIsInList = visiblePositionAfterNode(listNode.raw()) ==
currentSelection->endPosition(); | 219 bool rangeEndIsInList = visiblePositionAfterNode(listNode) == curren
tSelection->endPosition(); |
| 220 | 220 |
| 221 Handle<HTMLElement> newList = createHTMLElement(document(), listTag)
; | 221 Handle<HTMLElement> newList = createHTMLElement(document(), listTag)
; |
| 222 insertNodeBefore(newList, listNode); | 222 insertNodeBefore(newList, listNode); |
| 223 | 223 |
| 224 Handle<Node> firstChildInList = adoptRawResult(enclosingListChild(Vi
siblePosition(firstPositionInNode(listNode)).deepEquivalent().deprecatedNode().h
andle().raw(), listNode.raw())); | 224 Handle<Node> firstChildInList = adoptRawResult(enclosingListChild(Vi
siblePosition(firstPositionInNode(listNode)).deepEquivalent().deprecatedNode().h
andle().raw(), listNode.raw())); |
| 225 Handle<Node> outerBlock = firstChildInList->isBlockFlowElement() ? f
irstChildInList : Handle<Node>(listNode); | 225 Handle<Node> outerBlock = firstChildInList->isBlockFlowElement() ? f
irstChildInList : Handle<Node>(listNode); |
| 226 moveParagraphWithClones(firstPositionInNode(listNode), lastPositionI
nNode(listNode), newList, outerBlock); | 226 moveParagraphWithClones(firstPositionInNode(listNode), lastPositionI
nNode(listNode), newList, outerBlock); |
| 227 | 227 |
| 228 // Manually remove listNode because moveParagraphWithClones sometime
s leaves it behind in the document. | 228 // Manually remove listNode because moveParagraphWithClones sometime
s leaves it behind in the document. |
| 229 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it
em-with-nested-lists.html. | 229 // See the bug 33668 and editing/execCommand/insert-list-orphaned-it
em-with-nested-lists.html. |
| 230 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe
lection. | 230 // FIXME: This might be a bug in moveParagraphWithClones or deleteSe
lection. |
| 231 if (listNode && listNode->inDocument()) | 231 if (listNode && listNode->inDocument()) |
| 232 removeNode(listNode); | 232 removeNode(listNode); |
| 233 | 233 |
| 234 newList = mergeWithNeighboringLists(newList); | 234 newList = mergeWithNeighboringLists(newList); |
| 235 | 235 |
| 236 // Restore the start and the end of current selection if they starte
d inside listNode | 236 // Restore the start and the end of current selection if they starte
d inside listNode |
| 237 // because moveParagraphWithClones could have removed them. | 237 // because moveParagraphWithClones could have removed them. |
| 238 if (rangeStartIsInList && newList) | 238 if (rangeStartIsInList && newList) |
| 239 currentSelection->setStart(newList, 0, IGNORE_EXCEPTION); | 239 currentSelection->setStart(newList, 0, IGNORE_EXCEPTION); |
| 240 if (rangeEndIsInList && newList) | 240 if (rangeEndIsInList && newList) |
| 241 currentSelection->setEnd(newList, lastOffsetInNode(newList), IGN
ORE_EXCEPTION); | 241 currentSelection->setEnd(newList, lastOffsetInNode(newList), IGN
ORE_EXCEPTION); |
| 242 | 242 |
| 243 setEndingSelection(VisiblePosition(firstPositionInNode(newList))); | 243 setEndingSelection(VisiblePosition(firstPositionInNode(newList))); |
| 244 | 244 |
| 245 return; | 245 return; |
| 246 } | 246 } |
| 247 | 247 |
| 248 unlistifyParagraph(endingSelection().visibleStart(), listNode, listChild
Node); | 248 unlistifyParagraph(endingSelection().visibleStart(), listNode, listChild
Node.raw()); |
| 249 } | 249 } |
| 250 | 250 |
| 251 if (!listChildNode || switchListType || forceCreateList) | 251 if (!listChildNode || switchListType || forceCreateList) |
| 252 m_listElement = listifyParagraph(endingSelection().visibleStart(), listT
ag); | 252 m_listElement = listifyParagraph(endingSelection().visibleStart(), listT
ag); |
| 253 } | 253 } |
| 254 | 254 |
| 255 void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
const Handle<HTMLElement>& listNode, Node* listChildNode) | 255 void InsertListCommand::unlistifyParagraph(const VisiblePosition& originalStart,
const Handle<HTMLElement>& listNode, Node* listChildNode) |
| 256 { | 256 { |
| 257 Node* nextListChild; | 257 Node* nextListChild; |
| 258 Node* previousListChild; | 258 Node* previousListChild; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 271 ASSERT(nextListChild != listChildNode); | 271 ASSERT(nextListChild != listChildNode); |
| 272 previousListChild = enclosingListChild(start.previous().deepEquivalent()
.deprecatedNode().handle().raw(), listNode.raw()); | 272 previousListChild = enclosingListChild(start.previous().deepEquivalent()
.deprecatedNode().handle().raw(), listNode.raw()); |
| 273 ASSERT(previousListChild != listChildNode); | 273 ASSERT(previousListChild != listChildNode); |
| 274 } | 274 } |
| 275 // When removing a list, we must always create a placeholder to act as a poi
nt of insertion | 275 // When removing a list, we must always create a placeholder to act as a poi
nt of insertion |
| 276 // for the list content being removed. | 276 // for the list content being removed. |
| 277 Handle<Element> placeholder = createBreakElement(document()); | 277 Handle<Element> placeholder = createBreakElement(document()); |
| 278 Handle<Element> nodeToInsert = placeholder; | 278 Handle<Element> nodeToInsert = placeholder; |
| 279 // If the content of the list item will be moved into another list, put it i
n a list item | 279 // If the content of the list item will be moved into another list, put it i
n a list item |
| 280 // so that we don't create an orphaned list child. | 280 // so that we don't create an orphaned list child. |
| 281 if (enclosingList(listNode.raw())) { | 281 if (enclosingList(listNode)) { |
| 282 nodeToInsert = createListItemElement(document()); | 282 nodeToInsert = createListItemElement(document()); |
| 283 appendNode(placeholder, nodeToInsert); | 283 appendNode(placeholder, nodeToInsert); |
| 284 } | 284 } |
| 285 | 285 |
| 286 if (nextListChild && previousListChild) { | 286 if (nextListChild && previousListChild) { |
| 287 // We want to pull listChildNode out of listNode, and place it before ne
xtListChild | 287 // We want to pull listChildNode out of listNode, and place it before ne
xtListChild |
| 288 // and after previousListChild, so we split listNode and insert it betwe
en the two lists. | 288 // and after previousListChild, so we split listNode and insert it betwe
en the two lists. |
| 289 // But to split listNode, we must first split ancestors of listChildNode
between it and listNode, | 289 // But to split listNode, we must first split ancestors of listChildNode
between it and listNode, |
| 290 // if any exist. | 290 // if any exist. |
| 291 // FIXME: We appear to split at nextListChild as opposed to listChildNod
e so that when we remove | 291 // FIXME: We appear to split at nextListChild as opposed to listChildNod
e so that when we remove |
| (...skipping 11 matching lines...) Expand all Loading... |
| 303 insertNodeBefore(nodeToInsert, listNode); | 303 insertNodeBefore(nodeToInsert, listNode); |
| 304 } else | 304 } else |
| 305 insertNodeAfter(nodeToInsert, listNode); | 305 insertNodeAfter(nodeToInsert, listNode); |
| 306 | 306 |
| 307 VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placehol
der)); | 307 VisiblePosition insertionPoint = VisiblePosition(positionBeforeNode(placehol
der)); |
| 308 moveParagraphs(start, end, insertionPoint, /* preserveSelection */ true, /*
preserveStyle */ true, adoptRawResult(listChildNode)); | 308 moveParagraphs(start, end, insertionPoint, /* preserveSelection */ true, /*
preserveStyle */ true, adoptRawResult(listChildNode)); |
| 309 } | 309 } |
| 310 | 310 |
| 311 static Result<Element> adjacentEnclosingList(const VisiblePosition& pos, const V
isiblePosition& adjacentPos, const QualifiedName& listTag) | 311 static Result<Element> adjacentEnclosingList(const VisiblePosition& pos, const V
isiblePosition& adjacentPos, const QualifiedName& listTag) |
| 312 { | 312 { |
| 313 Handle<Element> listNode = outermostEnclosingList(adjacentPos.deepEquivalent
().deprecatedNode().handle().raw()); | 313 Handle<Element> listNode = outermostEnclosingList(adjacentPos.deepEquivalent
().deprecatedNode()); |
| 314 if (!listNode) | 314 if (!listNode) |
| 315 return nullptr; | 315 return nullptr; |
| 316 | 316 |
| 317 Node* previousCell = enclosingTableCell(pos.deepEquivalent()); | 317 Handle<Node> previousCell = enclosingTableCell(pos.deepEquivalent()); |
| 318 Node* currentCell = enclosingTableCell(adjacentPos.deepEquivalent()); | 318 Handle<Node> currentCell = enclosingTableCell(adjacentPos.deepEquivalent()); |
| 319 | 319 |
| 320 if (!listNode->hasTagName(listTag) | 320 if (!listNode->hasTagName(listTag) |
| 321 || listNode->contains(pos.deepEquivalent().deprecatedNode()) | 321 || listNode->contains(pos.deepEquivalent().deprecatedNode()) |
| 322 || previousCell != currentCell | 322 || previousCell != currentCell |
| 323 || enclosingList(listNode.raw()) != enclosingList(pos.deepEquivalent().d
eprecatedNode().handle().raw())) | 323 || enclosingList(listNode) != enclosingList(pos.deepEquivalent().depreca
tedNode())) |
| 324 return nullptr; | 324 return nullptr; |
| 325 | 325 |
| 326 return listNode; | 326 return listNode; |
| 327 } | 327 } |
| 328 | 328 |
| 329 Result<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& o
riginalStart, const QualifiedName& listTag) | 329 Result<HTMLElement> InsertListCommand::listifyParagraph(const VisiblePosition& o
riginalStart, const QualifiedName& listTag) |
| 330 { | 330 { |
| 331 VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBo
undary); | 331 VisiblePosition start = startOfParagraph(originalStart, CanSkipOverEditingBo
undary); |
| 332 VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary); | 332 VisiblePosition end = endOfParagraph(start, CanSkipOverEditingBoundary); |
| 333 | 333 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 345 Handle<HTMLElement> listElement; | 345 Handle<HTMLElement> listElement; |
| 346 if (previousList) | 346 if (previousList) |
| 347 appendNode(listItemElement, previousList); | 347 appendNode(listItemElement, previousList); |
| 348 else if (nextList) | 348 else if (nextList) |
| 349 insertNodeAt(listItemElement, positionBeforeNode(nextList)); | 349 insertNodeAt(listItemElement, positionBeforeNode(nextList)); |
| 350 else { | 350 else { |
| 351 // Create the list. | 351 // Create the list. |
| 352 listElement = createHTMLElement(document(), listTag); | 352 listElement = createHTMLElement(document(), listTag); |
| 353 appendNode(listItemElement, listElement); | 353 appendNode(listItemElement, listElement); |
| 354 | 354 |
| 355 if (start == end && isBlock(start.deepEquivalent().deprecatedNode().hand
le().raw())) { | 355 if (start == end && isBlock(start.deepEquivalent().deprecatedNode())) { |
| 356 // Inserting the list into an empty paragraph that isn't held open | 356 // Inserting the list into an empty paragraph that isn't held open |
| 357 // by a br or a '\n', will invalidate start and end. Insert | 357 // by a br or a '\n', will invalidate start and end. Insert |
| 358 // a placeholder and then recompute start and end. | 358 // a placeholder and then recompute start and end. |
| 359 Handle<Node> placeholder = insertBlockPlaceholder(start.deepEquivale
nt()); | 359 Handle<Node> placeholder = insertBlockPlaceholder(start.deepEquivale
nt()); |
| 360 start = positionBeforeNode(placeholder); | 360 start = positionBeforeNode(placeholder); |
| 361 end = start; | 361 end = start; |
| 362 } | 362 } |
| 363 | 363 |
| 364 // Insert the list at a position visually equivalent to start of the | 364 // Insert the list at a position visually equivalent to start of the |
| 365 // paragraph that is being moved into the list. | 365 // paragraph that is being moved into the list. |
| 366 // Try to avoid inserting it somewhere where it will be surrounded by | 366 // Try to avoid inserting it somewhere where it will be surrounded by |
| 367 // inline ancestors of start, since it is easier for editing to produce | 367 // inline ancestors of start, since it is easier for editing to produce |
| 368 // clean markup when inline elements are pushed down as far as possible. | 368 // clean markup when inline elements are pushed down as far as possible. |
| 369 Position insertionPos(start.deepEquivalent().upstream()); | 369 Position insertionPos(start.deepEquivalent().upstream()); |
| 370 // Also avoid the containing list item. | 370 // Also avoid the containing list item. |
| 371 Handle<Node> listChild = adoptRawResult(enclosingListChild(insertionPos.
deprecatedNode().handle().raw())); | 371 Handle<Node> listChild = enclosingListChild(insertionPos.deprecatedNode(
)); |
| 372 if (listChild && listChild->hasTagName(liTag)) | 372 if (listChild && listChild->hasTagName(liTag)) |
| 373 insertionPos = positionInParentBeforeNode(listChild); | 373 insertionPos = positionInParentBeforeNode(listChild); |
| 374 | 374 |
| 375 insertNodeAt(listElement, insertionPos); | 375 insertNodeAt(listElement, insertionPos); |
| 376 | 376 |
| 377 // We inserted the list at the start of the content we're about to move | 377 // We inserted the list at the start of the content we're about to move |
| 378 // Update the start of content, so we don't try to move the list into it
self. bug 19066 | 378 // Update the start of content, so we don't try to move the list into it
self. bug 19066 |
| 379 // Layout is necessary since start's node's inline renderers may have be
en destroyed by the insertion | 379 // Layout is necessary since start's node's inline renderers may have be
en destroyed by the insertion |
| 380 // The end of the content may have changed after the insertion and layou
t so update it as well. | 380 // The end of the content may have changed after the insertion and layou
t so update it as well. |
| 381 if (insertionPos == start.deepEquivalent()) { | 381 if (insertionPos == start.deepEquivalent()) { |
| 382 listElement->document()->updateLayoutIgnorePendingStylesheets(); | 382 listElement->document()->updateLayoutIgnorePendingStylesheets(); |
| 383 start = startOfParagraph(originalStart, CanSkipOverEditingBoundary); | 383 start = startOfParagraph(originalStart, CanSkipOverEditingBoundary); |
| 384 end = endOfParagraph(start, CanSkipOverEditingBoundary); | 384 end = endOfParagraph(start, CanSkipOverEditingBoundary); |
| 385 } | 385 } |
| 386 } | 386 } |
| 387 | 387 |
| 388 moveParagraph(start, end, positionBeforeNode(placeholder), true); | 388 moveParagraph(start, end, positionBeforeNode(placeholder), true); |
| 389 | 389 |
| 390 if (listElement) | 390 if (listElement) |
| 391 return mergeWithNeighboringLists(listElement); | 391 return mergeWithNeighboringLists(listElement); |
| 392 | 392 |
| 393 if (canMergeLists(previousList, nextList)) | 393 if (canMergeLists(previousList, nextList)) |
| 394 mergeIdenticalElements(previousList, nextList); | 394 mergeIdenticalElements(previousList, nextList); |
| 395 | 395 |
| 396 return listElement; | 396 return listElement; |
| 397 } | 397 } |
| 398 | 398 |
| 399 } | 399 } |
| OLD | NEW |