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