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
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
create(const QualifiedName & tagName,Document * document)58 PassRefPtr<WMLCardElement> WMLCardElement::create(const QualifiedName& tagName, Document* document)
59 {
60 return adoptRef(new WMLCardElement(tagName, document));
61 }
62
~WMLCardElement()63 WMLCardElement::~WMLCardElement()
64 {
65 }
66
showCard()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
hideCard()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
setTemplateElement(WMLTemplateElement * temp)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
setIntrinsicEventTimer(WMLTimerElement * timer)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
handleIntrinsicEventIfNeeded()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
handleDeckLevelTaskOverridesIfNeeded()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
parseMappedAttribute(Attribute * attr)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
insertedIntoDocument()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
createRenderer(RenderArena * arena,RenderStyle * style)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
findNamedCardInDocument(Document * doc,const String & cardName)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
determineActiveCard(Document * doc)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