Home | History | Annotate | Download | only in wml
      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 
     41 WMLSelectElement::WMLSelectElement(const QualifiedName& tagName, Document* document)
     42     : WMLFormControlElement(tagName, document)
     43     , m_initialized(false)
     44 {
     45 }
     46 
     47 PassRefPtr<WMLSelectElement> WMLSelectElement::create(const QualifiedName& tagName, Document* document)
     48 {
     49     return adoptRef(new WMLSelectElement(tagName, document));
     50 }
     51 
     52 WMLSelectElement::~WMLSelectElement()
     53 {
     54 }
     55 
     56 const AtomicString& WMLSelectElement::formControlName() const
     57 {
     58     AtomicString name = this->name();
     59     return name.isNull() ? emptyAtom : name;
     60 }
     61 
     62 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 
     69 bool WMLSelectElement::isKeyboardFocusable(KeyboardEvent* event) const
     70 {
     71     if (renderer())
     72         return isFocusable();
     73 
     74     return WMLFormControlElement::isKeyboardFocusable(event);
     75 }
     76 
     77 bool WMLSelectElement::isMouseFocusable() const
     78 {
     79     if (renderer())
     80         return isFocusable();
     81 
     82     return WMLFormControlElement::isMouseFocusable();
     83 }
     84 
     85 void WMLSelectElement::selectAll()
     86 {
     87     SelectElement::selectAll(m_data, this);
     88 }
     89 
     90 void WMLSelectElement::recalcStyle(StyleChange change)
     91 {
     92     WMLFormControlElement::recalcStyle(change);
     93 }
     94 
     95 void WMLSelectElement::dispatchFocusEvent()
     96 {
     97     SelectElement::dispatchFocusEvent(m_data, this);
     98     WMLFormControlElement::dispatchFocusEvent();
     99 }
    100 
    101 void WMLSelectElement::dispatchBlurEvent()
    102 {
    103     SelectElement::dispatchBlurEvent(m_data, this);
    104     WMLFormControlElement::dispatchBlurEvent();
    105 }
    106 
    107 int WMLSelectElement::selectedIndex() const
    108 {
    109     return SelectElement::selectedIndex(m_data, this);
    110 }
    111 
    112 void WMLSelectElement::setSelectedIndex(int optionIndex, bool deselect)
    113 {
    114     SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, false, false);
    115 }
    116 
    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 
    123 bool WMLSelectElement::saveFormControlState(String& value) const
    124 {
    125     return SelectElement::saveFormControlState(m_data, this, value);
    126 }
    127 
    128 void WMLSelectElement::restoreFormControlState(const String& state)
    129 {
    130     SelectElement::restoreFormControlState(m_data, this, state);
    131 }
    132 
    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 
    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 
    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 
    154 bool WMLSelectElement::appendFormData(FormDataList& list, bool)
    155 {
    156     return SelectElement::appendFormData(m_data, this, list);
    157 }
    158 
    159 int WMLSelectElement::optionToListIndex(int optionIndex) const
    160 {
    161     return SelectElement::optionToListIndex(m_data, this, optionIndex);
    162 }
    163 
    164 int WMLSelectElement::listToOptionIndex(int listIndex) const
    165 {
    166     return SelectElement::listToOptionIndex(m_data, this, listIndex);
    167 }
    168 
    169 void WMLSelectElement::reset()
    170 {
    171     SelectElement::reset(m_data, this);
    172 }
    173 
    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 
    187 void WMLSelectElement::accessKeyAction(bool sendToAnyElement)
    188 {
    189     focus();
    190     dispatchSimulatedClick(0, sendToAnyElement);
    191 }
    192 
    193 void WMLSelectElement::setActiveSelectionAnchorIndex(int index)
    194 {
    195     SelectElement::setActiveSelectionAnchorIndex(m_data, this, index);
    196 }
    197 
    198 void WMLSelectElement::setActiveSelectionEndIndex(int index)
    199 {
    200     SelectElement::setActiveSelectionEndIndex(m_data, index);
    201 }
    202 
    203 void WMLSelectElement::updateListBoxSelection(bool deselectOtherOptions)
    204 {
    205     SelectElement::updateListBoxSelection(m_data, this, deselectOtherOptions);
    206 }
    207 
    208 void WMLSelectElement::listBoxOnChange()
    209 {
    210     SelectElement::listBoxOnChange(m_data, this);
    211 }
    212 
    213 void WMLSelectElement::menuListOnChange()
    214 {
    215     SelectElement::menuListOnChange(m_data, this);
    216 }
    217 
    218 int WMLSelectElement::activeSelectionStartListIndex() const
    219 {
    220     if (m_data.activeSelectionAnchorIndex() >= 0)
    221         return m_data.activeSelectionAnchorIndex();
    222     return optionToListIndex(selectedIndex());
    223 }
    224 
    225 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 
    232 void WMLSelectElement::accessKeySetSelectedIndex(int index)
    233 {
    234     SelectElement::accessKeySetSelectedIndex(m_data, this, index);
    235 }
    236 
    237 void WMLSelectElement::setRecalcListItems()
    238 {
    239     SelectElement::setRecalcListItems(m_data, this);
    240 }
    241 
    242 void WMLSelectElement::scrollToSelection()
    243 {
    244     SelectElement::scrollToSelection(m_data, this);
    245 }
    246 
    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 
    265 void WMLSelectElement::insertedIntoTree(bool deep)
    266 {
    267     SelectElement::insertedIntoTree(m_data, this);
    268     WMLFormControlElement::insertedIntoTree(deep);
    269 }
    270 
    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 
    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 
    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 
    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 
    422 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 
    451 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 
    487 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 
    518 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 
    535 String WMLSelectElement::name() const
    536 {
    537     return parseValueForbiddingVariableReferences(getAttribute(HTMLNames::nameAttr));
    538 }
    539 
    540 String WMLSelectElement::value() const
    541 {
    542     return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr));
    543 }
    544 
    545 String WMLSelectElement::iname() const
    546 {
    547     return parseValueForbiddingVariableReferences(getAttribute(inameAttr));
    548 }
    549 
    550 String WMLSelectElement::ivalue() const
    551 {
    552     return parseValueSubstitutingVariableReferences(getAttribute(ivalueAttr));
    553 }
    554 
    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