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