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