Stop calling Element::ensureShadowRoot() if it is used in construction phase.
[WebKit-https.git] / Source / WebCore / html / HTMLDetailsElement.cpp
index c428695..d53a063 100644 (file)
 #include "config.h"
 #include "HTMLDetailsElement.h"
 
-#include "Frame.h"
+#if ENABLE(DETAILS)
+
+#include "HTMLContentElement.h"
 #include "HTMLNames.h"
+#include "HTMLSummaryElement.h"
+#include "LocalizedStrings.h"
 #include "MouseEvent.h"
-#include "PlatformMouseEvent.h"
 #include "RenderDetails.h"
+#include "ShadowRoot.h"
+#include "Text.h"
 
 namespace WebCore {
 
 using namespace HTMLNames;
 
+static const AtomicString& summaryQuerySelector()
+{
+    DEFINE_STATIC_LOCAL(AtomicString, selector, ("summary:first-of-type"));
+    return selector;
+};
+
+class DetailsContentElement : public HTMLContentElement {
+public:
+    static PassRefPtr<DetailsContentElement> create(Document*);
+
+private:
+    DetailsContentElement(Document* document)
+        : HTMLContentElement(HTMLNames::divTag, document)
+    {
+    }
+};
+
+PassRefPtr<DetailsContentElement> DetailsContentElement::create(Document* document)
+{
+    return adoptRef(new DetailsContentElement(document));
+}
+
+class DetailsSummaryElement : public HTMLContentElement {
+public:
+    static PassRefPtr<DetailsSummaryElement> create(Document*);
+
+    Element* fallbackSummary()
+    {
+        ASSERT(firstChild() && firstChild()->hasTagName(summaryTag));
+        return toElement(firstChild());
+    }
+
+private:
+    DetailsSummaryElement(Document* document)
+        : HTMLContentElement(HTMLNames::divTag, document)
+    {
+        setSelect(summaryQuerySelector());
+    }
+};
+
+PassRefPtr<DetailsSummaryElement> DetailsSummaryElement::create(Document* document)
+{
+    RefPtr<HTMLSummaryElement> defaultSummary = HTMLSummaryElement::create(summaryTag, document);
+    defaultSummary->appendChild(Text::create(document, defaultDetailsSummaryText()), ASSERT_NO_EXCEPTION);
+
+    RefPtr<DetailsSummaryElement> elem = adoptRef(new DetailsSummaryElement(document));
+    elem->appendChild(defaultSummary);
+    return elem.release();
+}
+
 PassRefPtr<HTMLDetailsElement> HTMLDetailsElement::create(const QualifiedName& tagName, Document* document)
 {
-    return adoptRef(new HTMLDetailsElement(tagName, document));
+    RefPtr<HTMLDetailsElement> elem = adoptRef(new HTMLDetailsElement(tagName, document));
+    elem->createShadowSubtree();
+
+    return elem.release();
 }
 
 HTMLDetailsElement::HTMLDetailsElement(const QualifiedName& tagName, Document* document)
     : HTMLElement(tagName, document)
-    , m_mainSummary(0)
     , m_isOpen(false)
 {
     ASSERT(hasTagName(detailsTag));
@@ -49,88 +106,52 @@ RenderObject* HTMLDetailsElement::createRenderer(RenderArena* arena, RenderStyle
     return new (arena) RenderDetails(this);
 }
 
-void HTMLDetailsElement::findMainSummary()
+void HTMLDetailsElement::createShadowSubtree()
 {
-    m_mainSummary = 0;
+    ASSERT(!shadowRoot());
 
-    for (Node* child = firstChild(); child; child = child->nextSibling()) {
-        if (child->hasTagName(summaryTag)) {
-            m_mainSummary = child;
-            break;
-        }
-    }
+    RefPtr<ShadowRoot> root = ShadowRoot::create(this, ASSERT_NO_EXCEPTION);
+    root->appendChild(DetailsSummaryElement::create(document()), ASSERT_NO_EXCEPTION, true);
+    root->appendChild(DetailsContentElement::create(document()), ASSERT_NO_EXCEPTION, true);
 }
 
-void HTMLDetailsElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
+Element* HTMLDetailsElement::findMainSummary() const
 {
-    HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
-    if (!changedByParser) {
-        Node* oldSummary = m_mainSummary;
-        findMainSummary();
-
-        if (oldSummary != m_mainSummary && !m_isOpen && attached()) {
-            if (oldSummary && oldSummary->attached())
-                oldSummary->detach();
-            if (m_mainSummary && childCountDelta < 0 && !m_mainSummary->renderer()) {
-                // If childCountDelta is less then zero and the main summary has changed it must be because previous main
-                // summary was removed. The new main summary was then inside the unrevealed content and needs to be
-                // reattached to create its renderer. If childCountDelta is not less then zero then a new <summary> element
-                // has been added and it will be attached without our help.
-                m_mainSummary->detach();
-                m_mainSummary->attach();
-            }
-        }
+    for (Node* child = firstChild(); child; child = child->nextSibling()) {
+        if (child->hasTagName(summaryTag))
+            return toElement(child);
     }
-}
 
-void HTMLDetailsElement::finishParsingChildren()
-{
-    HTMLElement::finishParsingChildren();
-    findMainSummary();
-    if (attached() && m_mainSummary && !m_mainSummary->renderer()) {
-        m_mainSummary->detach();
-        m_mainSummary->attach();
-    }
+    return static_cast<DetailsSummaryElement*>(shadowRoot()->firstChild())->fallbackSummary();
 }
 
-void HTMLDetailsElement::parseMappedAttribute(Attribute* attr)
+void HTMLDetailsElement::parseAttribute(Attribute* attr)
 {
     if (attr->name() == openAttr) {
         bool oldValue = m_isOpen;
         m_isOpen =  !attr->value().isNull();
-        if (attached() && oldValue != m_isOpen) {
-            detach();
-            attach();
-        }
+        if (oldValue != m_isOpen)
+            reattachIfAttached();
     } else
-        HTMLElement::parseMappedAttribute(attr);
+        HTMLElement::parseAttribute(attr);
 }
 
 bool HTMLDetailsElement::childShouldCreateRenderer(Node* child) const
 {
-    return m_isOpen || child == m_mainSummary;
-}
-
-void HTMLDetailsElement::defaultEventHandler(Event* event)
-{
-    HTMLElement::defaultEventHandler(event);
-
-    if (!renderer() || !renderer()->isDetails() || !event->isMouseEvent() || event->type() != eventNames().clickEvent || event->defaultHandled())
-        return;
-
-    MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
-    if (mouseEvent->button() != LeftButton)
-        return;
+    if (m_isOpen)
+        return true;
 
-    RenderDetails* renderDetails = static_cast<RenderDetails*>(renderer());
+    if (!child->hasTagName(summaryTag))
+        return false;
 
-    float factor = document() && document()->frame() ? document()->frame()->pageZoomFactor() : 1.0;
-    FloatPoint pos = renderDetails->absoluteToLocal(FloatPoint(mouseEvent->pageX() * factor, mouseEvent->pageY() * factor));
+    return child == findMainSummary();
+}
 
-    if (renderDetails->interactiveArea().contains(pos.x(), pos.y())) {
-        setAttribute(openAttr, m_isOpen ? String() : String(""));
-        event->setDefaultHandled();
-    }
+void HTMLDetailsElement::toggleOpen()
+{
+    setAttribute(openAttr, m_isOpen ? nullAtom : emptyAtom);
 }
 
 }
+
+#endif