1 /* 2 * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21 #include "config.h" 22 #include "core/html/HTMLDetailsElement.h" 23 24 #include "HTMLNames.h" 25 #include "bindings/v8/ExceptionStatePlaceholder.h" 26 #include "core/dom/NodeRenderingContext.h" 27 #include "core/dom/Text.h" 28 #include "core/dom/shadow/ShadowRoot.h" 29 #include "core/html/HTMLSummaryElement.h" 30 #include "core/html/shadow/HTMLContentElement.h" 31 #include "core/platform/LocalizedStrings.h" 32 #include "core/rendering/RenderBlock.h" 33 34 namespace WebCore { 35 36 using namespace HTMLNames; 37 38 PassRefPtr<HTMLDetailsElement> HTMLDetailsElement::create(const QualifiedName& tagName, Document* document) 39 { 40 RefPtr<HTMLDetailsElement> details = adoptRef(new HTMLDetailsElement(tagName, document)); 41 details->ensureUserAgentShadowRoot(); 42 return details.release(); 43 } 44 45 HTMLDetailsElement::HTMLDetailsElement(const QualifiedName& tagName, Document* document) 46 : HTMLElement(tagName, document) 47 , m_isOpen(false) 48 { 49 ASSERT(hasTagName(detailsTag)); 50 ScriptWrappable::init(this); 51 } 52 53 RenderObject* HTMLDetailsElement::createRenderer(RenderStyle*) 54 { 55 return new RenderBlock(this); 56 } 57 58 void HTMLDetailsElement::didAddUserAgentShadowRoot(ShadowRoot* root) 59 { 60 DEFINE_STATIC_LOCAL(AtomicString, summarySelector, ("summary:first-of-type", AtomicString::ConstructFromLiteral)); 61 62 RefPtr<HTMLSummaryElement> defaultSummary = HTMLSummaryElement::create(summaryTag, document()); 63 defaultSummary->appendChild(Text::create(document(), defaultDetailsSummaryText()), ASSERT_NO_EXCEPTION); 64 65 RefPtr<HTMLContentElement> content = HTMLContentElement::create(document()); 66 content->setAttribute(selectAttr, summarySelector); 67 content->appendChild(defaultSummary); 68 69 root->appendChild(content, ASSERT_NO_EXCEPTION, AttachLazily); 70 root->appendChild(HTMLContentElement::create(document()), ASSERT_NO_EXCEPTION, AttachLazily); 71 } 72 73 Element* HTMLDetailsElement::findMainSummary() const 74 { 75 for (Node* child = firstChild(); child; child = child->nextSibling()) { 76 if (child->hasTagName(summaryTag)) 77 return toElement(child); 78 } 79 80 HTMLContentElement* content = toHTMLContentElement(userAgentShadowRoot()->firstChild()); 81 ASSERT(content->firstChild() && content->firstChild()->hasTagName(summaryTag)); 82 return toElement(content->firstChild()); 83 } 84 85 void HTMLDetailsElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 86 { 87 if (name == openAttr) { 88 bool oldValue = m_isOpen; 89 m_isOpen = !value.isNull(); 90 if (oldValue != m_isOpen) 91 lazyReattachIfAttached(); 92 } else 93 HTMLElement::parseAttribute(name, value); 94 } 95 96 bool HTMLDetailsElement::childShouldCreateRenderer(const NodeRenderingContext& childContext) const 97 { 98 if (m_isOpen) 99 return HTMLElement::childShouldCreateRenderer(childContext); 100 if (!childContext.node()->hasTagName(summaryTag)) 101 return false; 102 return childContext.node() == findMainSummary() && HTMLElement::childShouldCreateRenderer(childContext); 103 } 104 105 void HTMLDetailsElement::toggleOpen() 106 { 107 setAttribute(openAttr, m_isOpen ? nullAtom : emptyAtom); 108 } 109 110 } 111