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