bool CaretBase::shouldRepaintCaret(Node& node) const { // If PositionAnchorType::BeforeAnchor or PositionAnchorType::AfterAnchor, // carets need to be repainted not only when the node is contentEditable but // also when its parentNode() is contentEditable. node.document().updateStyleAndLayoutTree(); return hasEditableStyle(node) || (node.parentNode() && hasEditableStyle(*node.parentNode())); }
void InsertNodeBeforeCommand::doApply(EditingState*) { ContainerNode* parent = m_refChild->parentNode(); document().updateStyleAndLayoutTree(); if (!parent || (m_shouldAssumeContentIsAlwaysEditable == DoNotAssumeContentIsAlwaysEditable && !hasEditableStyle(*parent))) return; DCHECK(hasEditableStyle(*parent)) << parent; parent->insertBefore(m_insertChild.get(), m_refChild.get(), IGNORE_EXCEPTION); }
bool SVGAElement::canStartSelection() const { if (!isLink()) return SVGElement::canStartSelection(); return hasEditableStyle(); }
void HTMLAnchorElement::defaultEventHandler(Event* event) { if (isLink()) { if (focused() && isEnterKeyKeydownEvent(event) && treatLinkAsLiveForEventType(NonMouseEvent)) { event->setDefaultHandled(); dispatchSimulatedClick(event); return; } if (isLinkClick(event) && treatLinkAsLiveForEventType(eventType(event))) { handleClick(event); return; } if (hasEditableStyle()) { // This keeps track of the editable block that the selection was in (if it was in one) just before the link was clicked // for the LiveWhenNotFocused editable link behavior if (event->type() == eventNames().mousedownEvent && event->isMouseEvent() && toMouseEvent(event)->button() != RightButton && document().frame()) { setRootEditableElementForSelectionOnMouseDown(document().frame()->selection().selection().rootEditableElement()); m_wasShiftKeyDownOnMouseDown = toMouseEvent(event)->shiftKey(); } else if (event->type() == eventNames().mouseoverEvent) { // These are cleared on mouseover and not mouseout because their values are needed for drag events, // but drag events happen after mouse out events. clearRootEditableElementForSelectionOnMouseDown(); m_wasShiftKeyDownOnMouseDown = false; } } } HTMLElement::defaultEventHandler(event); }
void InsertNodeBeforeCommand::doUnapply() { document().updateStyleAndLayoutTree(); if (!hasEditableStyle(*m_insertChild)) return; m_insertChild->remove(IGNORE_EXCEPTION); }
bool HTMLAnchorElement::treatLinkAsLiveForEventType(EventType eventType) const { if (!hasEditableStyle()) return true; Settings* settings = document().settings(); if (!settings) return true; switch (settings->editableLinkBehavior()) { case EditableLinkDefaultBehavior: case EditableLinkAlwaysLive: return true; case EditableLinkNeverLive: return false; // If the selection prior to clicking on this link resided in the same editable block as this link, // and the shift key isn't pressed, we don't want to follow the link. case EditableLinkLiveWhenNotFocused: return eventType == MouseEventWithShiftKey || (eventType == MouseEventWithoutShiftKey && rootEditableElementForSelectionOnMouseDown() != rootEditableElement()); case EditableLinkOnlyLiveWithShiftKey: return eventType == MouseEventWithShiftKey; } ASSERT_NOT_REACHED(); return false; }
void InsertIntoTextNodeCommand::doUnapply() { if (!hasEditableStyle(*m_node)) return; m_node->deleteData(m_offset, m_text.length(), IGNORE_EXCEPTION); document().updateStyleAndLayout(); }
void HTMLAnchorElement::setActive(bool down, bool pause) { if (hasEditableStyle()) { EditableLinkBehavior editableLinkBehavior = EditableLinkDefaultBehavior; if (Settings* settings = document().settings()) editableLinkBehavior = settings->editableLinkBehavior(); switch (editableLinkBehavior) { default: case EditableLinkDefaultBehavior: case EditableLinkAlwaysLive: break; case EditableLinkNeverLive: return; // Don't set the link to be active if the current selection is in the same editable block as // this link case EditableLinkLiveWhenNotFocused: if (down && document().frame() && document().frame()->selection().selection().rootEditableElement() == rootEditableElement()) return; break; case EditableLinkOnlyLiveWithShiftKey: return; } } HTMLElement::setActive(down, pause); }
void SplitElementCommand::executeApply() { if (m_atChild->parentNode() != m_element2) return; HeapVector<Member<Node>> children; for (Node* node = m_element2->firstChild(); node != m_atChild; node = node->nextSibling()) children.append(node); DummyExceptionStateForTesting exceptionState; ContainerNode* parent = m_element2->parentNode(); if (!parent || !hasEditableStyle(*parent)) return; parent->insertBefore(m_element1.get(), m_element2.get(), exceptionState); if (exceptionState.hadException()) return; // Delete id attribute from the second element because the same id cannot be // used for more than one element m_element2->removeAttribute(HTMLNames::idAttr); for (const auto& child : children) m_element1->appendChild(child, exceptionState); }
bool HTMLAnchorElement::supportsFocus() const { if (hasEditableStyle()) return HTMLElement::supportsFocus(); // If not a link we should still be able to focus the element if it has tabIndex. return isLink() || HTMLElement::supportsFocus(); }
bool SVGAElement::supportsFocus() const { if (hasEditableStyle()) return SVGGraphicsElement::supportsFocus(); // If not a link we should still be able to focus the element if it has a tabIndex. return isLink() || Element::supportsFocus(); }
void WrapContentsInDummySpanCommand::doReapply() { DCHECK(m_element); if (!m_dummySpan || !hasEditableStyle(*m_element)) return; executeApply(); }
void DeleteFromTextNodeCommand::doUnapply() { DCHECK(m_node); if (!hasEditableStyle(*m_node)) return; m_node->insertData(m_offset, m_text, IGNORE_EXCEPTION); m_node->document().updateStyleAndLayout(); }
void SplitElementCommand::doUnapply() { if (!m_element1 || !hasEditableStyle(*m_element1) || !hasEditableStyle(*m_element2)) return; NodeVector children; getChildNodes(*m_element1, children); Node* refChild = m_element2->firstChild(); for (const auto& child : children) m_element2->insertBefore(child, refChild, IGNORE_EXCEPTION); // Recover the id attribute of the original element. const AtomicString& id = m_element1->getAttribute(HTMLNames::idAttr); if (!id.isNull()) m_element2->setAttribute(HTMLNames::idAttr, id); m_element1->remove(IGNORE_EXCEPTION); }
void WrapContentsInDummySpanCommand::doUnapply() { DCHECK(m_element); if (!m_dummySpan || !hasEditableStyle(*m_element)) return; NodeVector children; getChildNodes(*m_dummySpan, children); for (auto& child : children) m_element->appendChild(child.release(), IGNORE_EXCEPTION); m_dummySpan->remove(IGNORE_EXCEPTION); }
void DeleteFromTextNodeCommand::doApply(EditingState*) { DCHECK(m_node); document().updateStyleAndLayoutTree(); if (!hasEditableStyle(*m_node)) return; TrackExceptionState exceptionState; m_text = m_node->substringData(m_offset, m_count, exceptionState); if (exceptionState.hadException()) return; m_node->deleteData(m_offset, m_count, exceptionState); m_node->document().updateStyleAndLayout(); }
InsertNodeBeforeCommand::InsertNodeBeforeCommand( Node* insertChild, Node* refChild, ShouldAssumeContentIsAlwaysEditable shouldAssumeContentIsAlwaysEditable) : SimpleEditCommand(refChild->document()), m_insertChild(insertChild), m_refChild(refChild), m_shouldAssumeContentIsAlwaysEditable( shouldAssumeContentIsAlwaysEditable) { DCHECK(m_insertChild); DCHECK(!m_insertChild->parentNode()) << m_insertChild; DCHECK(m_refChild); DCHECK(m_refChild->parentNode()) << m_refChild; DCHECK(hasEditableStyle(*m_refChild->parentNode()) || !m_refChild->parentNode()->inActiveDocument()) << m_refChild->parentNode(); }
void InsertIntoTextNodeCommand::doApply(EditingState*) { bool passwordEchoEnabled = document().settings() && document().settings()->passwordEchoEnabled(); if (passwordEchoEnabled) document().updateStyleAndLayoutIgnorePendingStylesheets(); if (!hasEditableStyle(*m_node)) return; if (passwordEchoEnabled) { LayoutText* layoutText = m_node->layoutObject(); if (layoutText && layoutText->isSecure()) layoutText->momentarilyRevealLastTypedCharacter(m_offset + m_text.length() - 1); } m_node->insertData(m_offset, m_text, IGNORE_EXCEPTION); document().updateStyleAndLayout(); }
void RemoveNodePreservingChildrenCommand::doApply(EditingState* editingState) { ABORT_EDITING_COMMAND_IF(!m_node->parentNode()); ABORT_EDITING_COMMAND_IF(!hasEditableStyle(*m_node->parentNode())); if (m_node->isContainerNode()) { NodeVector children; getChildNodes(toContainerNode(*m_node), children); for (auto& currentChild : children) { Node* child = currentChild.release(); removeNode(child, editingState, m_shouldAssumeContentIsAlwaysEditable); if (editingState->isAborted()) return; insertNodeBefore(child, m_node, editingState, m_shouldAssumeContentIsAlwaysEditable); if (editingState->isAborted()) return; } } removeNode(m_node, editingState, m_shouldAssumeContentIsAlwaysEditable); }
void SplitTextNodeContainingElementCommand::doApply(EditingState*) { DCHECK(m_text); DCHECK_GT(m_offset, 0); splitTextNode(m_text.get(), m_offset); Element* parent = m_text->parentElement(); if (!parent || !parent->parentElement() || !hasEditableStyle(*parent->parentElement())) return; LayoutObject* parentLayoutObject = parent->layoutObject(); if (!parentLayoutObject || !parentLayoutObject->isInline()) { wrapContentsInDummySpan(parent); Node* firstChild = parent->firstChild(); if (!firstChild || !firstChild->isElementNode()) return; parent = toElement(firstChild); } splitElement(parent, m_text.get()); }
AtomicString getInputModeAttribute(Element* element) { if (!element) return AtomicString(); bool queryAttribute = false; if (isHTMLInputElement(*element)) { queryAttribute = toHTMLInputElement(*element).supportsInputModeAttribute(); } else if (isHTMLTextAreaElement(*element)) { queryAttribute = true; } else { element->document().updateStyleAndLayoutTree(); if (hasEditableStyle(*element)) queryAttribute = true; } if (!queryAttribute) return AtomicString(); // TODO(dtapuska): We may wish to restrict this to a yet to be proposed // <contenteditable> or <richtext> element Mozilla discussed at TPAC 2016. return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); }
bool HTMLAnchorElement::canStartSelection() const { return hasEditableStyle(); }
bool HTMLAnchorElement::isLiveLink() const { return !hasEditableStyle(); }
bool HTMLAnchorElement::supportsFocus() const { if (hasEditableStyle()) return HTMLElement::supportsFocus(); return true; }
bool HTMLAnchorElement::canStartSelection() const { if (!isLink()) return HTMLElement::canStartSelection(); return hasEditableStyle(); }
bool HTMLBodyElement::supportsFocus() const { // This override is needed because the inherited method bails if the parent is editable. // The <body> should be focusable even if <html> is editable. return hasEditableStyle() || HTMLElement::supportsFocus(); }
void CaretBase::invalidateCaretRect(Node* node) { node->document().updateStyleAndLayoutTree(); if (hasEditableStyle(*node)) invalidateLocalCaretRect(node, localCaretRectWithoutUpdate()); }