TEST_F(EditingUtilitiesTest, enclosingNodeOfType)
{
    const char* bodyContent = "<p id='host'><b id='one'>11</b></p>";
    const char* shadowContent = "<content select=#two></content><div id='three'><content select=#one></div></content>";
    setBodyContent(bodyContent);
    RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = setShadowContent(shadowContent, "host");
    updateLayoutAndStyleForPainting();
    Node* host = document().getElementById("host");
    Node* one = document().getElementById("one");
    Node* three = shadowRoot->getElementById("three");

    EXPECT_EQ(host, enclosingNodeOfType(Position(one, 0), isEnclosingBlock));
    EXPECT_EQ(three, enclosingNodeOfType(PositionInComposedTree(one, 0), isEnclosingBlock));
}
void AppendNodeCommand::doApply()
{
    ASSERT(m_childToAppend);
    ASSERT(m_parentNode);
    // If the child to append is already in a tree, appending it will remove it from it's old location
    // in an non-undoable way.  We might eventually find it useful to do an undoable remove in this case.
    ASSERT(!m_childToAppend->parent());
    ASSERT(enclosingNodeOfType(Position(m_parentNode.get(), 0), &isContentEditable) || !m_parentNode->attached());

    ExceptionCode ec = 0;
    m_parentNode->appendChild(m_childToAppend.get(), ec);
    ASSERT(ec == 0);
}
void InsertNodeBeforeCommand::doApply()
{
    ASSERT(m_insertChild);
    ASSERT(m_refChild);
    ASSERT(m_refChild->parentNode());
    // If the child to insert is already in a tree, inserting it will remove it from it's old location
    // in an non-undoable way.  We might eventually find it useful to do an undoable remove in this case.
    ASSERT(!m_insertChild->parent());
    ASSERT(enclosingNodeOfType(Position(m_refChild->parentNode(), 0), &isContentEditable) || !m_refChild->parentNode()->attached());

    ExceptionCode ec = 0;
    m_refChild->parentNode()->insertBefore(m_insertChild.get(), m_refChild.get(), ec);
    ASSERT(ec == 0);
}
Beispiel #4
0
static HTMLElement* highestAncestorToWrapMarkup(
    const PositionTemplate<Strategy>& startPosition,
    const PositionTemplate<Strategy>& endPosition,
    EAnnotateForInterchange shouldAnnotate,
    Node* constrainingAncestor) {
  Node* firstNode = startPosition.nodeAsRangeFirstNode();
  // For compatibility reason, we use container node of start and end
  // positions rather than first node and last node in selection.
  Node* commonAncestor =
      Strategy::commonAncestor(*startPosition.computeContainerNode(),
                               *endPosition.computeContainerNode());
  DCHECK(commonAncestor);
  HTMLElement* specialCommonAncestor = nullptr;
  if (shouldAnnotate == AnnotateForInterchange) {
    // Include ancestors that aren't completely inside the range but are
    // required to retain the structure and appearance of the copied markup.
    specialCommonAncestor =
        ancestorToRetainStructureAndAppearance(commonAncestor);
    if (Node* parentListNode = enclosingNodeOfType(
            firstPositionInOrBeforeNode(firstNode), isListItem)) {
      EphemeralRangeTemplate<Strategy> markupRange =
          EphemeralRangeTemplate<Strategy>(startPosition, endPosition);
      EphemeralRangeTemplate<Strategy> nodeRange = normalizeRange(
          EphemeralRangeTemplate<Strategy>::rangeOfContents(*parentListNode));
      if (nodeRange == markupRange) {
        ContainerNode* ancestor = parentListNode->parentNode();
        while (ancestor && !isHTMLListElement(ancestor))
          ancestor = ancestor->parentNode();
        specialCommonAncestor = toHTMLElement(ancestor);
      }
    }

    // Retain the Mail quote level by including all ancestor mail block quotes.
    if (HTMLQuoteElement* highestMailBlockquote =
            toHTMLQuoteElement(highestEnclosingNodeOfType(
                firstPositionInOrBeforeNode(firstNode),
                isMailHTMLBlockquoteElement, CanCrossEditingBoundary)))
      specialCommonAncestor = highestMailBlockquote;
  }

  Node* checkAncestor =
      specialCommonAncestor ? specialCommonAncestor : commonAncestor;
  if (checkAncestor->layoutObject()) {
    HTMLElement* newSpecialCommonAncestor =
        toHTMLElement(highestEnclosingNodeOfType(
            Position::firstPositionInNode(checkAncestor),
            &isPresentationalHTMLElement, CanCrossEditingBoundary,
            constrainingAncestor));
    if (newSpecialCommonAncestor)
      specialCommonAncestor = newSpecialCommonAncestor;
  }

  // If a single tab is selected, commonAncestor will be a text node inside a
  // tab span. If two or more tabs are selected, commonAncestor will be the tab
  // span. In either case, if there is a specialCommonAncestor already, it will
  // necessarily be above any tab span that needs to be included.
  if (!specialCommonAncestor && isTabHTMLSpanElementTextNode(commonAncestor))
    specialCommonAncestor =
        toHTMLSpanElement(Strategy::parent(*commonAncestor));
  if (!specialCommonAncestor && isTabHTMLSpanElement(commonAncestor))
    specialCommonAncestor = toHTMLSpanElement(commonAncestor);

  if (HTMLAnchorElement* enclosingAnchor =
          toHTMLAnchorElement(enclosingElementWithTag(
              Position::firstPositionInNode(specialCommonAncestor
                                                ? specialCommonAncestor
                                                : commonAncestor),
              aTag)))
    specialCommonAncestor = enclosingAnchor;

  return specialCommonAncestor;
}
Beispiel #5
0
static inline HTMLElement*
ancestorToRetainStructureAndAppearanceWithNoLayoutObject(Node* commonAncestor) {
  HTMLElement* commonAncestorBlock = toHTMLElement(enclosingNodeOfType(
      firstPositionInOrBeforeNode(commonAncestor), isHTMLBlockElement));
  return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock);
}