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