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 |