1/* 2 * Copyright (C) 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 "HTMLSummaryElement.h" 23 24#if ENABLE(DETAILS_ELEMENT) 25#include "DetailsMarkerControl.h" 26#include "HTMLDetailsElement.h" 27#include "InsertionPoint.h" 28#include "KeyboardEvent.h" 29#include "MouseEvent.h" 30#include "NodeRenderingTraversal.h" 31#include "PlatformMouseEvent.h" 32#include "RenderBlockFlow.h" 33 34namespace WebCore { 35 36using namespace HTMLNames; 37 38class SummaryContentElement : public InsertionPoint { 39public: 40 static PassRefPtr<SummaryContentElement> create(Document&); 41 42private: 43 SummaryContentElement(Document& document) 44 : InsertionPoint(webkitShadowContentTag, document) 45 { 46 } 47}; 48 49PassRefPtr<SummaryContentElement> SummaryContentElement::create(Document& document) 50{ 51 return adoptRef(new SummaryContentElement(document)); 52} 53 54PassRefPtr<HTMLSummaryElement> HTMLSummaryElement::create(const QualifiedName& tagName, Document& document) 55{ 56 RefPtr<HTMLSummaryElement> summary = adoptRef(new HTMLSummaryElement(tagName, document)); 57 summary->ensureUserAgentShadowRoot(); 58 return summary.release(); 59} 60 61HTMLSummaryElement::HTMLSummaryElement(const QualifiedName& tagName, Document& document) 62 : HTMLElement(tagName, document) 63{ 64 ASSERT(hasTagName(summaryTag)); 65} 66 67RenderPtr<RenderElement> HTMLSummaryElement::createElementRenderer(PassRef<RenderStyle> style) 68{ 69 return createRenderer<RenderBlockFlow>(*this, WTF::move(style)); 70} 71 72bool HTMLSummaryElement::childShouldCreateRenderer(const Node& child) const 73{ 74 if (child.isPseudoElement()) 75 return HTMLElement::childShouldCreateRenderer(child); 76 77 return hasShadowRootOrActiveInsertionPointParent(child) && HTMLElement::childShouldCreateRenderer(child); 78} 79 80void HTMLSummaryElement::didAddUserAgentShadowRoot(ShadowRoot* root) 81{ 82 root->appendChild(DetailsMarkerControl::create(document()), ASSERT_NO_EXCEPTION); 83 root->appendChild(SummaryContentElement::create(document()), ASSERT_NO_EXCEPTION); 84} 85 86HTMLDetailsElement* HTMLSummaryElement::detailsElement() const 87{ 88 Node* mayDetails = NodeRenderingTraversal::parent(this); 89 if (!mayDetails || !mayDetails->hasTagName(detailsTag)) 90 return 0; 91 return toHTMLDetailsElement(mayDetails); 92} 93 94bool HTMLSummaryElement::isMainSummary() const 95{ 96 if (HTMLDetailsElement* details = detailsElement()) 97 return details->findMainSummary() == this; 98 99 return false; 100} 101 102static bool isClickableControl(Node* node) 103{ 104 if (!node->isElementNode()) 105 return false; 106 Element* element = toElement(node); 107 if (element->isFormControlElement()) 108 return true; 109 Element* host = element->shadowHost(); 110 return host && host->isFormControlElement(); 111} 112 113bool HTMLSummaryElement::supportsFocus() const 114{ 115 return isMainSummary(); 116} 117 118void HTMLSummaryElement::defaultEventHandler(Event* event) 119{ 120 if (isMainSummary() && renderer()) { 121 if (event->type() == eventNames().DOMActivateEvent && !isClickableControl(event->target()->toNode())) { 122 if (HTMLDetailsElement* details = detailsElement()) 123 details->toggleOpen(); 124 event->setDefaultHandled(); 125 return; 126 } 127 128 if (event->isKeyboardEvent()) { 129 if (event->type() == eventNames().keydownEvent && toKeyboardEvent(event)->keyIdentifier() == "U+0020") { 130 setActive(true, true); 131 // No setDefaultHandled() - IE dispatches a keypress in this case. 132 return; 133 } 134 if (event->type() == eventNames().keypressEvent) { 135 switch (toKeyboardEvent(event)->charCode()) { 136 case '\r': 137 dispatchSimulatedClick(event); 138 event->setDefaultHandled(); 139 return; 140 case ' ': 141 // Prevent scrolling down the page. 142 event->setDefaultHandled(); 143 return; 144 } 145 } 146 if (event->type() == eventNames().keyupEvent && toKeyboardEvent(event)->keyIdentifier() == "U+0020") { 147 if (active()) 148 dispatchSimulatedClick(event); 149 event->setDefaultHandled(); 150 return; 151 } 152 } 153 } 154 155 HTMLElement::defaultEventHandler(event); 156} 157 158bool HTMLSummaryElement::willRespondToMouseClickEvents() 159{ 160 if (isMainSummary() && renderer()) 161 return true; 162 163 return HTMLElement::willRespondToMouseClickEvents(); 164} 165 166} 167 168#endif 169