2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "AtomicString.h"
30 #include "CSSPropertyNames.h"
31 #include "CreateLinkCommand.h"
32 #include "DocumentFragment.h"
34 #include "EditorClient.h"
36 #include "EventHandler.h"
38 #include "FormatBlockCommand.h"
39 #include "HTMLFontElement.h"
40 #include "HTMLImageElement.h"
41 #include "IndentOutdentCommand.h"
42 #include "InsertListCommand.h"
44 #include "ReplaceSelectionCommand.h"
45 #include "Scrollbar.h"
48 #include "TypingCommand.h"
49 #include "UnlinkCommand.h"
50 #include "htmlediting.h"
55 using namespace HTMLNames
;
57 class EditorInternalCommand
{
59 bool (*execute
)(Frame
*, Event
*, EditorCommandSource
, const String
&);
60 bool (*isSupported
)(Frame
*, EditorCommandSource
);
61 bool (*isEnabled
)(Frame
*, Event
*, EditorCommandSource
);
62 TriState (*state
)(Frame
*, Event
*);
63 String (*value
)(Frame
*, Event
*);
65 bool allowExecutionWhenDisabled
;
68 typedef HashMap
<String
, const EditorInternalCommand
*, CaseFoldingHash
> CommandMap
;
70 static const bool notTextInsertion
= false;
71 static const bool isTextInsertion
= true;
73 static const bool allowExecutionWhenDisabled
= true;
74 static const bool doNotAllowExecutionWhenDisabled
= false;
76 // Related to Editor::selectionForCommand.
77 // Certain operations continue to use the target control's selection even if the event handler
78 // already moved the selection outside of the text control.
79 static Frame
* targetFrame(Frame
* frame
, Event
* event
)
83 Node
* node
= event
->target()->toNode();
86 return node
->document()->frame();
89 static bool executeApplyStyle(Frame
* frame
, EditorCommandSource source
, EditAction action
, int propertyID
, const String
& propertyValue
)
91 RefPtr
<CSSMutableStyleDeclaration
> style
= CSSMutableStyleDeclaration::create();
92 style
->setProperty(propertyID
, propertyValue
);
93 // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
95 case CommandFromMenuOrKeyBinding
:
96 frame
->editor()->applyStyleToSelection(style
.get(), action
);
99 case CommandFromDOMWithUserInterface
:
100 frame
->editor()->applyStyle(style
.get());
103 ASSERT_NOT_REACHED();
107 static bool executeApplyStyle(Frame
* frame
, EditorCommandSource source
, EditAction action
, int propertyID
, const char* propertyValue
)
109 return executeApplyStyle(frame
, source
, action
, propertyID
, String(propertyValue
));
112 static bool executeApplyStyle(Frame
* frame
, EditorCommandSource source
, EditAction action
, int propertyID
, int propertyValue
)
114 RefPtr
<CSSMutableStyleDeclaration
> style
= CSSMutableStyleDeclaration::create();
115 style
->setProperty(propertyID
, propertyValue
);
116 // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
118 case CommandFromMenuOrKeyBinding
:
119 frame
->editor()->applyStyleToSelection(style
.get(), action
);
122 case CommandFromDOMWithUserInterface
:
123 frame
->editor()->applyStyle(style
.get());
126 ASSERT_NOT_REACHED();
130 static bool executeToggleStyle(Frame
* frame
, EditorCommandSource source
, EditAction action
, int propertyID
, const char* offValue
, const char* onValue
)
132 RefPtr
<CSSMutableStyleDeclaration
> style
= CSSMutableStyleDeclaration::create();
133 style
->setProperty(propertyID
, onValue
);
134 style
->setProperty(propertyID
, frame
->editor()->selectionStartHasStyle(style
.get()) ? offValue
: onValue
);
135 // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
137 case CommandFromMenuOrKeyBinding
:
138 frame
->editor()->applyStyleToSelection(style
.get(), action
);
141 case CommandFromDOMWithUserInterface
:
142 frame
->editor()->applyStyle(style
.get());
145 ASSERT_NOT_REACHED();
149 static bool executeApplyParagraphStyle(Frame
* frame
, EditorCommandSource source
, EditAction action
, int propertyID
, const String
& propertyValue
)
151 RefPtr
<CSSMutableStyleDeclaration
> style
= CSSMutableStyleDeclaration::create();
152 style
->setProperty(propertyID
, propertyValue
);
153 // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
155 case CommandFromMenuOrKeyBinding
:
156 frame
->editor()->applyParagraphStyleToSelection(style
.get(), action
);
159 case CommandFromDOMWithUserInterface
:
160 frame
->editor()->applyParagraphStyle(style
.get());
163 ASSERT_NOT_REACHED();
167 static bool executeInsertFragment(Frame
* frame
, PassRefPtr
<DocumentFragment
> fragment
)
169 applyCommand(ReplaceSelectionCommand::create(frame
->document(), fragment
,
170 false, false, false, true, false, EditActionUnspecified
));
174 static bool executeInsertNode(Frame
* frame
, PassRefPtr
<Node
> content
)
176 RefPtr
<DocumentFragment
> fragment
= new DocumentFragment(frame
->document());
177 ExceptionCode ec
= 0;
178 fragment
->appendChild(content
, ec
);
181 return executeInsertFragment(frame
, fragment
.release());
184 static bool expandSelectionToGranularity(Frame
* frame
, TextGranularity granularity
)
186 Selection selection
= frame
->selection()->selection();
187 selection
.expandUsingGranularity(granularity
);
188 RefPtr
<Range
> newRange
= selection
.toRange();
191 ExceptionCode ec
= 0;
192 if (newRange
->collapsed(ec
))
194 RefPtr
<Range
> oldRange
= frame
->selection()->selection().toRange();
195 EAffinity affinity
= frame
->selection()->affinity();
196 if (!frame
->editor()->client()->shouldChangeSelectedRange(oldRange
.get(), newRange
.get(), affinity
, false))
198 frame
->selection()->setSelectedRange(newRange
.get(), affinity
, true);
202 static TriState
stateStyle(Frame
* frame
, int propertyID
, const char* desiredValue
)
204 RefPtr
<CSSMutableStyleDeclaration
> style
= CSSMutableStyleDeclaration::create();
205 style
->setProperty(propertyID
, desiredValue
);
206 return frame
->editor()->selectionHasStyle(style
.get());
209 static String
valueStyle(Frame
* frame
, int propertyID
)
211 return frame
->selectionStartStylePropertyValue(propertyID
);
214 static int verticalScrollDistance(Frame
* frame
)
216 Node
* focusedNode
= frame
->document()->focusedNode();
219 RenderObject
* renderer
= focusedNode
->renderer();
222 RenderStyle
* style
= renderer
->style();
225 if (!(style
->overflowY() == OSCROLL
|| style
->overflowY() == OAUTO
|| renderer
->isTextArea()))
227 int height
= renderer
->clientHeight();
228 return max((height
+ 1) / 2, height
- cAmountToKeepWhenPaging
);
231 static RefPtr
<Range
> unionDOMRanges(Range
* a
, Range
* b
)
233 ExceptionCode ec
= 0;
234 Range
* start
= a
->compareBoundaryPoints(Range::START_TO_START
, b
, ec
) <= 0 ? a
: b
;
236 Range
* end
= a
->compareBoundaryPoints(Range::END_TO_END
, b
, ec
) <= 0 ? b
: a
;
239 return Range::create(a
->startContainer(ec
)->ownerDocument(), start
->startContainer(ec
), start
->startOffset(ec
), end
->endContainer(ec
), end
->endOffset(ec
));
242 // Execute command functions
244 static bool executeBackColor(Frame
* frame
, Event
*, EditorCommandSource source
, const String
& value
)
246 return executeApplyStyle(frame
, source
, EditActionSetBackgroundColor
, CSSPropertyBackgroundColor
, value
);
249 static bool executeCopy(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
251 frame
->editor()->copy();
255 static bool executeCreateLink(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
257 // FIXME: If userInterface is true, we should display a dialog box to let the user enter a URL.
260 applyCommand(CreateLinkCommand::create(frame
->document(), value
));
264 static bool executeCut(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
266 frame
->editor()->cut();
270 static bool executeDelete(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
273 case CommandFromMenuOrKeyBinding
:
274 // Doesn't modify the text if the current selection isn't a range.
275 frame
->editor()->performDelete();
278 case CommandFromDOMWithUserInterface
:
279 // If the current selection is a caret, delete the preceding character. IE performs forwardDelete, but we currently side with Firefox.
280 // Doesn't scroll to make the selection visible, or modify the kill ring (this time, siding with IE, not Firefox).
281 TypingCommand::deleteKeyPressed(frame
->document(), frame
->selectionGranularity() == WordGranularity
);
284 ASSERT_NOT_REACHED();
288 static bool executeDeleteBackward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
290 frame
->editor()->deleteWithDirection(SelectionController::BACKWARD
, CharacterGranularity
, false, true);
294 static bool executeDeleteBackwardByDecomposingPreviousCharacter(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
296 LOG_ERROR("DeleteBackwardByDecomposingPreviousCharacter is not implemented, doing DeleteBackward instead");
297 frame
->editor()->deleteWithDirection(SelectionController::BACKWARD
, CharacterGranularity
, false, true);
301 static bool executeDeleteForward(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
303 frame
->editor()->deleteWithDirection(SelectionController::FORWARD
, CharacterGranularity
, false, true);
307 static bool executeDeleteToBeginningOfLine(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
309 frame
->editor()->deleteWithDirection(SelectionController::BACKWARD
, LineBoundary
, true, false);
313 static bool executeDeleteToBeginningOfParagraph(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
315 frame
->editor()->deleteWithDirection(SelectionController::BACKWARD
, ParagraphBoundary
, true, false);
319 static bool executeDeleteToEndOfLine(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
321 // Despite its name, this command should delete the newline at the end of
322 // a paragraph if you are at the end of a paragraph (like DeleteToEndOfParagraph).
323 frame
->editor()->deleteWithDirection(SelectionController::FORWARD
, LineBoundary
, true, false);
327 static bool executeDeleteToEndOfParagraph(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
329 // Despite its name, this command should delete the newline at the end of
330 // a paragraph if you are at the end of a paragraph.
331 frame
->editor()->deleteWithDirection(SelectionController::FORWARD
, ParagraphBoundary
, true, false);
335 static bool executeDeleteToMark(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
337 RefPtr
<Range
> mark
= frame
->mark().toRange();
339 SelectionController
* selection
= frame
->selection();
340 bool selected
= selection
->setSelectedRange(unionDOMRanges(mark
.get(), frame
->editor()->selectedRange().get()).get(), DOWNSTREAM
, true);
345 frame
->editor()->performDelete();
346 frame
->setMark(frame
->selection()->selection());
350 static bool executeDeleteWordBackward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
352 frame
->editor()->deleteWithDirection(SelectionController::BACKWARD
, WordGranularity
, true, false);
356 static bool executeDeleteWordForward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
358 frame
->editor()->deleteWithDirection(SelectionController::FORWARD
, WordGranularity
, true, false);
362 static bool executeFindString(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
364 return frame
->findString(value
, true, false, true, false);
367 static bool executeFontName(Frame
* frame
, Event
*, EditorCommandSource source
, const String
& value
)
369 return executeApplyStyle(frame
, source
, EditActionSetFont
, CSSPropertyFontFamily
, value
);
372 static bool executeFontSize(Frame
* frame
, Event
*, EditorCommandSource source
, const String
& value
)
375 if (!HTMLFontElement::cssValueFromFontSizeNumber(value
, size
))
377 return executeApplyStyle(frame
, source
, EditActionChangeAttributes
, CSSPropertyFontSize
, size
);
380 static bool executeFontSizeDelta(Frame
* frame
, Event
*, EditorCommandSource source
, const String
& value
)
382 return executeApplyStyle(frame
, source
, EditActionChangeAttributes
, CSSPropertyWebkitFontSizeDelta
, value
);
385 static bool executeForeColor(Frame
* frame
, Event
*, EditorCommandSource source
, const String
& value
)
387 return executeApplyStyle(frame
, source
, EditActionSetColor
, CSSPropertyColor
, value
);
390 static bool executeFormatBlock(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
392 String tagName
= value
.lower();
393 if (tagName
[0] == '<' && tagName
[tagName
.length() - 1] == '>')
394 tagName
= tagName
.substring(1, tagName
.length() - 2);
395 if (!validBlockTag(tagName
))
397 applyCommand(FormatBlockCommand::create(frame
->document(), tagName
));
401 static bool executeForwardDelete(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
404 case CommandFromMenuOrKeyBinding
:
405 frame
->editor()->deleteWithDirection(SelectionController::FORWARD
, CharacterGranularity
, false, true);
408 case CommandFromDOMWithUserInterface
:
409 // Doesn't scroll to make the selection visible, or modify the kill ring.
410 // ForwardDelete is not implemented in IE or Firefox, so this behavior is only needed for
411 // backward compatibility with ourselves, and for consistency with Delete.
412 TypingCommand::forwardDeleteKeyPressed(frame
->document());
415 ASSERT_NOT_REACHED();
419 static bool executeIgnoreSpelling(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
421 frame
->editor()->ignoreSpelling();
425 static bool executeIndent(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
427 applyCommand(IndentOutdentCommand::create(frame
->document(), IndentOutdentCommand::Indent
));
431 static bool executeInsertBacktab(Frame
* frame
, Event
* event
, EditorCommandSource
, const String
&)
433 return targetFrame(frame
, event
)->eventHandler()->handleTextInputEvent("\t", event
, false, true);
436 static bool executeInsertHorizontalRule(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
438 RefPtr
<HTMLElement
> hr
= new HTMLElement(hrTag
, frame
->document());
439 if (!value
.isEmpty())
441 return executeInsertNode(frame
, hr
.release());
444 static bool executeInsertHTML(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
446 return executeInsertFragment(frame
, createFragmentFromMarkup(frame
->document(), value
, ""));
449 static bool executeInsertImage(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
451 // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
452 RefPtr
<HTMLImageElement
> image
= new HTMLImageElement(imgTag
, frame
->document());
453 image
->setSrc(value
);
454 return executeInsertNode(frame
, image
.release());
457 static bool executeInsertLineBreak(Frame
* frame
, Event
* event
, EditorCommandSource source
, const String
&)
460 case CommandFromMenuOrKeyBinding
:
461 return targetFrame(frame
, event
)->eventHandler()->handleTextInputEvent("\n", event
, true);
463 case CommandFromDOMWithUserInterface
:
464 // Doesn't scroll to make the selection visible, or modify the kill ring.
465 // InsertLineBreak is not implemented in IE or Firefox, so this behavior is only needed for
466 // backward compatibility with ourselves, and for consistency with other commands.
467 TypingCommand::insertLineBreak(frame
->document());
470 ASSERT_NOT_REACHED();
474 static bool executeInsertNewline(Frame
* frame
, Event
* event
, EditorCommandSource
, const String
&)
476 Frame
* targetFrame
= WebCore::targetFrame(frame
, event
);
477 return targetFrame
->eventHandler()->handleTextInputEvent("\n", event
, !targetFrame
->editor()->canEditRichly());
480 static bool executeInsertNewlineInQuotedContent(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
482 TypingCommand::insertParagraphSeparatorInQuotedContent(frame
->document());
486 static bool executeInsertOrderedList(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
488 applyCommand(InsertListCommand::create(frame
->document(), InsertListCommand::OrderedList
, value
));
492 static bool executeInsertParagraph(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
494 TypingCommand::insertParagraphSeparator(frame
->document());
498 static bool executeInsertTab(Frame
* frame
, Event
* event
, EditorCommandSource
, const String
&)
500 return targetFrame(frame
, event
)->eventHandler()->handleTextInputEvent("\t", event
, false, false);
503 static bool executeInsertText(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
505 TypingCommand::insertText(frame
->document(), value
);
509 static bool executeInsertUnorderedList(Frame
* frame
, Event
*, EditorCommandSource
, const String
& value
)
511 applyCommand(InsertListCommand::create(frame
->document(), InsertListCommand::UnorderedList
, value
));
515 static bool executeJustifyCenter(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
517 return executeApplyParagraphStyle(frame
, source
, EditActionCenter
, CSSPropertyTextAlign
, "center");
520 static bool executeJustifyFull(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
522 return executeApplyParagraphStyle(frame
, source
, EditActionJustify
, CSSPropertyTextAlign
, "justify");
525 static bool executeJustifyLeft(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
527 return executeApplyParagraphStyle(frame
, source
, EditActionAlignLeft
, CSSPropertyTextAlign
, "left");
530 static bool executeJustifyRight(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
532 return executeApplyParagraphStyle(frame
, source
, EditActionAlignRight
, CSSPropertyTextAlign
, "right");
535 static bool executeMoveBackward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
537 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, CharacterGranularity
, true);
541 static bool executeMoveBackwardAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
543 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, CharacterGranularity
, true);
547 static bool executeMoveDown(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
549 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, LineGranularity
, true);
553 static bool executeMoveDownAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
555 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, LineGranularity
, true);
559 static bool executeMoveForward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
561 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, CharacterGranularity
, true);
565 static bool executeMoveForwardAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
567 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, CharacterGranularity
, true);
571 static bool executeMoveLeft(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
573 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::LEFT
, CharacterGranularity
, true);
577 static bool executeMoveLeftAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
579 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::LEFT
, CharacterGranularity
, true);
583 static bool executeMovePageDown(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
585 int distance
= verticalScrollDistance(frame
);
588 return frame
->selection()->modify(SelectionController::MOVE
, distance
, true);
591 static bool executeMovePageDownAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
593 int distance
= verticalScrollDistance(frame
);
596 return frame
->selection()->modify(SelectionController::EXTEND
, distance
, true);
599 static bool executeMovePageUp(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
601 int distance
= verticalScrollDistance(frame
);
604 return frame
->selection()->modify(SelectionController::MOVE
, -distance
, true);
607 static bool executeMovePageUpAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
609 int distance
= verticalScrollDistance(frame
);
612 return frame
->selection()->modify(SelectionController::EXTEND
, -distance
, true);
615 static bool executeMoveRight(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
617 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::RIGHT
, CharacterGranularity
, true);
621 static bool executeMoveRightAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
623 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::RIGHT
, CharacterGranularity
, true);
627 static bool executeMoveToBeginningOfDocument(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
629 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, DocumentBoundary
, true);
633 static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
635 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, DocumentBoundary
, true);
639 static bool executeMoveToBeginningOfLine(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
641 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, LineBoundary
, true);
645 static bool executeMoveToBeginningOfLineAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
647 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, LineBoundary
, true);
651 static bool executeMoveToBeginningOfParagraph(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
653 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, ParagraphBoundary
, true);
657 static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
659 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, ParagraphBoundary
, true);
663 static bool executeMoveToBeginningOfSentence(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
665 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, SentenceBoundary
, true);
669 static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
671 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, SentenceBoundary
, true);
675 static bool executeMoveToEndOfDocument(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
677 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, DocumentBoundary
, true);
681 static bool executeMoveToEndOfDocumentAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
683 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, DocumentBoundary
, true);
687 static bool executeMoveToEndOfSentence(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
689 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, SentenceBoundary
, true);
693 static bool executeMoveToEndOfSentenceAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
695 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, SentenceBoundary
, true);
699 static bool executeMoveToEndOfLine(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
701 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, LineBoundary
, true);
705 static bool executeMoveToEndOfLineAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
707 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, LineBoundary
, true);
711 static bool executeMoveToEndOfParagraph(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
713 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, ParagraphBoundary
, true);
717 static bool executeMoveToEndOfParagraphAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
719 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, ParagraphBoundary
, true);
723 static bool executeMoveParagraphBackwardAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
725 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, ParagraphGranularity
, true);
729 static bool executeMoveParagraphForwardAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
731 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, ParagraphGranularity
, true);
735 static bool executeMoveUp(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
737 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, LineGranularity
, true);
741 static bool executeMoveUpAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
743 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, LineGranularity
, true);
747 static bool executeMoveWordBackward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
749 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::BACKWARD
, WordGranularity
, true);
753 static bool executeMoveWordBackwardAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
755 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::BACKWARD
, WordGranularity
, true);
759 static bool executeMoveWordForward(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
761 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::FORWARD
, WordGranularity
, true);
765 static bool executeMoveWordForwardAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
767 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::FORWARD
, WordGranularity
, true);
771 static bool executeMoveWordLeft(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
773 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::LEFT
, WordGranularity
, true);
777 static bool executeMoveWordLeftAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
779 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::LEFT
, WordGranularity
, true);
783 static bool executeMoveWordRight(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
785 frame
->selection()->modify(SelectionController::MOVE
, SelectionController::RIGHT
, WordGranularity
, true);
789 static bool executeMoveWordRightAndModifySelection(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
791 frame
->selection()->modify(SelectionController::EXTEND
, SelectionController::RIGHT
, WordGranularity
, true);
795 static bool executeOutdent(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
797 applyCommand(IndentOutdentCommand::create(frame
->document(), IndentOutdentCommand::Outdent
));
801 static bool executePaste(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
803 frame
->editor()->paste();
807 static bool executePasteAndMatchStyle(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
809 frame
->editor()->pasteAsPlainText();
813 static bool executePrint(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
815 Page
* page
= frame
->page();
818 page
->chrome()->print(frame
);
822 static bool executeRedo(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
824 frame
->editor()->redo();
828 static bool executeRemoveFormat(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
830 frame
->editor()->removeFormattingAndStyle();
834 static bool executeSelectAll(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
836 frame
->selection()->selectAll();
840 static bool executeSelectLine(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
842 return expandSelectionToGranularity(frame
, LineGranularity
);
845 static bool executeSelectParagraph(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
847 return expandSelectionToGranularity(frame
, ParagraphGranularity
);
850 static bool executeSelectSentence(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
852 return expandSelectionToGranularity(frame
, SentenceGranularity
);
855 static bool executeSelectToMark(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
857 RefPtr
<Range
> mark
= frame
->mark().toRange();
858 RefPtr
<Range
> selection
= frame
->editor()->selectedRange();
859 if (!mark
|| !selection
) {
863 frame
->selection()->setSelectedRange(unionDOMRanges(mark
.get(), selection
.get()).get(), DOWNSTREAM
, true);
867 static bool executeSelectWord(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
869 return expandSelectionToGranularity(frame
, WordGranularity
);
872 static bool executeSetMark(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
874 frame
->setMark(frame
->selection()->selection());
878 static bool executeStrikethrough(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
880 return executeToggleStyle(frame
, source
, EditActionChangeAttributes
, CSSPropertyWebkitTextDecorationsInEffect
, "none", "line-through");
883 static bool executeSubscript(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
885 return executeApplyStyle(frame
, source
, EditActionSubscript
, CSSPropertyVerticalAlign
, "sub");
888 static bool executeSuperscript(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
890 return executeApplyStyle(frame
, source
, EditActionSuperscript
, CSSPropertyVerticalAlign
, "super");
893 static bool executeSwapWithMark(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
895 const Selection
& mark
= frame
->mark();
896 const Selection
& selection
= frame
->selection()->selection();
897 if (mark
.isNone() || selection
.isNone()) {
901 frame
->selection()->setSelection(mark
);
902 frame
->setMark(selection
);
906 static bool executeToggleBold(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
908 return executeToggleStyle(frame
, source
, EditActionChangeAttributes
, CSSPropertyFontWeight
, "normal", "bold");
911 static bool executeToggleItalic(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
913 return executeToggleStyle(frame
, source
, EditActionChangeAttributes
, CSSPropertyFontStyle
, "normal", "italic");
916 static bool executeTranspose(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
918 frame
->editor()->transpose();
922 static bool executeUnderline(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
924 // FIXME: This currently clears overline, line-through, and blink as an unwanted side effect.
925 return executeToggleStyle(frame
, source
, EditActionUnderline
, CSSPropertyWebkitTextDecorationsInEffect
, "none", "underline");
928 static bool executeUndo(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
930 frame
->editor()->undo();
934 static bool executeUnlink(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
936 applyCommand(UnlinkCommand::create(frame
->document()));
940 static bool executeUnscript(Frame
* frame
, Event
*, EditorCommandSource source
, const String
&)
942 return executeApplyStyle(frame
, source
, EditActionUnscript
, CSSPropertyVerticalAlign
, "baseline");
945 static bool executeUnselect(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
947 frame
->selection()->clear();
951 static bool executeYank(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
953 frame
->editor()->insertTextWithoutSendingTextEvent(frame
->editor()->yankFromKillRing(), false, 0);
954 frame
->editor()->setKillRingToYankedState();
958 static bool executeYankAndSelect(Frame
* frame
, Event
*, EditorCommandSource
, const String
&)
960 frame
->editor()->insertTextWithoutSendingTextEvent(frame
->editor()->yankFromKillRing(), true, 0);
961 frame
->editor()->setKillRingToYankedState();
965 // Supported functions
967 static bool supported(Frame
*, EditorCommandSource
)
972 static bool supportedFromMenuOrKeyBinding(Frame
*, EditorCommandSource source
)
974 return source
== CommandFromMenuOrKeyBinding
;
977 static bool supportedPaste(Frame
* frame
, EditorCommandSource source
)
980 case CommandFromMenuOrKeyBinding
:
983 case CommandFromDOMWithUserInterface
: {
984 Settings
* settings
= frame
? frame
->settings() : 0;
985 return settings
&& settings
->isDOMPasteAllowed();
988 ASSERT_NOT_REACHED();
994 static bool enabled(Frame
*, Event
*, EditorCommandSource
)
999 static bool enabledAnySelection(Frame
* frame
, Event
*, EditorCommandSource
)
1001 return frame
->selection()->isCaretOrRange();
1004 static bool enabledAnySelectionAndMark(Frame
* frame
, Event
*, EditorCommandSource
)
1006 return frame
->selection()->isCaretOrRange() && frame
->mark().isCaretOrRange();
1009 static bool enableCaretInEditableText(Frame
* frame
, Event
* event
, EditorCommandSource
)
1011 const Selection
& selection
= frame
->editor()->selectionForCommand(event
);
1012 return selection
.isCaret() && selection
.isContentEditable();
1015 static bool enabledCopy(Frame
* frame
, Event
*, EditorCommandSource
)
1017 return frame
->editor()->canDHTMLCopy() || frame
->editor()->canCopy();
1020 static bool enabledCut(Frame
* frame
, Event
*, EditorCommandSource
)
1022 return frame
->editor()->canDHTMLCut() || frame
->editor()->canCut();
1025 static bool enabledDelete(Frame
* frame
, Event
* event
, EditorCommandSource source
)
1028 case CommandFromMenuOrKeyBinding
:
1029 // "Delete" from menu only affects selected range, just like Cut but without affecting pasteboard
1030 return frame
->editor()->canDHTMLCut() || frame
->editor()->canCut();
1031 case CommandFromDOM
:
1032 case CommandFromDOMWithUserInterface
:
1033 // "Delete" from DOM is like delete/backspace keypress, affects selected range if non-empty,
1034 // otherwise removes a character
1035 return frame
->editor()->selectionForCommand(event
).isContentEditable();
1037 ASSERT_NOT_REACHED();
1041 static bool enabledInEditableText(Frame
* frame
, Event
* event
, EditorCommandSource
)
1043 return frame
->editor()->selectionForCommand(event
).isContentEditable();
1046 static bool enabledInRichlyEditableText(Frame
* frame
, Event
*, EditorCommandSource
)
1048 return frame
->selection()->isCaretOrRange() && frame
->selection()->isContentRichlyEditable();
1051 static bool enabledPaste(Frame
* frame
, Event
*, EditorCommandSource
)
1053 return frame
->editor()->canPaste();
1056 static bool enabledRangeInEditableText(Frame
* frame
, Event
*, EditorCommandSource
)
1058 return frame
->selection()->isRange() && frame
->selection()->isContentEditable();
1061 static bool enabledRangeInRichlyEditableText(Frame
* frame
, Event
*, EditorCommandSource
)
1063 return frame
->selection()->isRange() && frame
->selection()->isContentRichlyEditable();
1066 static bool enabledRedo(Frame
* frame
, Event
*, EditorCommandSource
)
1068 return frame
->editor()->canRedo();
1071 static bool enabledUndo(Frame
* frame
, Event
*, EditorCommandSource
)
1073 return frame
->editor()->canUndo();
1078 static TriState
stateNone(Frame
*, Event
*)
1080 return FalseTriState
;
1083 static TriState
stateBold(Frame
* frame
, Event
*)
1085 return stateStyle(frame
, CSSPropertyFontWeight
, "bold");
1088 static TriState
stateItalic(Frame
* frame
, Event
*)
1090 return stateStyle(frame
, CSSPropertyFontStyle
, "italic");
1093 static TriState
stateOrderedList(Frame
* frame
, Event
*)
1095 return frame
->editor()->selectionOrderedListState();
1098 static TriState
stateStrikethrough(Frame
* frame
, Event
*)
1100 return stateStyle(frame
, CSSPropertyTextDecoration
, "line-through");
1103 static TriState
stateSubscript(Frame
* frame
, Event
*)
1105 return stateStyle(frame
, CSSPropertyVerticalAlign
, "sub");
1108 static TriState
stateSuperscript(Frame
* frame
, Event
*)
1110 return stateStyle(frame
, CSSPropertyVerticalAlign
, "super");
1113 static TriState
stateUnderline(Frame
* frame
, Event
*)
1115 return stateStyle(frame
, CSSPropertyTextDecoration
, "underline");
1118 static TriState
stateUnorderedList(Frame
* frame
, Event
*)
1120 return frame
->editor()->selectionUnorderedListState();
1125 static String
valueNull(Frame
*, Event
*)
1130 String
valueBackColor(Frame
* frame
, Event
*)
1132 return valueStyle(frame
, CSSPropertyBackgroundColor
);
1135 String
valueFontName(Frame
* frame
, Event
*)
1137 return valueStyle(frame
, CSSPropertyFontFamily
);
1140 String
valueFontSize(Frame
* frame
, Event
*)
1142 return valueStyle(frame
, CSSPropertyFontSize
);
1145 String
valueFontSizeDelta(Frame
* frame
, Event
*)
1147 return valueStyle(frame
, CSSPropertyWebkitFontSizeDelta
);
1150 String
valueForeColor(Frame
* frame
, Event
*)
1152 return valueStyle(frame
, CSSPropertyColor
);
1157 static const CommandMap
& createCommandMap()
1159 struct CommandEntry
{ const char* name
; EditorInternalCommand command
; };
1161 static const CommandEntry commands
[] = {
1162 { "AlignCenter", { executeJustifyCenter
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1163 { "AlignJustified", { executeJustifyFull
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1164 { "AlignLeft", { executeJustifyLeft
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1165 { "AlignRight", { executeJustifyRight
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1166 { "BackColor", { executeBackColor
, supported
, enabledInRichlyEditableText
, stateNone
, valueBackColor
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1167 { "BackwardDelete", { executeDeleteBackward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} }, // FIXME: remove BackwardDelete when Safari for Windows stops using it.
1168 { "Bold", { executeToggleBold
, supported
, enabledInRichlyEditableText
, stateBold
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1169 { "Copy", { executeCopy
, supported
, enabledCopy
, stateNone
, valueNull
, notTextInsertion
, allowExecutionWhenDisabled
} },
1170 { "CreateLink", { executeCreateLink
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1171 { "Cut", { executeCut
, supported
, enabledCut
, stateNone
, valueNull
, notTextInsertion
, allowExecutionWhenDisabled
} },
1172 { "Delete", { executeDelete
, supported
, enabledDelete
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1173 { "DeleteBackward", { executeDeleteBackward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1174 { "DeleteBackwardByDecomposingPreviousCharacter", { executeDeleteBackwardByDecomposingPreviousCharacter
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1175 { "DeleteForward", { executeDeleteForward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1176 { "DeleteToBeginningOfLine", { executeDeleteToBeginningOfLine
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1177 { "DeleteToBeginningOfParagraph", { executeDeleteToBeginningOfParagraph
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1178 { "DeleteToEndOfLine", { executeDeleteToEndOfLine
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1179 { "DeleteToEndOfParagraph", { executeDeleteToEndOfParagraph
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1180 { "DeleteToMark", { executeDeleteToMark
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1181 { "DeleteWordBackward", { executeDeleteWordBackward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1182 { "DeleteWordForward", { executeDeleteWordForward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1183 { "FindString", { executeFindString
, supported
, enabled
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1184 { "FontName", { executeFontName
, supported
, enabledInEditableText
, stateNone
, valueFontName
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1185 { "FontSize", { executeFontSize
, supported
, enabledInEditableText
, stateNone
, valueFontSize
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1186 { "FontSizeDelta", { executeFontSizeDelta
, supported
, enabledInEditableText
, stateNone
, valueFontSizeDelta
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1187 { "ForeColor", { executeForeColor
, supported
, enabledInRichlyEditableText
, stateNone
, valueForeColor
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1188 { "FormatBlock", { executeFormatBlock
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1189 { "ForwardDelete", { executeForwardDelete
, supported
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1190 { "HiliteColor", { executeBackColor
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1191 { "IgnoreSpelling", { executeIgnoreSpelling
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1192 { "Indent", { executeIndent
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1193 { "InsertBacktab", { executeInsertBacktab
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, isTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1194 { "InsertHorizontalRule", { executeInsertHorizontalRule
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1195 { "InsertHTML", { executeInsertHTML
, supported
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1196 { "InsertImage", { executeInsertImage
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1197 { "InsertLineBreak", { executeInsertLineBreak
, supported
, enabledInEditableText
, stateNone
, valueNull
, isTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1198 { "InsertNewline", { executeInsertNewline
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, isTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1199 { "InsertNewlineInQuotedContent", { executeInsertNewlineInQuotedContent
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1200 { "InsertOrderedList", { executeInsertOrderedList
, supported
, enabledInRichlyEditableText
, stateOrderedList
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1201 { "InsertParagraph", { executeInsertParagraph
, supported
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1202 { "InsertTab", { executeInsertTab
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, isTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1203 { "InsertText", { executeInsertText
, supported
, enabledInEditableText
, stateNone
, valueNull
, isTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1204 { "InsertUnorderedList", { executeInsertUnorderedList
, supported
, enabledInRichlyEditableText
, stateUnorderedList
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1205 { "Italic", { executeToggleItalic
, supported
, enabledInRichlyEditableText
, stateItalic
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1206 { "JustifyCenter", { executeJustifyCenter
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1207 { "JustifyFull", { executeJustifyFull
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1208 { "JustifyLeft", { executeJustifyLeft
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1209 { "JustifyNone", { executeJustifyLeft
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1210 { "JustifyRight", { executeJustifyRight
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1211 { "MoveBackward", { executeMoveBackward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1212 { "MoveBackwardAndModifySelection", { executeMoveBackwardAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1213 { "MoveDown", { executeMoveDown
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1214 { "MoveDownAndModifySelection", { executeMoveDownAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1215 { "MoveForward", { executeMoveForward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1216 { "MoveForwardAndModifySelection", { executeMoveForwardAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1217 { "MoveLeft", { executeMoveLeft
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1218 { "MoveLeftAndModifySelection", { executeMoveLeftAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1219 { "MovePageDown", { executeMovePageDown
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1220 { "MovePageDownAndModifySelection", { executeMovePageDownAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1221 { "MovePageUp", { executeMovePageUp
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1222 { "MovePageUpAndModifySelection", { executeMovePageUpAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1223 { "MoveParagraphBackwardAndModifySelection", { executeMoveParagraphBackwardAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1224 { "MoveParagraphForwardAndModifySelection", { executeMoveParagraphForwardAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1225 { "MoveRight", { executeMoveRight
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1226 { "MoveRightAndModifySelection", { executeMoveRightAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1227 { "MoveToBeginningOfDocument", { executeMoveToBeginningOfDocument
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1228 { "MoveToBeginningOfDocumentAndModifySelection", { executeMoveToBeginningOfDocumentAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1229 { "MoveToBeginningOfLine", { executeMoveToBeginningOfLine
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1230 { "MoveToBeginningOfLineAndModifySelection", { executeMoveToBeginningOfLineAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1231 { "MoveToBeginningOfParagraph", { executeMoveToBeginningOfParagraph
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1232 { "MoveToBeginningOfParagraphAndModifySelection", { executeMoveToBeginningOfParagraphAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1233 { "MoveToBeginningOfSentence", { executeMoveToBeginningOfSentence
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1234 { "MoveToBeginningOfSentenceAndModifySelection", { executeMoveToBeginningOfSentenceAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1235 { "MoveToEndOfDocument", { executeMoveToEndOfDocument
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1236 { "MoveToEndOfDocumentAndModifySelection", { executeMoveToEndOfDocumentAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1237 { "MoveToEndOfLine", { executeMoveToEndOfLine
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1238 { "MoveToEndOfLineAndModifySelection", { executeMoveToEndOfLineAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1239 { "MoveToEndOfParagraph", { executeMoveToEndOfParagraph
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1240 { "MoveToEndOfParagraphAndModifySelection", { executeMoveToEndOfParagraphAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1241 { "MoveToEndOfSentence", { executeMoveToEndOfSentence
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1242 { "MoveToEndOfSentenceAndModifySelection", { executeMoveToEndOfSentenceAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1243 { "MoveUp", { executeMoveUp
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1244 { "MoveUpAndModifySelection", { executeMoveUpAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1245 { "MoveWordBackward", { executeMoveWordBackward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1246 { "MoveWordBackwardAndModifySelection", { executeMoveWordBackwardAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1247 { "MoveWordForward", { executeMoveWordForward
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1248 { "MoveWordForwardAndModifySelection", { executeMoveWordForwardAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1249 { "MoveWordLeft", { executeMoveWordLeft
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1250 { "MoveWordLeftAndModifySelection", { executeMoveWordLeftAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1251 { "MoveWordRight", { executeMoveWordRight
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1252 { "MoveWordRightAndModifySelection", { executeMoveWordRightAndModifySelection
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1253 { "Outdent", { executeOutdent
, supported
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1254 { "Paste", { executePaste
, supportedPaste
, enabledPaste
, stateNone
, valueNull
, notTextInsertion
, allowExecutionWhenDisabled
} },
1255 { "PasteAndMatchStyle", { executePasteAndMatchStyle
, supportedPaste
, enabledPaste
, stateNone
, valueNull
, notTextInsertion
, allowExecutionWhenDisabled
} },
1256 { "Print", { executePrint
, supported
, enabled
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1257 { "Redo", { executeRedo
, supported
, enabledRedo
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1258 { "RemoveFormat", { executeRemoveFormat
, supported
, enabledRangeInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1259 { "SelectAll", { executeSelectAll
, supported
, enabled
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1260 { "SelectLine", { executeSelectLine
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1261 { "SelectParagraph", { executeSelectParagraph
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1262 { "SelectSentence", { executeSelectSentence
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1263 { "SelectToMark", { executeSelectToMark
, supportedFromMenuOrKeyBinding
, enabledAnySelectionAndMark
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1264 { "SelectWord", { executeSelectWord
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1265 { "SetMark", { executeSetMark
, supportedFromMenuOrKeyBinding
, enabledAnySelection
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1266 { "Strikethrough", { executeStrikethrough
, supported
, enabledInRichlyEditableText
, stateStrikethrough
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1267 { "Subscript", { executeSubscript
, supported
, enabledInRichlyEditableText
, stateSubscript
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1268 { "Superscript", { executeSuperscript
, supported
, enabledInRichlyEditableText
, stateSuperscript
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1269 { "SwapWithMark", { executeSwapWithMark
, supportedFromMenuOrKeyBinding
, enabledAnySelectionAndMark
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1270 { "ToggleBold", { executeToggleBold
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateBold
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1271 { "ToggleItalic", { executeToggleItalic
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateItalic
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1272 { "ToggleUnderline", { executeUnderline
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateUnderline
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1273 { "Transpose", { executeTranspose
, supported
, enableCaretInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1274 { "Underline", { executeUnderline
, supported
, enabledInRichlyEditableText
, stateUnderline
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1275 { "Undo", { executeUndo
, supported
, enabledUndo
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1276 { "Unlink", { executeUnlink
, supported
, enabledRangeInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1277 { "Unscript", { executeUnscript
, supportedFromMenuOrKeyBinding
, enabledInRichlyEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1278 { "Unselect", { executeUnselect
, supported
, enabledAnySelection
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1279 { "Yank", { executeYank
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1280 { "YankAndSelect", { executeYankAndSelect
, supportedFromMenuOrKeyBinding
, enabledInEditableText
, stateNone
, valueNull
, notTextInsertion
, doNotAllowExecutionWhenDisabled
} },
1283 // These unsupported commands are listed here since they appear in the Microsoft
1284 // documentation used as the starting point for our DOM executeCommand support.
1286 // 2D-Position (not supported)
1287 // AbsolutePosition (not supported)
1288 // BlockDirLTR (not supported)
1289 // BlockDirRTL (not supported)
1290 // BrowseMode (not supported)
1291 // ClearAuthenticationCache (not supported)
1292 // CreateBookmark (not supported)
1293 // DirLTR (not supported)
1294 // DirRTL (not supported)
1295 // EditMode (not supported)
1296 // InlineDirLTR (not supported)
1297 // InlineDirRTL (not supported)
1298 // InsertButton (not supported)
1299 // InsertFieldSet (not supported)
1300 // InsertIFrame (not supported)
1301 // InsertInputButton (not supported)
1302 // InsertInputCheckbox (not supported)
1303 // InsertInputFileUpload (not supported)
1304 // InsertInputHidden (not supported)
1305 // InsertInputImage (not supported)
1306 // InsertInputPassword (not supported)
1307 // InsertInputRadio (not supported)
1308 // InsertInputReset (not supported)
1309 // InsertInputSubmit (not supported)
1310 // InsertInputText (not supported)
1311 // InsertMarquee (not supported)
1312 // InsertSelectDropDown (not supported)
1313 // InsertSelectListBox (not supported)
1314 // InsertTextArea (not supported)
1315 // LiveResize (not supported)
1316 // MultipleSelection (not supported)
1317 // Open (not supported)
1318 // Overwrite (not supported)
1319 // PlayImage (not supported)
1320 // Refresh (not supported)
1321 // RemoveParaFormat (not supported)
1322 // SaveAs (not supported)
1323 // SizeToControl (not supported)
1324 // SizeToControlHeight (not supported)
1325 // SizeToControlWidth (not supported)
1326 // Stop (not supported)
1327 // StopImage (not supported)
1328 // Unbookmark (not supported)
1330 CommandMap
& commandMap
= *new CommandMap
;
1332 const unsigned numCommands
= sizeof(commands
) / sizeof(commands
[0]);
1333 for (unsigned i
= 0; i
< numCommands
; i
++) {
1334 ASSERT(!commandMap
.get(commands
[i
].name
));
1335 commandMap
.set(commands
[i
].name
, &commands
[i
].command
);
1341 Editor::Command
Editor::command(const String
& commandName
)
1343 return command(commandName
, CommandFromMenuOrKeyBinding
);
1346 Editor::Command
Editor::command(const String
& commandName
, EditorCommandSource source
)
1348 if (commandName
.isEmpty())
1351 static const CommandMap
& commandMap
= createCommandMap();
1352 const EditorInternalCommand
* internalCommand
= commandMap
.get(commandName
);
1353 return internalCommand
? Command(m_frame
, internalCommand
, source
) : Command();
1356 Editor::Command::Command()
1362 Editor::Command::Command(PassRefPtr
<Frame
> frame
, const EditorInternalCommand
* command
, EditorCommandSource source
)
1364 , m_command(command
)
1371 bool Editor::Command::execute(const String
& parameter
, Event
* triggeringEvent
) const
1373 if (!isEnabled(triggeringEvent
)) {
1374 // Let certain commands be executed when performed explicitly even if they are disabled.
1375 if (!isSupported() || !m_frame
|| !m_frame
->document() || !m_command
->allowExecutionWhenDisabled
)
1378 m_frame
->document()->updateLayoutIgnorePendingStylesheets();
1379 return m_command
->execute(m_frame
.get(), triggeringEvent
, m_source
, parameter
);
1382 bool Editor::Command::execute(Event
* triggeringEvent
) const
1384 return execute(String(), triggeringEvent
);
1387 bool Editor::Command::isSupported() const
1389 return m_command
&& m_command
->isSupported(m_frame
.get(), m_source
);
1392 bool Editor::Command::isEnabled(Event
* triggeringEvent
) const
1394 if (!isSupported() || !m_frame
|| !m_frame
->document())
1396 return m_command
->isEnabled(m_frame
.get(), triggeringEvent
, m_source
);
1399 TriState
Editor::Command::state(Event
* triggeringEvent
) const
1401 if (!isSupported() || !m_frame
|| !m_frame
->document())
1402 return FalseTriState
;
1403 return m_command
->state(m_frame
.get(), triggeringEvent
);
1406 String
Editor::Command::value(Event
* triggeringEvent
) const
1408 if (!isSupported() || !m_frame
|| !m_frame
->document())
1410 return m_command
->value(m_frame
.get(), triggeringEvent
);
1413 bool Editor::Command::isTextInsertion() const
1415 return m_command
&& m_command
->isTextInsertion
;
1418 } // namespace WebCore