• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 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 "WMLSelectElement.h"
25 
26 #include "Attribute.h"
27 #include "HTMLNames.h"
28 #include "OptionElement.h"
29 #include "RenderListBox.h"
30 #include "RenderMenuList.h"
31 #include "WMLDocument.h"
32 #include "WMLNames.h"
33 #include "WMLVariables.h"
34 #include <wtf/StdLibExtras.h>
35 #include <wtf/text/CString.h>
36 
37 namespace WebCore {
38 
39 using namespace WMLNames;
40 
WMLSelectElement(const QualifiedName & tagName,Document * document)41 WMLSelectElement::WMLSelectElement(const QualifiedName& tagName, Document* document)
42     : WMLFormControlElement(tagName, document)
43     , m_initialized(false)
44 {
45 }
46 
create(const QualifiedName & tagName,Document * document)47 PassRefPtr<WMLSelectElement> WMLSelectElement::create(const QualifiedName& tagName, Document* document)
48 {
49     return adoptRef(new WMLSelectElement(tagName, document));
50 }
51 
~WMLSelectElement()52 WMLSelectElement::~WMLSelectElement()
53 {
54 }
55 
formControlName() const56 const AtomicString& WMLSelectElement::formControlName() const
57 {
58     AtomicString name = this->name();
59     return name.isNull() ? emptyAtom : name;
60 }
61 
formControlType() const62 const AtomicString& WMLSelectElement::formControlType() const
63 {
64     DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple"));
65     DEFINE_STATIC_LOCAL(const AtomicString, selectOne, ("select-one"));
66     return m_data.multiple() ? selectMultiple : selectOne;
67 }
68 
isKeyboardFocusable(KeyboardEvent * event) const69 bool WMLSelectElement::isKeyboardFocusable(KeyboardEvent* event) const
70 {
71     if (renderer())
72         return isFocusable();
73 
74     return WMLFormControlElement::isKeyboardFocusable(event);
75 }
76 
isMouseFocusable() const77 bool WMLSelectElement::isMouseFocusable() const
78 {
79     if (renderer())
80         return isFocusable();
81 
82     return WMLFormControlElement::isMouseFocusable();
83 }
84 
selectAll()85 void WMLSelectElement::selectAll()
86 {
87     SelectElement::selectAll(m_data, this);
88 }
89 
recalcStyle(StyleChange change)90 void WMLSelectElement::recalcStyle(StyleChange change)
91 {
92     WMLFormControlElement::recalcStyle(change);
93 }
94 
dispatchFocusEvent()95 void WMLSelectElement::dispatchFocusEvent()
96 {
97     SelectElement::dispatchFocusEvent(m_data, this);
98     WMLFormControlElement::dispatchFocusEvent();
99 }
100 
dispatchBlurEvent()101 void WMLSelectElement::dispatchBlurEvent()
102 {
103     SelectElement::dispatchBlurEvent(m_data, this);
104     WMLFormControlElement::dispatchBlurEvent();
105 }
106 
selectedIndex() const107 int WMLSelectElement::selectedIndex() const
108 {
109     return SelectElement::selectedIndex(m_data, this);
110 }
111 
setSelectedIndex(int optionIndex,bool deselect)112 void WMLSelectElement::setSelectedIndex(int optionIndex, bool deselect)
113 {
114     SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, false, false);
115 }
116 
setSelectedIndexByUser(int optionIndex,bool deselect,bool fireOnChangeNow,bool allowMultipleSelection)117 void WMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow, bool allowMultipleSelection)
118 {
119     UNUSED_PARAM(allowMultipleSelection);
120     SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChangeNow, true);
121 }
122 
saveFormControlState(String & value) const123 bool WMLSelectElement::saveFormControlState(String& value) const
124 {
125     return SelectElement::saveFormControlState(m_data, this, value);
126 }
127 
restoreFormControlState(const String & state)128 void WMLSelectElement::restoreFormControlState(const String& state)
129 {
130     SelectElement::restoreFormControlState(m_data, this, state);
131 }
132 
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)133 void WMLSelectElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
134 {
135     SelectElement::setRecalcListItems(m_data, this);
136     WMLFormControlElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
137 }
138 
parseMappedAttribute(Attribute * attr)139 void WMLSelectElement::parseMappedAttribute(Attribute* attr)
140 {
141     if (attr->name() == HTMLNames::multipleAttr)
142         SelectElement::parseMultipleAttribute(m_data, this, attr);
143     else
144         WMLFormControlElement::parseMappedAttribute(attr);
145 }
146 
createRenderer(RenderArena * arena,RenderStyle *)147 RenderObject* WMLSelectElement::createRenderer(RenderArena* arena, RenderStyle*)
148 {
149     if (m_data.usesMenuList())
150         return new (arena) RenderMenuList(this);
151     return new (arena) RenderListBox(this);
152 }
153 
appendFormData(FormDataList & list,bool)154 bool WMLSelectElement::appendFormData(FormDataList& list, bool)
155 {
156     return SelectElement::appendFormData(m_data, this, list);
157 }
158 
optionToListIndex(int optionIndex) const159 int WMLSelectElement::optionToListIndex(int optionIndex) const
160 {
161     return SelectElement::optionToListIndex(m_data, this, optionIndex);
162 }
163 
listToOptionIndex(int listIndex) const164 int WMLSelectElement::listToOptionIndex(int listIndex) const
165 {
166     return SelectElement::listToOptionIndex(m_data, this, listIndex);
167 }
168 
reset()169 void WMLSelectElement::reset()
170 {
171     SelectElement::reset(m_data, this);
172 }
173 
defaultEventHandler(Event * event)174 void WMLSelectElement::defaultEventHandler(Event* event)
175 {
176     SelectElement::defaultEventHandler(m_data, this, event, 0);
177 
178     // FIXME: There must be a better place to update the page variable state. Investigate.
179     updateVariables();
180 
181     if (event->defaultHandled())
182         return;
183 
184     WMLFormControlElement::defaultEventHandler(event);
185 }
186 
accessKeyAction(bool sendToAnyElement)187 void WMLSelectElement::accessKeyAction(bool sendToAnyElement)
188 {
189     focus();
190     dispatchSimulatedClick(0, sendToAnyElement);
191 }
192 
setActiveSelectionAnchorIndex(int index)193 void WMLSelectElement::setActiveSelectionAnchorIndex(int index)
194 {
195     SelectElement::setActiveSelectionAnchorIndex(m_data, this, index);
196 }
197 
setActiveSelectionEndIndex(int index)198 void WMLSelectElement::setActiveSelectionEndIndex(int index)
199 {
200     SelectElement::setActiveSelectionEndIndex(m_data, index);
201 }
202 
updateListBoxSelection(bool deselectOtherOptions)203 void WMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
204 {
205     SelectElement::updateListBoxSelection(m_data, this, deselectOtherOptions);
206 }
207 
listBoxOnChange()208 void WMLSelectElement::listBoxOnChange()
209 {
210     SelectElement::listBoxOnChange(m_data, this);
211 }
212 
menuListOnChange()213 void WMLSelectElement::menuListOnChange()
214 {
215     SelectElement::menuListOnChange(m_data, this);
216 }
217 
activeSelectionStartListIndex() const218 int WMLSelectElement::activeSelectionStartListIndex() const
219 {
220     if (m_data.activeSelectionAnchorIndex() >= 0)
221         return m_data.activeSelectionAnchorIndex();
222     return optionToListIndex(selectedIndex());
223 }
224 
activeSelectionEndListIndex() const225 int WMLSelectElement::activeSelectionEndListIndex() const
226 {
227     if (m_data.activeSelectionEndIndex() >= 0)
228         return m_data.activeSelectionEndIndex();
229     return SelectElement::lastSelectedListIndex(m_data, this);
230 }
231 
accessKeySetSelectedIndex(int index)232 void WMLSelectElement::accessKeySetSelectedIndex(int index)
233 {
234     SelectElement::accessKeySetSelectedIndex(m_data, this, index);
235 }
236 
setRecalcListItems()237 void WMLSelectElement::setRecalcListItems()
238 {
239     SelectElement::setRecalcListItems(m_data, this);
240 }
241 
scrollToSelection()242 void WMLSelectElement::scrollToSelection()
243 {
244     SelectElement::scrollToSelection(m_data, this);
245 }
246 
selectInitialOptions()247 void WMLSelectElement::selectInitialOptions()
248 {
249     // Spec: Step 1 - the default option index is determined using iname and ivalue
250     calculateDefaultOptionIndices();
251 
252     if (m_defaultOptionIndices.isEmpty()) {
253         m_initialized = true;
254         return;
255     }
256 
257     // Spec: Step 2 – initialise variables
258     initializeVariables();
259 
260     // Spec: Step 3 – pre-select option(s) specified by the default option index
261     selectDefaultOptions();
262     m_initialized = true;
263 }
264 
insertedIntoTree(bool deep)265 void WMLSelectElement::insertedIntoTree(bool deep)
266 {
267     SelectElement::insertedIntoTree(m_data, this);
268     WMLFormControlElement::insertedIntoTree(deep);
269 }
270 
calculateDefaultOptionIndices()271 void WMLSelectElement::calculateDefaultOptionIndices()
272 {
273     WMLPageState* pageState = wmlPageStateForDocument(document());
274     if (!pageState)
275         return;
276 
277     String variable;
278 
279     // Spec: If the 'iname' attribute is specified and names a variable that is set,
280     // then the default option index is the validated value of that variable.
281     String iname = this->iname();
282     if (!iname.isEmpty()) {
283         variable = pageState->getVariable(iname);
284         if (!variable.isEmpty())
285             m_defaultOptionIndices = parseIndexValueString(variable);
286     }
287 
288     // Spec: If the default option index is empty and the 'ivalue' attribute is specified,
289     // then the default option index is the validated attribute value.
290     String ivalue = this->ivalue();
291     if (m_defaultOptionIndices.isEmpty() && !ivalue.isEmpty())
292         m_defaultOptionIndices = parseIndexValueString(ivalue);
293 
294     // Spec: If the default option index is empty, and the 'name' attribute is specified
295     // and the 'name' ttribute names a variable that is set, then for each value in the 'name'
296     // variable that is present as a value in the select's option elements, the index of the
297     // first option element containing that value is added to the default index if that
298     // index has not been previously added.
299     String name = this->name();
300     if (m_defaultOptionIndices.isEmpty() && !name.isEmpty()) {
301         variable = pageState->getVariable(name);
302         if (!variable.isEmpty())
303             m_defaultOptionIndices = valueStringToOptionIndices(variable);
304     }
305 
306     String value = parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr));
307 
308     // Spec: If the default option index is empty and the 'value' attribute is specified then
309     // for each  value in the 'value' attribute that is present as a value in the select's
310     // option elements, the index of the first option element containing that value is added
311     // to the default index if that index has not been previously added.
312     if (m_defaultOptionIndices.isEmpty() && !value.isEmpty())
313         m_defaultOptionIndices = valueStringToOptionIndices(value);
314 
315     // Spec: If the default option index is empty and the select is a multi-choice, then the
316     // default option index is set to zero. If the select is single-choice, then the default
317     // option index is set to one.
318     if (m_defaultOptionIndices.isEmpty())
319         m_defaultOptionIndices.append((unsigned) !m_data.multiple());
320 }
321 
selectDefaultOptions()322 void WMLSelectElement::selectDefaultOptions()
323 {
324     ASSERT(!m_defaultOptionIndices.isEmpty());
325 
326     if (!m_data.multiple()) {
327         setSelectedIndex(m_defaultOptionIndices.first() - 1, false);
328         return;
329     }
330 
331     Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end();
332     for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it)
333         setSelectedIndex((*it) - 1, false);
334 }
335 
initializeVariables()336 void WMLSelectElement::initializeVariables()
337 {
338     ASSERT(!m_defaultOptionIndices.isEmpty());
339 
340     WMLPageState* pageState = wmlPageStateForDocument(document());
341     if (!pageState)
342         return;
343 
344     const Vector<Element*>& items = m_data.listItems(this);
345     if (items.isEmpty())
346         return;
347 
348     // Spec: If the 'iname' attribute is specified, then the named variable is set with the default option index.
349     String iname = this->iname();
350     if (!iname.isEmpty())
351         pageState->storeVariable(iname, optionIndicesToString());
352 
353     String name = this->name();
354     if (name.isEmpty())
355         return;
356 
357     if (m_data.multiple()) {
358         // Spec: If the 'name' attribute is specified and the select is a multiple-choice element,
359         // then for each index greater than zero, the value of the 'value' attribute on the option
360         // element at the index is added to the name variable.
361         pageState->storeVariable(name, optionIndicesToValueString());
362         return;
363     }
364 
365     // Spec: If the 'name' attribute is specified and the select is a single-choice element,
366     // then the named variable is set with the value of the 'value' attribute on the option
367     // element at the default option index.
368     unsigned optionIndex = m_defaultOptionIndices.first();
369     ASSERT(optionIndex >= 1);
370 
371     int listIndex = optionToListIndex(optionIndex - 1);
372     ASSERT(listIndex >= 0);
373     ASSERT(listIndex < (int) items.size());
374 
375     if (OptionElement* optionElement = toOptionElement(items[listIndex]))
376         pageState->storeVariable(name, optionElement->value());
377 }
378 
updateVariables()379 void WMLSelectElement::updateVariables()
380 {
381     WMLPageState* pageState = wmlPageStateForDocument(document());
382     if (!pageState)
383         return;
384 
385     String name = this->name();
386     String iname = this->iname();
387     if (iname.isEmpty() && name.isEmpty())
388         return;
389 
390     String nameString;
391     String inameString;
392 
393     unsigned optionIndex = 0;
394     const Vector<Element*>& items = m_data.listItems(this);
395 
396     for (unsigned i = 0; i < items.size(); ++i) {
397         OptionElement* optionElement = toOptionElement(items[i]);
398         if (!optionElement)
399             continue;
400 
401         ++optionIndex;
402         if (!optionElement->selected())
403             continue;
404 
405         if (!nameString.isEmpty())
406             nameString += ";";
407 
408         if (!inameString.isEmpty())
409             inameString += ";";
410 
411         nameString += optionElement->value();
412         inameString += String::number(optionIndex);
413     }
414 
415     if (!name.isEmpty())
416         pageState->storeVariable(name, nameString);
417 
418     if (!iname.isEmpty())
419         pageState->storeVariable(iname, inameString);
420 }
421 
parseIndexValueString(const String & indexValue) const422 Vector<unsigned> WMLSelectElement::parseIndexValueString(const String& indexValue) const
423 {
424     Vector<unsigned> indices;
425     if (indexValue.isEmpty())
426         return indices;
427 
428     Vector<String> indexStrings;
429     indexValue.split(';', indexStrings);
430 
431     bool ok = false;
432     unsigned optionCount = SelectElement::optionCount(m_data, this);
433 
434     Vector<String>::const_iterator end = indexStrings.end();
435     for (Vector<String>::const_iterator it = indexStrings.begin(); it != end; ++it) {
436         unsigned parsedValue = (*it).toUIntStrict(&ok);
437         // Spec: Remove all non-integer indices from the value. Remove all out-of-range indices
438         // from the value, where out-of-range is defined as any index with a value greater than
439         // the number of options in the select or with a value less than one.
440         if (!ok || parsedValue < 1 || parsedValue > optionCount)
441             continue;
442 
443         // Spec: Remove duplicate indices.
444         if (indices.find(parsedValue) == notFound)
445             indices.append(parsedValue);
446     }
447 
448     return indices;
449 }
450 
valueStringToOptionIndices(const String & value) const451 Vector<unsigned> WMLSelectElement::valueStringToOptionIndices(const String& value) const
452 {
453     Vector<unsigned> indices;
454     if (value.isEmpty())
455         return indices;
456 
457     const Vector<Element*>& items = m_data.listItems(this);
458     if (items.isEmpty())
459         return indices;
460 
461     Vector<String> indexStrings;
462     value.split(';', indexStrings);
463 
464     unsigned optionIndex = 0;
465 
466     Vector<String>::const_iterator end = indexStrings.end();
467     for (Vector<String>::const_iterator it = indexStrings.begin(); it != end; ++it) {
468         String value = *it;
469 
470         for (unsigned i = 0; i < items.size(); ++i) {
471             if (!isOptionElement(items[i]))
472                 continue;
473 
474             ++optionIndex;
475             if (OptionElement* optionElement = toOptionElement(items[i])) {
476                 if (optionElement->value() == value) {
477                     indices.append(optionIndex);
478                     break;
479                 }
480             }
481         }
482     }
483 
484     return indices;
485 }
486 
optionIndicesToValueString() const487 String WMLSelectElement::optionIndicesToValueString() const
488 {
489     String valueString;
490     if (m_defaultOptionIndices.isEmpty())
491         return valueString;
492 
493     const Vector<Element*>& items = m_data.listItems(this);
494     if (items.isEmpty())
495         return valueString;
496 
497     Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end();
498     for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) {
499         unsigned optionIndex = (*it);
500         if (optionIndex < 1 || optionIndex > items.size())
501             continue;
502 
503         int listIndex = optionToListIndex((*it) - 1);
504         ASSERT(listIndex >= 0);
505         ASSERT(listIndex < (int) items.size());
506 
507         if (OptionElement* optionElement = toOptionElement(items[listIndex])) {
508             if (!valueString.isEmpty())
509                 valueString += ";";
510 
511             valueString += optionElement->value();
512         }
513     }
514 
515     return valueString;
516 }
517 
optionIndicesToString() const518 String WMLSelectElement::optionIndicesToString() const
519 {
520     String valueString;
521     if (m_defaultOptionIndices.isEmpty())
522         return valueString;
523 
524     Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end();
525     for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) {
526         if (!valueString.isEmpty())
527             valueString += ";";
528 
529         valueString += String::number(*it);
530     }
531 
532     return valueString;
533 }
534 
name() const535 String WMLSelectElement::name() const
536 {
537     return parseValueForbiddingVariableReferences(getAttribute(HTMLNames::nameAttr));
538 }
539 
value() const540 String WMLSelectElement::value() const
541 {
542     return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr));
543 }
544 
iname() const545 String WMLSelectElement::iname() const
546 {
547     return parseValueForbiddingVariableReferences(getAttribute(inameAttr));
548 }
549 
ivalue() const550 String WMLSelectElement::ivalue() const
551 {
552     return parseValueSubstitutingVariableReferences(getAttribute(ivalueAttr));
553 }
554 
listBoxSelectItem(int,bool,bool,bool)555 void WMLSelectElement::listBoxSelectItem(int, bool, bool, bool)
556 {
557     /* Dummy implementation as listBoxSelectItem is pure virtual in SelectElement class */
558 }
559 
560 }
561 
562 #endif
563