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