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