2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "ApplyStyleCommand.h"
30 #include "AXObjectCache.h"
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSProperty.h"
33 #include "CSSPropertyNames.h"
34 #include "DeleteButtonController.h"
35 #include "DeleteSelectionCommand.h"
37 #include "DocumentFragment.h"
38 #include "EditCommand.h"
40 #include "EditorClient.h"
42 #include "EventNames.h"
43 #include "HTMLElement.h"
44 #include "HTMLNames.h"
45 #include "HitTestResult.h"
46 #include "IndentOutdentCommand.h"
48 #include "ReplaceSelectionCommand.h"
49 #include "SelectionController.h"
51 #include "htmlediting.h"
56 using namespace EventNames;
57 using namespace HTMLNames;
59 // implement as platform-specific
60 static Pasteboard generalPasteboard()
65 EditorClient* Editor::client() const
67 return m_client.get();
70 bool Editor::canEdit() const
72 SelectionController* selectionController = m_frame->selectionController();
73 return selectionController->isCaretOrRange() && selectionController->isContentEditable();
76 bool Editor::canEditRichly() const
78 SelectionController* selectionController = m_frame->selectionController();
79 return canEdit() && selectionController->isContentRichlyEditable();
82 bool Editor::canCut() const
84 return canCopy() && canDelete();
87 bool Editor::canCopy() const
89 SelectionController* selectionController = m_frame->selectionController();
90 return selectionController->isRange() && !selectionController->isInPasswordField();
93 bool Editor::canPaste() const
95 SelectionController* selectionController = m_frame->selectionController();
96 return selectionController->isCaretOrRange() && selectionController->isContentEditable();
99 bool Editor::canDelete() const
101 SelectionController* selectionController = m_frame->selectionController();
102 return selectionController->isRange() && selectionController->isContentEditable();
105 bool Editor::canDeleteRange(Range* range) const
107 ExceptionCode ec = 0;
108 Node* startContainer = range->startContainer(ec);
109 Node* endContainer = range->endContainer(ec);
110 if (!startContainer || !endContainer)
113 if (!startContainer->isContentEditable() || !endContainer->isContentEditable())
116 if (range->collapsed(ec)) {
117 VisiblePosition start(startContainer, range->startOffset(ec), DOWNSTREAM);
118 VisiblePosition previous = start.previous();
119 // FIXME: We sometimes allow deletions at the start of editable roots, like when the caret is in an empty list item.
120 if (previous.isNull() || previous.deepEquivalent().node()->rootEditableElement() != startContainer->rootEditableElement())
126 bool Editor::canSmartCopyOrDelete()
131 void Editor::deleteSelection()
135 void Editor::deleteSelectionWithSmartDelete(bool smartDelete)
137 if (m_frame->selectionController()->isNone())
140 applyCommand(new DeleteSelectionCommand(m_frame->document(), smartDelete));
143 void Editor::pasteAsPlainTextWithPasteboard(Pasteboard pasteboard)
147 void Editor::pasteWithPasteboard(Pasteboard pasteboard, bool allowPlainText)
151 Range* Editor::selectedRange()
156 bool Editor::shouldDeleteRange(Range* range) const
159 if (!range || range->collapsed(ec))
162 if (!canDeleteRange(range))
165 return m_client->shouldDeleteRange(range);
168 bool Editor::tryDHTMLCopy()
170 bool handled = false;
174 bool Editor::tryDHTMLCut()
176 bool handled = false;
180 bool Editor::tryDHTMLPaste()
182 bool handled = false;
186 void Editor::writeSelectionToPasteboard(Pasteboard pasteboard)
190 bool Editor::shouldShowDeleteInterface(HTMLElement* element) const
192 return m_client->shouldShowDeleteInterface(element);
195 void Editor::respondToChangedSelection(const Selection& oldSelection)
197 m_deleteButtonController->respondToChangedSelection(oldSelection);
200 void Editor::respondToChangedContents(const Selection& endingSelection)
202 if (AXObjectCache::accessibilityEnabled()) {
203 Node* node = endingSelection.start().node();
205 m_frame->renderer()->document()->axObjectCache()->postNotification(node->renderer(), "AXValueChanged");
208 m_client->respondToChangedContents();
209 m_deleteButtonController->respondToChangedContents();
212 Frame::TriState Editor::selectionUnorderedListState() const
214 if (m_frame->selectionController()->isCaret()) {
215 Node* selectionNode = m_frame->selectionController()->selection().start().node();
216 if (enclosingNodeWithTag(selectionNode, ulTag))
217 return Frame::trueTriState;
218 } else if (m_frame->selectionController()->isRange()) {
219 Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), ulTag);
220 Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), ulTag);
221 if (startNode && endNode && startNode == endNode)
222 return Frame::trueTriState;
225 return Frame::falseTriState;
228 Frame::TriState Editor::selectionOrderedListState() const
230 if (m_frame->selectionController()->isCaret()) {
231 Node* selectionNode = m_frame->selectionController()->selection().start().node();
232 if (enclosingNodeWithTag(selectionNode, olTag))
233 return Frame::trueTriState;
234 } else if (m_frame->selectionController()->isRange()) {
235 Node* startNode = enclosingNodeWithTag(m_frame->selectionController()->selection().start().node(), olTag);
236 Node* endNode = enclosingNodeWithTag(m_frame->selectionController()->selection().end().node(), olTag);
237 if (startNode && endNode && startNode == endNode)
238 return Frame::trueTriState;
241 return Frame::falseTriState;
244 void Editor::removeFormattingAndStyle()
246 Document* document = m_frame->document();
248 // Make a plain text string from the selection to remove formatting like tables and lists.
249 RefPtr<DocumentFragment> text = createFragmentFromText(m_frame->selectionController()->toRange().get(), m_frame->selectionController()->toString());
251 // Put the fragment made from that string into a style span with the document's
252 // default style to make sure that it is unstyled regardless of where it is inserted.
253 Position pos(document->documentElement(), 0);
254 RefPtr<CSSComputedStyleDeclaration> computedStyle = pos.computedStyle();
255 RefPtr<CSSMutableStyleDeclaration> defaultStyle = computedStyle->copyInheritableProperties();
257 RefPtr<Element> span = createStyleSpanElement(document);
258 span->setAttribute(styleAttr, defaultStyle->cssText());
262 while (text->lastChild())
263 span->appendChild(text->lastChild(), ec);
265 RefPtr<DocumentFragment> fragment = new DocumentFragment(document);
266 fragment->appendChild(span, ec);
268 applyCommand(new ReplaceSelectionCommand(document, fragment, false, false, false, true, EditActionUnspecified));
271 void Editor::setLastEditCommand(PassRefPtr<EditCommand> lastEditCommand)
273 m_lastEditCommand = lastEditCommand;
276 void Editor::applyStyle(CSSStyleDeclaration *style, EditAction editingAction)
278 switch (m_frame->selectionController()->state()) {
279 case Selection::NONE:
282 case Selection::CARET: {
283 m_frame->computeAndSetTypingStyle(style, editingAction);
286 case Selection::RANGE:
287 if (m_frame->document() && style)
288 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction));
293 void Editor::applyParagraphStyle(CSSStyleDeclaration *style, EditAction editingAction)
295 switch (m_frame->selectionController()->state()) {
296 case Selection::NONE:
299 case Selection::CARET:
300 case Selection::RANGE:
301 if (m_frame->document() && style)
302 applyCommand(new ApplyStyleCommand(m_frame->document(), style, editingAction, ApplyStyleCommand::ForceBlockProperties));
307 void Editor::applyStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
309 if (!style || style->length() == 0 || !canEditRichly())
312 if (m_client->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
313 applyStyle(style, editingAction);
316 void Editor::applyParagraphStyleToSelection(CSSStyleDeclaration* style, EditAction editingAction)
318 if (!style || style->length() == 0 || !canEditRichly())
321 if (m_client->shouldApplyStyle(style, m_frame->selectionController()->toRange().get()))
322 applyParagraphStyle(style, editingAction);
325 void Editor::toggleBold()
329 RefPtr<CSSStyleDeclaration> style = m_frame->document()->createCSSStyleDeclaration();
330 style->setProperty(CSS_PROP_FONT_WEIGHT, "bold", false, ec);
331 if (selectionStartHasStyle(style.get()))
332 style->setProperty(CSS_PROP_FONT_WEIGHT, "normal", false, ec);
333 applyStyleToSelection(style.get(), EditActionSetFont);
336 void Editor::toggleItalic()
340 RefPtr<CSSStyleDeclaration> style = m_frame->document()->createCSSStyleDeclaration();
341 style->setProperty(CSS_PROP_FONT_STYLE, "italic", false, ec);
342 if (selectionStartHasStyle(style.get()))
343 style->setProperty(CSS_PROP_FONT_STYLE, "normal", false, ec);
344 applyStyleToSelection(style.get(), EditActionSetFont);
347 bool Editor::selectionStartHasStyle(CSSStyleDeclaration* style) const
350 RefPtr<CSSStyleDeclaration> selectionStyle = m_frame->selectionComputedStyle(nodeToRemove);
354 RefPtr<CSSMutableStyleDeclaration> mutableStyle = style->makeMutable();
357 DeprecatedValueListConstIterator<CSSProperty> end;
358 for (DeprecatedValueListConstIterator<CSSProperty> it = mutableStyle->valuesIterator(); it != end; ++it) {
359 int propertyID = (*it).id();
360 if (!equalIgnoringCase(mutableStyle->getPropertyValue(propertyID), selectionStyle->getPropertyValue(propertyID))) {
367 ExceptionCode ec = 0;
368 nodeToRemove->remove(ec);
375 void Editor::indent()
377 applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Indent));
380 void Editor::outdent()
382 applyCommand(new IndentOutdentCommand(m_frame->document(), IndentOutdentCommand::Outdent));
385 static void dispatchEditableContentChangedEvents(const EditCommand& command)
387 Element* startRoot = command.startingRootEditableElement();
388 Element* endRoot = command.endingRootEditableElement();
391 startRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
392 if (endRoot && endRoot != startRoot)
393 endRoot->dispatchEvent(new Event(khtmlEditableContentChangedEvent, false, false), ec, true);
396 void Editor::appliedEditing(PassRefPtr<EditCommand> cmd)
398 dispatchEditableContentChangedEvents(*cmd);
400 Selection newSelection(cmd->endingSelection());
401 if (m_frame->shouldChangeSelection(newSelection))
402 m_frame->selectionController()->setSelection(newSelection, false);
404 // Now set the typing style from the command. Clear it when done.
405 // This helps make the case work where you completely delete a piece
406 // of styled text and then type a character immediately after.
407 // That new character needs to take on the style of the just-deleted text.
408 // FIXME: Improve typing style.
409 // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
410 if (cmd->typingStyle()) {
411 m_frame->setTypingStyle(cmd->typingStyle());
412 cmd->setTypingStyle(0);
415 // Command will be equal to last edit command only in the case of typing
416 if (m_lastEditCommand.get() == cmd)
417 ASSERT(cmd->isTypingCommand());
419 // Only register a new undo command if the command passed in is
420 // different from the last command
421 m_lastEditCommand = cmd;
422 m_frame->registerCommandForUndo(m_lastEditCommand);
424 respondToChangedContents(newSelection);
427 void Editor::unappliedEditing(PassRefPtr<EditCommand> cmd)
429 dispatchEditableContentChangedEvents(*cmd);
431 Selection newSelection(cmd->startingSelection());
432 if (m_frame->shouldChangeSelection(newSelection))
433 m_frame->selectionController()->setSelection(newSelection, true);
435 m_lastEditCommand = 0;
436 m_frame->registerCommandForRedo(cmd);
437 respondToChangedContents(newSelection);
440 void Editor::reappliedEditing(PassRefPtr<EditCommand> cmd)
442 dispatchEditableContentChangedEvents(*cmd);
444 Selection newSelection(cmd->endingSelection());
445 if (m_frame->shouldChangeSelection(newSelection))
446 m_frame->selectionController()->setSelection(newSelection, true);
448 m_lastEditCommand = 0;
449 m_frame->registerCommandForUndo(cmd);
450 respondToChangedContents(newSelection);
453 // Execute command functions
455 static bool execMoveBackward(Frame* frame)
457 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, CharacterGranularity, true);
461 static bool execMoveBackwardAndModifySelection(Frame* frame)
463 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, CharacterGranularity, true);
467 static bool execMoveDown(Frame* frame)
469 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineGranularity, true);
473 static bool execMoveDownAndModifySelection(Frame* frame)
475 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineGranularity, true);
479 static bool execMoveForward(Frame* frame)
481 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, CharacterGranularity, true);
485 static bool execMoveForwardAndModifySelection(Frame* frame)
487 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, CharacterGranularity, true);
491 static bool execMoveLeft(Frame* frame)
493 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, CharacterGranularity, true);
497 static bool execMoveLeftAndModifySelection(Frame* frame)
499 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, CharacterGranularity, true);
503 static bool execMoveRight(Frame* frame)
505 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, CharacterGranularity, true);
509 static bool execMoveRightAndModifySelection(Frame* frame)
511 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, CharacterGranularity, true);
515 static bool execMoveToBeginningOfDocument(Frame* frame)
517 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, DocumentBoundary, true);
521 static bool execMoveToBeginningOfDocumentAndModifySelection(Frame* frame)
523 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, DocumentBoundary, true);
527 static bool execMoveToBeginningOfSentence(Frame* frame)
529 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, SentenceBoundary, true);
533 static bool execMoveToBeginningOfSentenceAndModifySelection(Frame* frame)
535 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, SentenceBoundary, true);
539 static bool execMoveToBeginningOfLine(Frame* frame)
541 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineBoundary, true);
545 static bool execMoveToBeginningOfLineAndModifySelection(Frame* frame)
547 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineBoundary, true);
551 static bool execMoveToBeginningOfParagraph(Frame* frame)
553 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, ParagraphBoundary, true);
557 static bool execMoveToBeginningOfParagraphAndModifySelection(Frame* frame)
559 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphBoundary, true);
563 static bool execMoveToEndOfDocument(Frame* frame)
565 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, DocumentBoundary, true);
569 static bool execMoveToEndOfDocumentAndModifySelection(Frame* frame)
571 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, DocumentBoundary, true);
575 static bool execMoveToEndOfSentence(Frame* frame)
577 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, SentenceBoundary, true);
581 static bool execMoveToEndOfSentenceAndModifySelection(Frame* frame)
583 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, SentenceBoundary, true);
587 static bool execMoveToEndOfLine(Frame* frame)
589 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, LineBoundary, true);
593 static bool execMoveToEndOfLineAndModifySelection(Frame* frame)
595 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, LineBoundary, true);
599 static bool execMoveToEndOfParagraph(Frame* frame)
601 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, ParagraphBoundary, true);
605 static bool execMoveToEndOfParagraphAndModifySelection(Frame* frame)
607 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphBoundary, true);
611 static bool execMoveParagraphBackwardAndModifySelection(Frame* frame)
613 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, ParagraphGranularity, true);
617 static bool execMoveParagraphForwardAndModifySelection(Frame* frame)
619 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, ParagraphGranularity, true);
623 static bool execMoveUp(Frame* frame)
625 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, LineGranularity, true);
629 static bool execMoveUpAndModifySelection(Frame* frame)
631 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, LineGranularity, true);
635 static bool execMoveWordBackward(Frame* frame)
637 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::BACKWARD, WordGranularity, true);
641 static bool execMoveWordBackwardAndModifySelection(Frame* frame)
643 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::BACKWARD, WordGranularity, true);
647 static bool execMoveWordForward(Frame* frame)
649 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::FORWARD, WordGranularity, true);
653 static bool execMoveWordForwardAndModifySelection(Frame* frame)
655 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::FORWARD, WordGranularity, true);
659 static bool execMoveWordLeft(Frame* frame)
661 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::LEFT, WordGranularity, true);
665 static bool execMoveWordLeftAndModifySelection(Frame* frame)
667 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::LEFT, WordGranularity, true);
671 static bool execMoveWordRight(Frame* frame)
673 frame->selectionController()->modify(SelectionController::MOVE, SelectionController::RIGHT, WordGranularity, true);
677 static bool execMoveWordRightAndModifySelection(Frame* frame)
679 frame->selectionController()->modify(SelectionController::EXTEND, SelectionController::RIGHT, WordGranularity, true);
685 bool canAlterCurrentSelection(Frame* frame)
687 return frame->selectionController()->isCaretOrRange() && frame->selectionController()->isContentEditable();
691 bool (*enabled)(Frame* frame);
692 bool (*exec)(Frame* frame);
695 typedef HashMap<String, const Command*> CommandMap;
697 static CommandMap* createCommandMap()
699 struct CommandEntry { const char* name; Command command; };
701 static const CommandEntry commands[] = {
702 { "MoveBackward", { canAlterCurrentSelection, execMoveBackward } },
703 { "MoveBackwardAndModifySelection", { canAlterCurrentSelection, execMoveBackwardAndModifySelection } },
704 { "MoveDown", { canAlterCurrentSelection, execMoveDown } },
705 { "MoveDownAndModifySelection", { canAlterCurrentSelection, execMoveDownAndModifySelection } },
706 { "MoveForward", { canAlterCurrentSelection, execMoveForward } },
707 { "MoveForwardAndModifySelection", { canAlterCurrentSelection, execMoveForwardAndModifySelection } },
708 { "MoveLeft", { canAlterCurrentSelection, execMoveLeft } },
709 { "MoveLeftAndModifySelection", { canAlterCurrentSelection, execMoveLeftAndModifySelection } },
710 { "MoveRight", { canAlterCurrentSelection, execMoveRight } },
711 { "MoveRightAndModifySelection", { canAlterCurrentSelection, execMoveRightAndModifySelection } },
712 { "MoveToBeginningOfDocument", { canAlterCurrentSelection, execMoveToBeginningOfDocument } },
713 { "MoveToBeginningOfDocumentAndModifySelection", { canAlterCurrentSelection, execMoveToBeginningOfDocumentAndModifySelection } },
714 { "MoveToBeginningOfSentence", { canAlterCurrentSelection, execMoveToBeginningOfSentence } },
715 { "MoveToBeginningOfSentenceAndModifySelection", { canAlterCurrentSelection, execMoveToBeginningOfSentenceAndModifySelection } },
716 { "MoveToBeginningOfLine", { canAlterCurrentSelection, execMoveToBeginningOfLine } },
717 { "MoveToBeginningOfLineAndModifySelection", { canAlterCurrentSelection, execMoveToBeginningOfLineAndModifySelection } },
718 { "MoveToBeginningOfParagraph", { canAlterCurrentSelection, execMoveToBeginningOfParagraph } },
719 { "MoveToBeginningOfLineAndModifySelection", { canAlterCurrentSelection, execMoveToBeginningOfParagraphAndModifySelection } },
720 { "MoveToEndOfDocument", { canAlterCurrentSelection, execMoveToEndOfDocument } },
721 { "MoveToEndOfDocumentAndModifySelection", { canAlterCurrentSelection, execMoveToEndOfDocumentAndModifySelection } },
722 { "MoveToEndOfSentence", { canAlterCurrentSelection, execMoveToEndOfSentence } },
723 { "MoveToEndOfSentenceAndModifySelection", { canAlterCurrentSelection, execMoveToEndOfSentenceAndModifySelection } },
724 { "MoveToEndOfLine", { canAlterCurrentSelection, execMoveToEndOfLine } },
725 { "MoveToEndOfLineAndModifySelection", { canAlterCurrentSelection, execMoveToEndOfLineAndModifySelection } },
726 { "MoveToEndOfParagraph", { canAlterCurrentSelection, execMoveToEndOfParagraph } },
727 { "MoveToEndOfLineAndModifySelection", { canAlterCurrentSelection, execMoveToEndOfParagraphAndModifySelection } },
728 { "MoveParagraphBackwardAndModifySelection", { canAlterCurrentSelection, execMoveParagraphBackwardAndModifySelection } },
729 { "MoveParagraphForwardAndModifySelection", { canAlterCurrentSelection, execMoveParagraphForwardAndModifySelection } },
730 { "MoveUp", { canAlterCurrentSelection, execMoveUp } },
731 { "MoveUpAndModifySelection", { canAlterCurrentSelection, execMoveUpAndModifySelection } },
732 { "MoveWordBackward", { canAlterCurrentSelection, execMoveWordBackward } },
733 { "MoveWordBackwardAndModifySelection", { canAlterCurrentSelection, execMoveWordBackwardAndModifySelection } },
734 { "MoveWordForward", { canAlterCurrentSelection, execMoveWordForward } },
735 { "MoveWordForwardAndModifySelection", { canAlterCurrentSelection, execMoveWordForwardAndModifySelection } },
736 { "MoveWordLeft", { canAlterCurrentSelection, execMoveWordLeft } },
737 { "MoveWordLeftAndModifySelection", { canAlterCurrentSelection, execMoveWordLeftAndModifySelection } },
738 { "MoveWordRight", { canAlterCurrentSelection, execMoveWordRight } },
739 { "MoveWordRightAndModifySelection", { canAlterCurrentSelection, execMoveWordRightAndModifySelection } },
742 CommandMap* commandMap = new CommandMap;
744 const unsigned numCommands = sizeof(commands) / sizeof(commands[0]);
745 for (unsigned i = 0; i < numCommands; i++)
746 commandMap->set(commands[i].name, &commands[i].command);
750 // =============================================================================
752 // public editing commands
754 // =============================================================================
756 Editor::Editor(Frame* frame, PassRefPtr<EditorClient> client)
759 , m_deleteButtonController(new DeleteButtonController(frame))
767 bool Editor::execCommand(const String& command)
769 static CommandMap* commandMap;
771 commandMap = createCommandMap();
773 const Command* c = commandMap->get(command);
776 bool handled = false;
778 if (c->enabled(m_frame)) {
779 m_frame->document()->updateLayoutIgnorePendingStylesheets();
780 handled = c->exec(m_frame);
789 return; // DHTML did the whole operation
795 if (shouldDeleteRange(selectedRange())) {
796 writeSelectionToPasteboard(generalPasteboard());
797 deleteSelectionWithSmartDelete(canSmartCopyOrDelete());
804 return; // DHTML did the whole operation
809 writeSelectionToPasteboard(generalPasteboard());
815 return; // DHTML did the whole operation
819 pasteWithPasteboard(generalPasteboard(), true);
821 pasteAsPlainTextWithPasteboard(generalPasteboard());
824 void Editor::performDelete()
833 } // namespace WebCore