WMLCardElement.cpp revision 5f1ab04193ad0130ca8204aadaceae083aca9881
1/* 2 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 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 23#if ENABLE(WML) 24#include "WMLCardElement.h" 25 26#include "Frame.h" 27#include "FrameLoader.h" 28#include "HTMLNames.h" 29#include "MappedAttribute.h" 30#include "NodeList.h" 31#include "RenderStyle.h" 32#include "WMLDocument.h" 33#include "WMLDoElement.h" 34#include "WMLInputElement.h" 35#include "WMLIntrinsicEventHandler.h" 36#include "WMLNames.h" 37#include "WMLTemplateElement.h" 38#include "WMLTimerElement.h" 39#include "WMLVariables.h" 40 41namespace WebCore { 42 43using namespace WMLNames; 44 45WMLCardElement::WMLCardElement(const QualifiedName& tagName, Document* doc) 46 : WMLElement(tagName, doc) 47 , m_isNewContext(false) 48 , m_isOrdered(false) 49 , m_isVisible(false) 50 , m_eventTimer(0) 51 , m_template(0) 52{ 53 ASSERT(hasTagName(cardTag)); 54} 55 56WMLCardElement::~WMLCardElement() 57{ 58} 59 60void WMLCardElement::showCard() 61{ 62 ASSERT(attached()); 63 64 if (m_isVisible) { 65 ASSERT(renderer()); 66 return; 67 } 68 69 m_isVisible = true; 70 ASSERT(!renderer()); 71 72 detach(); 73 attach(); 74 75 ASSERT(attached()); 76 ASSERT(renderer()); 77} 78 79void WMLCardElement::hideCard() 80{ 81 ASSERT(attached()); 82 83 if (!m_isVisible) { 84 ASSERT(!renderer()); 85 return; 86 } 87 88 m_isVisible = false; 89 ASSERT(renderer()); 90 91 detach(); 92 attach(); 93 94 ASSERT(attached()); 95 ASSERT(!renderer()); 96} 97 98void WMLCardElement::setTemplateElement(WMLTemplateElement* temp) 99{ 100 // Only one template is allowed to be attached to a card 101 if (m_template) { 102 reportWMLError(document(), WMLErrorMultipleTemplateElements); 103 return; 104 } 105 106 m_template = temp; 107} 108 109void WMLCardElement::setIntrinsicEventTimer(WMLTimerElement* timer) 110{ 111 // Only one timer is allowed in a card 112 if (m_eventTimer) { 113 reportWMLError(document(), WMLErrorMultipleTimerElements); 114 return; 115 } 116 117 m_eventTimer = timer; 118} 119 120void WMLCardElement::handleIntrinsicEventIfNeeded() 121{ 122 WMLPageState* pageState = wmlPageStateForDocument(document()); 123 if (!pageState) 124 return; 125 126 Frame* frame = document()->frame(); 127 if (!frame) 128 return; 129 130 FrameLoader* loader = frame->loader(); 131 if (!loader) 132 return; 133 134 int currentHistoryLength = loader->getHistoryLength(); 135 int lastHistoryLength = pageState->historyLength(); 136 137 // Calculate the entry method of current card 138 WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown; 139 if (lastHistoryLength > currentHistoryLength) 140 eventType = WMLIntrinsicEventOnEnterBackward; 141 else if (lastHistoryLength < currentHistoryLength) 142 eventType = WMLIntrinsicEventOnEnterForward; 143 144 // Synchronize history length with WMLPageState 145 pageState->setHistoryLength(currentHistoryLength); 146 147 // Figure out target event handler 148 WMLIntrinsicEventHandler* eventHandler = this->eventHandler(); 149 bool hasIntrinsicEvent = false; 150 151 if (eventType != WMLIntrinsicEventUnknown) { 152 if (eventHandler && eventHandler->hasIntrinsicEvent(eventType)) 153 hasIntrinsicEvent = true; 154 else if (m_template) { 155 eventHandler = m_template->eventHandler(); 156 if (eventHandler && eventHandler->hasIntrinsicEvent(eventType)) 157 hasIntrinsicEvent = true; 158 } 159 } 160 161 if (hasIntrinsicEvent) 162 eventHandler->triggerIntrinsicEvent(eventType); 163 164 // Start the timer if it exists in current card 165 if (m_eventTimer) 166 m_eventTimer->start(); 167 168 // FIXME: Initialize select elements in this card 169 for (Node* node = traverseNextNode(); node != 0; node = node->traverseNextNode()) { 170 if (!node->isElementNode()) 171 continue; 172 173 if (node->hasTagName(inputTag)) 174 static_cast<WMLInputElement*>(node)->initialize(); 175 /* 176 else if (node->hasTagName(selectTag)) 177 static_cast<WMLSelectElement*>(node)->selectInitialOptions(); 178 */ 179 } 180} 181 182void WMLCardElement::handleDeckLevelTaskOverridesIfNeeded() 183{ 184 // Spec: The event-handling element may appear inside a template element and specify 185 // event-processing behaviour for all cards in the deck. A deck-level event-handling 186 // element is equivalent to specifying the event-handling element in each card. 187 if (!m_template) 188 return; 189 190 Vector<WMLDoElement*>& templateDoElements = m_template->doElements(); 191 if (templateDoElements.isEmpty()) 192 return; 193 194 Vector<WMLDoElement*>& cardDoElements = doElements(); 195 Vector<WMLDoElement*>::iterator it = cardDoElements.begin(); 196 Vector<WMLDoElement*>::iterator end = cardDoElements.end(); 197 198 HashSet<String> cardDoElementNames; 199 for (; it != end; ++it) 200 cardDoElementNames.add((*it)->name()); 201 202 it = templateDoElements.begin(); 203 end = templateDoElements.end(); 204 205 for (; it != end; ++it) 206 (*it)->setActive(!cardDoElementNames.contains((*it)->name())); 207} 208 209void WMLCardElement::parseMappedAttribute(MappedAttribute* attr) 210{ 211 WMLIntrinsicEventType eventType = WMLIntrinsicEventUnknown; 212 213 if (attr->name() == onenterforwardAttr) 214 eventType = WMLIntrinsicEventOnEnterForward; 215 else if (attr->name() == onenterbackwardAttr) 216 eventType = WMLIntrinsicEventOnEnterBackward; 217 else if (attr->name() == ontimerAttr) 218 eventType = WMLIntrinsicEventOnTimer; 219 else if (attr->name() == newcontextAttr) 220 m_isNewContext = (attr->value() == "true"); 221 else if (attr->name() == orderedAttr) 222 m_isOrdered = (attr->value() == "true"); 223 else { 224 WMLElement::parseMappedAttribute(attr); 225 return; 226 } 227 228 if (eventType == WMLIntrinsicEventUnknown) 229 return; 230 231 // Register intrinsic event in card 232 RefPtr<WMLIntrinsicEvent> event = WMLIntrinsicEvent::create(document(), attr->value()); 233 234 createEventHandlerIfNeeded(); 235 eventHandler()->registerIntrinsicEvent(eventType, event); 236} 237 238void WMLCardElement::insertedIntoDocument() 239{ 240 WMLElement::insertedIntoDocument(); 241 242 // The first card inserted into a document, is visible by default. 243 if (!m_isVisible) { 244 RefPtr<NodeList> nodeList = document()->getElementsByTagName("card"); 245 if (nodeList && nodeList->length() == 1 && nodeList->item(0) == this) 246 m_isVisible = true; 247 } 248} 249 250RenderObject* WMLCardElement::createRenderer(RenderArena* arena, RenderStyle* style) 251{ 252 if (!m_isVisible) { 253 style->setUnique(); 254 style->setDisplay(NONE); 255 } 256 257 return WMLElement::createRenderer(arena, style); 258} 259 260WMLCardElement* WMLCardElement::findNamedCardInDocument(Document* doc, const String& cardName) 261{ 262 if (cardName.isEmpty()) 263 return 0; 264 265 RefPtr<NodeList> nodeList = doc->getElementsByTagName("card"); 266 if (!nodeList) 267 return 0; 268 269 unsigned length = nodeList->length(); 270 if (length < 1) 271 return 0; 272 273 for (unsigned i = 0; i < length; ++i) { 274 WMLCardElement* card = static_cast<WMLCardElement*>(nodeList->item(i)); 275 if (card->getIDAttribute() != cardName) 276 continue; 277 278 return card; 279 } 280 281 return 0; 282} 283 284WMLCardElement* WMLCardElement::determineActiveCard(Document* doc) 285{ 286 WMLPageState* pageState = wmlPageStateForDocument(doc); 287 if (!pageState) 288 return 0; 289 290 RefPtr<NodeList> nodeList = doc->getElementsByTagName("card"); 291 if (!nodeList) 292 return 0; 293 294 unsigned length = nodeList->length(); 295 if (length < 1) 296 return 0; 297 298 // Figure out the new target card 299 String cardName = doc->url().ref(); 300 301 WMLCardElement* activeCard = findNamedCardInDocument(doc, cardName); 302 if (activeCard) { 303 // Hide all cards - except the destination card - in document 304 for (unsigned i = 0; i < length; ++i) { 305 WMLCardElement* card = static_cast<WMLCardElement*>(nodeList->item(i)); 306 307 if (card == activeCard) 308 card->showCard(); 309 else 310 card->hideCard(); 311 } 312 } else { 313 // If the target URL didn't contain a fragment identifier, activeCard 314 // is 0, and has to be set to the first card element in the deck. 315 activeCard = static_cast<WMLCardElement*>(nodeList->item(0)); 316 activeCard->showCard(); 317 } 318 319 // Assure destination card is visible 320 ASSERT(activeCard->isVisible()); 321 ASSERT(activeCard->attached()); 322 ASSERT(activeCard->renderer()); 323 324 // Update the document title 325 doc->setTitle(activeCard->title()); 326 327 // Set the active activeCard in the WMLPageState object 328 pageState->setActiveCard(activeCard); 329 return activeCard; 330} 331 332} 333 334#endif 335