| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. | 2 * Copyright (C) 2005 Apple Computer, 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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) | 76 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) |
| 77 , m_needPlaceholder(false) | 77 , m_needPlaceholder(false) |
| 78 , m_replace(replace) | 78 , m_replace(replace) |
| 79 , m_expandForSpecialElements(expandForSpecialElements) | 79 , m_expandForSpecialElements(expandForSpecialElements) |
| 80 , m_pruneStartBlockIfNecessary(false) | 80 , m_pruneStartBlockIfNecessary(false) |
| 81 , m_startsAtEmptyLine(false) | 81 , m_startsAtEmptyLine(false) |
| 82 , m_sanitizeMarkup(sanitizeMarkup) | 82 , m_sanitizeMarkup(sanitizeMarkup) |
| 83 , m_startBlock(0) | 83 , m_startBlock(0) |
| 84 , m_endBlock(0) | 84 , m_endBlock(0) |
| 85 , m_typingStyle(0) | 85 , m_typingStyle(0) |
| 86 , m_deleteIntoBlockquoteStyle(0) | |
| 87 { | 86 { |
| 88 } | 87 } |
| 89 | 88 |
| 90 DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection
, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpe
cialElements, bool sanitizeMarkup) | 89 DeleteSelectionCommand::DeleteSelectionCommand(const VisibleSelection& selection
, bool smartDelete, bool mergeBlocksAfterDelete, bool replace, bool expandForSpe
cialElements, bool sanitizeMarkup) |
| 91 : CompositeEditCommand(selection.start().anchorNode()->document()) | 90 : CompositeEditCommand(selection.start().anchorNode()->document()) |
| 92 , m_hasSelectionToDelete(true) | 91 , m_hasSelectionToDelete(true) |
| 93 , m_smartDelete(smartDelete) | 92 , m_smartDelete(smartDelete) |
| 94 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) | 93 , m_mergeBlocksAfterDelete(mergeBlocksAfterDelete) |
| 95 , m_needPlaceholder(false) | 94 , m_needPlaceholder(false) |
| 96 , m_replace(replace) | 95 , m_replace(replace) |
| 97 , m_expandForSpecialElements(expandForSpecialElements) | 96 , m_expandForSpecialElements(expandForSpecialElements) |
| 98 , m_pruneStartBlockIfNecessary(false) | 97 , m_pruneStartBlockIfNecessary(false) |
| 99 , m_startsAtEmptyLine(false) | 98 , m_startsAtEmptyLine(false) |
| 100 , m_sanitizeMarkup(sanitizeMarkup) | 99 , m_sanitizeMarkup(sanitizeMarkup) |
| 101 , m_selectionToDelete(selection) | 100 , m_selectionToDelete(selection) |
| 102 , m_startBlock(0) | 101 , m_startBlock(0) |
| 103 , m_endBlock(0) | 102 , m_endBlock(0) |
| 104 , m_typingStyle(0) | 103 , m_typingStyle(0) |
| 105 , m_deleteIntoBlockquoteStyle(0) | |
| 106 { | 104 { |
| 107 } | 105 } |
| 108 | 106 |
| 109 void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end) | 107 void DeleteSelectionCommand::initializeStartEnd(Position& start, Position& end) |
| 110 { | 108 { |
| 111 Node* startSpecialContainer = 0; | 109 Node* startSpecialContainer = 0; |
| 112 Node* endSpecialContainer = 0; | 110 Node* endSpecialContainer = 0; |
| 113 | 111 |
| 114 start = m_selectionToDelete.start(); | 112 start = m_selectionToDelete.start(); |
| 115 end = m_selectionToDelete.end(); | 113 end = m_selectionToDelete.end(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 | 200 |
| 203 // Usually the start and the end of the selection to delete are pulled toget
her as a result of the deletion. | 201 // Usually the start and the end of the selection to delete are pulled toget
her as a result of the deletion. |
| 204 // Sometimes they aren't (like when no merge is requested), so we must choos
e one position to hold the caret | 202 // Sometimes they aren't (like when no merge is requested), so we must choos
e one position to hold the caret |
| 205 // and receive the placeholder after deletion. | 203 // and receive the placeholder after deletion. |
| 206 VisiblePosition visibleEnd(m_downstreamEnd); | 204 VisiblePosition visibleEnd(m_downstreamEnd); |
| 207 if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd)) | 205 if (m_mergeBlocksAfterDelete && !isEndOfParagraph(visibleEnd)) |
| 208 m_endingPosition = m_downstreamEnd; | 206 m_endingPosition = m_downstreamEnd; |
| 209 else | 207 else |
| 210 m_endingPosition = m_downstreamStart; | 208 m_endingPosition = m_downstreamStart; |
| 211 | 209 |
| 212 // We don't want to merge into a block if it will mean changing the quote le
vel of content after deleting | |
| 213 // selections that contain a whole number paragraphs plus a line break, sinc
e it is unclear to most users | |
| 214 // that such a selection actually ends at the start of the next paragraph. T
his matches TextEdit behavior | |
| 215 // for indented paragraphs. | |
| 216 // Only apply this rule if the endingSelection is a range selection. If it
is a caret, then other operations have created | |
| 217 // the selection we're deleting (like the process of creating a selection to
delete during a backspace), and the user isn't in the situation described above
. | |
| 218 if (numEnclosingMailBlockquotes(start) != numEnclosingMailBlockquotes(end) | |
| 219 && isStartOfParagraph(visibleEnd) && isStartOfParagraph(VisiblePosit
ion(start)) | |
| 220 && endingSelection().isRange()) { | |
| 221 m_mergeBlocksAfterDelete = false; | |
| 222 m_pruneStartBlockIfNecessary = true; | |
| 223 } | |
| 224 | |
| 225 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection | 210 // Handle leading and trailing whitespace, as well as smart delete adjustmen
ts to the selection |
| 226 m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(m_selectionT
oDelete.affinity()); | 211 m_leadingWhitespace = m_upstreamStart.leadingWhitespacePosition(m_selectionT
oDelete.affinity()); |
| 227 m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT
_AFFINITY); | 212 m_trailingWhitespace = m_downstreamEnd.trailingWhitespacePosition(VP_DEFAULT
_AFFINITY); |
| 228 | 213 |
| 229 if (m_smartDelete) { | 214 if (m_smartDelete) { |
| 230 | 215 |
| 231 // skip smart delete if the selection to delete already starts or ends w
ith whitespace | 216 // skip smart delete if the selection to delete already starts or ends w
ith whitespace |
| 232 Position pos = VisiblePosition(m_upstreamStart, m_selectionToDelete.affi
nity()).deepEquivalent(); | 217 Position pos = VisiblePosition(m_upstreamStart, m_selectionToDelete.affi
nity()).deepEquivalent(); |
| 233 bool skipSmartDelete = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINIT
Y, true).isNotNull(); | 218 bool skipSmartDelete = pos.trailingWhitespacePosition(VP_DEFAULT_AFFINIT
Y, true).isNotNull(); |
| 234 if (!skipSmartDelete) | 219 if (!skipSmartDelete) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 // two positions will be identical). Therefore there is no need to save the | 265 // two positions will be identical). Therefore there is no need to save the |
| 281 // typing style at the start of the selection, nor is there a reason to | 266 // typing style at the start of the selection, nor is there a reason to |
| 282 // compute the style at the start of the selection after deletion (see the | 267 // compute the style at the start of the selection after deletion (see the |
| 283 // early return in calculateTypingStyleAfterDelete). | 268 // early return in calculateTypingStyleAfterDelete). |
| 284 if (m_upstreamStart.deprecatedNode() == m_downstreamEnd.deprecatedNode() &&
m_upstreamStart.deprecatedNode()->isTextNode()) | 269 if (m_upstreamStart.deprecatedNode() == m_downstreamEnd.deprecatedNode() &&
m_upstreamStart.deprecatedNode()->isTextNode()) |
| 285 return; | 270 return; |
| 286 | 271 |
| 287 // Figure out the typing style in effect before the delete is done. | 272 // Figure out the typing style in effect before the delete is done. |
| 288 m_typingStyle = EditingStyle::create(m_selectionToDelete.start()); | 273 m_typingStyle = EditingStyle::create(m_selectionToDelete.start()); |
| 289 m_typingStyle->removeStyleAddedByNode(enclosingAnchorElement(m_selectionToDe
lete.start())); | 274 m_typingStyle->removeStyleAddedByNode(enclosingAnchorElement(m_selectionToDe
lete.start())); |
| 290 | |
| 291 // If we're deleting into a Mail blockquote, save the style at end() instead
of start() | |
| 292 // We'll use this later in computeTypingStyleAfterDelete if we end up outsid
e of a Mail blockquote | |
| 293 if (enclosingNodeOfType(m_selectionToDelete.start(), isMailBlockquote)) | |
| 294 m_deleteIntoBlockquoteStyle = EditingStyle::create(m_selectionToDelete.e
nd()); | |
| 295 else | |
| 296 m_deleteIntoBlockquoteStyle = 0; | |
| 297 } | 275 } |
| 298 | 276 |
| 299 bool DeleteSelectionCommand::handleSpecialCaseBRDelete() | 277 bool DeleteSelectionCommand::handleSpecialCaseBRDelete() |
| 300 { | 278 { |
| 301 Node* nodeAfterUpstreamStart = m_upstreamStart.computeNodeAfterPosition(); | 279 Node* nodeAfterUpstreamStart = m_upstreamStart.computeNodeAfterPosition(); |
| 302 Node* nodeAfterDownstreamStart = m_downstreamStart.computeNodeAfterPosition(
); | 280 Node* nodeAfterDownstreamStart = m_downstreamStart.computeNodeAfterPosition(
); |
| 303 // Upstream end will appear before BR due to canonicalization | 281 // Upstream end will appear before BR due to canonicalization |
| 304 Node* nodeAfterUpstreamEnd = m_upstreamEnd.computeNodeAfterPosition(); | 282 Node* nodeAfterUpstreamEnd = m_upstreamEnd.computeNodeAfterPosition(); |
| 305 | 283 |
| 306 if (!nodeAfterUpstreamStart || !nodeAfterDownstreamStart) | 284 if (!nodeAfterUpstreamStart || !nodeAfterDownstreamStart) |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 702 { | 680 { |
| 703 if (!m_typingStyle) | 681 if (!m_typingStyle) |
| 704 return; | 682 return; |
| 705 | 683 |
| 706 // Compute the difference between the style before the delete and the style
now | 684 // Compute the difference between the style before the delete and the style
now |
| 707 // after the delete has been done. Set this style on the frame, so other edi
ting | 685 // after the delete has been done. Set this style on the frame, so other edi
ting |
| 708 // commands being composed with this one will work, and also cache it on the
command, | 686 // commands being composed with this one will work, and also cache it on the
command, |
| 709 // so the Frame::appliedEditing can set it after the whole composite command
| 687 // so the Frame::appliedEditing can set it after the whole composite command
|
| 710 // has completed. | 688 // has completed. |
| 711 | 689 |
| 712 // If we deleted into a blockquote, but are now no longer in a blockquote, u
se the alternate typing style | |
| 713 if (m_deleteIntoBlockquoteStyle && !enclosingNodeOfType(m_endingPosition, is
MailBlockquote, CanCrossEditingBoundary)) | |
| 714 m_typingStyle = m_deleteIntoBlockquoteStyle; | |
| 715 m_deleteIntoBlockquoteStyle = 0; | |
| 716 | |
| 717 m_typingStyle->prepareToApplyAt(m_endingPosition); | 690 m_typingStyle->prepareToApplyAt(m_endingPosition); |
| 718 if (m_typingStyle->isEmpty()) | 691 if (m_typingStyle->isEmpty()) |
| 719 m_typingStyle = 0; | 692 m_typingStyle = 0; |
| 720 // This is where we've deleted all traces of a style but not a whole paragra
ph (that's handled above). | 693 // This is where we've deleted all traces of a style but not a whole paragra
ph (that's handled above). |
| 721 // In this case if we start typing, the new characters should have the same
style as the just deleted ones, | 694 // In this case if we start typing, the new characters should have the same
style as the just deleted ones, |
| 722 // but, if we change the selection, come back and start typing that style sh
ould be lost. Also see | 695 // but, if we change the selection, come back and start typing that style sh
ould be lost. Also see |
| 723 // preserveTypingStyle() below. | 696 // preserveTypingStyle() below. |
| 724 document()->frame()->selection()->setTypingStyle(m_typingStyle); | 697 document()->frame()->selection()->setTypingStyle(m_typingStyle); |
| 725 } | 698 } |
| 726 | 699 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 871 | 844 |
| 872 // Normally deletion doesn't preserve the typing style that was present before i
t. For example, | 845 // Normally deletion doesn't preserve the typing style that was present before i
t. For example, |
| 873 // type a character, Bold, then delete the character and start typing. The Bold
typing style shouldn't | 846 // type a character, Bold, then delete the character and start typing. The Bold
typing style shouldn't |
| 874 // stick around. Deletion should preserve a typing style that *it* sets, howeve
r. | 847 // stick around. Deletion should preserve a typing style that *it* sets, howeve
r. |
| 875 bool DeleteSelectionCommand::preservesTypingStyle() const | 848 bool DeleteSelectionCommand::preservesTypingStyle() const |
| 876 { | 849 { |
| 877 return m_typingStyle; | 850 return m_typingStyle; |
| 878 } | 851 } |
| 879 | 852 |
| 880 } // namespace WebCore | 853 } // namespace WebCore |
| OLD | NEW |