bool Editor::insertTextWithoutSendingTextEvent(const String& text, bool selectInsertedText, TextEvent* triggeringEvent) { if (text.isEmpty()) return false; VisibleSelection selection = selectionForCommand(triggeringEvent); if (!selection.isContentEditable()) return false; spellChecker().updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0])); // Get the selection to use for the event that triggered this insertText. // If the event handler changed the selection, we may want to use a different selection // that is contained in the event target. selection = selectionForCommand(triggeringEvent); if (selection.isContentEditable()) { if (Node* selectionStart = selection.start().deprecatedNode()) { RefPtr<Document> document(selectionStart->document()); // Insert the text TypingCommand::Options options = 0; if (selectInsertedText) options |= TypingCommand::SelectInsertedText; TypingCommand::insertText(*document.get(), text, selection, options, triggeringEvent && triggeringEvent->isComposition() ? TypingCommand::TextCompositionConfirm : TypingCommand::TextCompositionNone); // Reveal the current selection if (LocalFrame* editedFrame = document->frame()) { if (Page* page = editedFrame->page()) page->focusController().focusedOrMainFrame()->selection().revealSelection(ScrollAlignment::alignCenterIfNeeded); } } } return true; }
void Editor::replaceSelectionWithFragment(PassRefPtr<DocumentFragment> fragment, bool selectReplacement, bool smartReplace, bool matchStyle) { if (m_frame.selection().isNone() || !m_frame.selection().isContentEditable() || !fragment) return; ReplaceSelectionCommand::CommandOptions options = ReplaceSelectionCommand::PreventNesting; if (selectReplacement) options |= ReplaceSelectionCommand::SelectReplacement; if (smartReplace) options |= ReplaceSelectionCommand::SmartReplace; if (matchStyle) options |= ReplaceSelectionCommand::MatchStyle; ASSERT(m_frame.document()); ReplaceSelectionCommand::create(*m_frame.document(), fragment, options, EditActionPaste)->apply(); revealSelectionAfterEditingOperation(); if (m_frame.selection().isInPasswordField() || !spellChecker().isContinuousSpellCheckingEnabled()) return; spellChecker().chunkAndMarkAllMisspellingsAndBadGrammar(m_frame.selection().rootEditableElement()); }
bool Editor::executeCommand(const String& commandName) { // Specially handling commands that Editor::execCommand does not directly // support. if (commandName == "DeleteToEndOfParagraph") { if (!deleteWithDirection(DirectionForward, ParagraphBoundary, false)) deleteWithDirection(DirectionForward, CharacterGranularity, false); return true; } if (commandName == "DeleteBackward") return command(AtomicString("BackwardDelete")).execute(); if (commandName == "DeleteForward") return command(AtomicString("ForwardDelete")).execute(); if (commandName == "AdvanceToNextMisspelling") { // Wee need to pass false here or else the currently selected word will never be skipped. spellChecker().advanceToNextMisspelling(false); return true; } if (commandName == "ToggleSpellPanel") { spellChecker().showSpellingGuessPanel(); return true; } return command(commandName).execute(); }
bool Editor::executeCommand(const String& commandName, const String& value) { // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit for editable nodes. if (!canEdit() && commandName == "moveToBeginningOfDocument") return m_frame.eventHandler().bubblingScroll(ScrollUp, ScrollByDocument); if (!canEdit() && commandName == "moveToEndOfDocument") return m_frame.eventHandler().bubblingScroll(ScrollDown, ScrollByDocument); if (commandName == "showGuessPanel") { spellChecker().showSpellingGuessPanel(); return true; } return command(commandName).execute(value); }
TEST_F(HTMLTextFormControlElementTest, SpellCheckDoesNotCauseUpdateLayout) { HTMLInputElement* input = toHTMLInputElement(document().getElementById("input")); input->focus(); input->setValue("Hello, input field"); VisibleSelection oldSelection = document().frame()->selection().selection(); Position newPosition(input->innerEditorElement()->firstChild(), 3); VisibleSelection newSelection(newPosition, TextAffinity::Downstream); document().frame()->selection().setSelection(newSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle | FrameSelection::DoNotUpdateAppearance); ASSERT_EQ(3, input->selectionStart()); Persistent<SpellChecker> spellChecker(SpellChecker::create(page().frame())); forceLayoutFlag(); int startCount = layoutCount(); spellChecker->respondToChangedSelection(oldSelection, FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle); EXPECT_EQ(startCount, layoutCount()); }
void Editor::respondToChangedSelection(const VisibleSelection& oldSelection, FrameSelection::SetSelectionOptions options) { spellChecker().respondToChangedSelection(oldSelection, options); m_frame.inputMethodController().cancelCompositionIfSelectionIsInvalid(); notifyComponentsOnChangedSelection(oldSelection, options); }
void Editor::respondToChangedContents(const VisibleSelection& endingSelection) { spellChecker().updateMarkersForWordsAffectedByEditing(true); client().respondToChangedContents(); }