diff options
Diffstat (limited to 'WebCore/wml/WMLSelectElement.cpp')
-rw-r--r-- | WebCore/wml/WMLSelectElement.cpp | 331 |
1 files changed, 327 insertions, 4 deletions
diff --git a/WebCore/wml/WMLSelectElement.cpp b/WebCore/wml/WMLSelectElement.cpp index 5b5aed1..2d03a3f 100644 --- a/WebCore/wml/WMLSelectElement.cpp +++ b/WebCore/wml/WMLSelectElement.cpp @@ -22,16 +22,21 @@ #if ENABLE(WML) #include "WMLSelectElement.h" - +#include "CString.h" #include "HTMLNames.h" #include "MappedAttribute.h" +#include "OptionElement.h" #include "RenderListBox.h" #include "RenderMenuList.h" - +#include "WMLDocument.h" +#include "WMLNames.h" +#include "WMLVariables.h" #include <wtf/StdLibExtras.h> namespace WebCore { +using namespace WMLNames; + WMLSelectElement::WMLSelectElement(const QualifiedName& tagName, Document* document) : WMLFormControlElement(tagName, document) { @@ -41,6 +46,12 @@ WMLSelectElement::~WMLSelectElement() { } +const AtomicString& WMLSelectElement::formControlName() const +{ + AtomicString name = this->name(); + return name.isNull() ? emptyAtom : name; +} + const AtomicString& WMLSelectElement::formControlType() const { DEFINE_STATIC_LOCAL(const AtomicString, selectMultiple, ("select-multiple")); @@ -92,9 +103,14 @@ int WMLSelectElement::selectedIndex() const return SelectElement::selectedIndex(m_data, this); } -void WMLSelectElement::setSelectedIndex(int index, bool deselect, bool fireOnChange) +void WMLSelectElement::setSelectedIndex(int optionIndex, bool deselect) { - SelectElement::setSelectedIndex(m_data, this, index, deselect, fireOnChange); + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, false, false); +} + +void WMLSelectElement::setSelectedIndexByUser(int optionIndex, bool deselect, bool fireOnChangeNow) +{ + SelectElement::setSelectedIndex(m_data, this, optionIndex, deselect, fireOnChangeNow, true); } bool WMLSelectElement::saveFormControlState(String& value) const @@ -151,6 +167,14 @@ void WMLSelectElement::reset() void WMLSelectElement::defaultEventHandler(Event* event) { SelectElement::defaultEventHandler(m_data, this, event); + + // FIXME: There must be a better place to update the page variable state. Investigate. + updateVariables(); + + if (event->defaultHandled()) + return; + + WMLFormControlElement::defaultEventHandler(event); } void WMLSelectElement::accessKeyAction(bool sendToAnyElement) @@ -213,12 +237,311 @@ void WMLSelectElement::scrollToSelection() SelectElement::scrollToSelection(m_data, this); } +void WMLSelectElement::selectInitialOptions() +{ + // Spec: Step 1 - the default option index is determined using iname and ivalue + calculateDefaultOptionIndices(); + + if (m_defaultOptionIndices.isEmpty()) + return; + + // Spec: Step 2 – initialise variables + initializeVariables(); + + // Spec: Step 3 – pre-select option(s) specified by the default option index + selectDefaultOptions(); +} + void WMLSelectElement::insertedIntoTree(bool deep) { SelectElement::insertedIntoTree(m_data, this); WMLFormControlElement::insertedIntoTree(deep); } +void WMLSelectElement::calculateDefaultOptionIndices() +{ + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + String variable; + + // Spec: If the 'iname' attribute is specified and names a variable that is set, + // then the default option index is the validated value of that variable. + String iname = this->iname(); + if (!iname.isEmpty()) { + variable = pageState->getVariable(iname); + if (!variable.isEmpty()) + m_defaultOptionIndices = parseIndexValueString(variable); + } + + // Spec: If the default option index is empty and the 'ivalue' attribute is specified, + // then the default option index is the validated attribute value. + String ivalue = this->ivalue(); + if (m_defaultOptionIndices.isEmpty() && !ivalue.isEmpty()) + m_defaultOptionIndices = parseIndexValueString(ivalue); + + // Spec: If the default option index is empty, and the 'name' attribute is specified + // and the 'name' ttribute names a variable that is set, then for each value in the 'name' + // variable that is present as a value in the select's option elements, the index of the + // first option element containing that value is added to the default index if that + // index has not been previously added. + String name = this->name(); + if (m_defaultOptionIndices.isEmpty() && !name.isEmpty()) { + variable = pageState->getVariable(name); + if (!variable.isEmpty()) + m_defaultOptionIndices = valueStringToOptionIndices(variable); + } + + String value = parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); + + // Spec: If the default option index is empty and the 'value' attribute is specified then + // for each value in the 'value' attribute that is present as a value in the select's + // option elements, the index of the first option element containing that value is added + // to the default index if that index has not been previously added. + if (m_defaultOptionIndices.isEmpty() && !value.isEmpty()) + m_defaultOptionIndices = valueStringToOptionIndices(value); + + // Spec: If the default option index is empty and the select is a multi-choice, then the + // default option index is set to zero. If the select is single-choice, then the default + // option index is set to one. + if (m_defaultOptionIndices.isEmpty()) + m_defaultOptionIndices.append((unsigned) !m_data.multiple()); +} + +void WMLSelectElement::selectDefaultOptions() +{ + ASSERT(!m_defaultOptionIndices.isEmpty()); + + if (!m_data.multiple()) { + setSelectedIndex(m_defaultOptionIndices.first() - 1, false); + return; + } + + Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end(); + for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) + setSelectedIndex((*it) - 1, false); +} + +void WMLSelectElement::initializeVariables() +{ + ASSERT(!m_defaultOptionIndices.isEmpty()); + + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + const Vector<Element*>& items = m_data.listItems(this); + if (items.isEmpty()) + return; + + // Spec: If the 'iname' attribute is specified, then the named variable is set with the default option index. + String iname = this->iname(); + if (!iname.isEmpty()) + pageState->storeVariable(iname, optionIndicesToString()); + + String name = this->name(); + if (name.isEmpty()) + return; + + if (m_data.multiple()) { + // Spec: If the 'name' attribute is specified and the select is a multiple-choice element, + // then for each index greater than zero, the value of the 'value' attribute on the option + // element at the index is added to the name variable. + pageState->storeVariable(name, optionIndicesToValueString()); + return; + } + + // Spec: If the 'name' attribute is specified and the select is a single-choice element, + // then the named variable is set with the value of the 'value' attribute on the option + // element at the default option index. + unsigned optionIndex = m_defaultOptionIndices.first(); + ASSERT(optionIndex >= 1); + + int listIndex = optionToListIndex(optionIndex - 1); + ASSERT(listIndex >= 0); + ASSERT(listIndex < (int) items.size()); + + if (OptionElement* optionElement = toOptionElement(items[listIndex])) + pageState->storeVariable(name, optionElement->value()); +} + +void WMLSelectElement::updateVariables() +{ + WMLPageState* pageState = wmlPageStateForDocument(document()); + if (!pageState) + return; + + String name = this->name(); + String iname = this->iname(); + if (iname.isEmpty() && name.isEmpty()) + return; + + String nameString; + String inameString; + + unsigned optionIndex = 0; + const Vector<Element*>& items = m_data.listItems(this); + + for (unsigned i = 0; i < items.size(); ++i) { + OptionElement* optionElement = toOptionElement(items[i]); + if (!optionElement) + continue; + + ++optionIndex; + if (!optionElement->selected()) + continue; + + if (!nameString.isEmpty()) + nameString += ";"; + + if (!inameString.isEmpty()) + inameString += ";"; + + nameString += optionElement->value(); + inameString += String::number(optionIndex); + } + + if (!name.isEmpty()) + pageState->storeVariable(name, nameString); + + if (!iname.isEmpty()) + pageState->storeVariable(iname, inameString); +} + +Vector<unsigned> WMLSelectElement::parseIndexValueString(const String& indexValue) const +{ + Vector<unsigned> indices; + if (indexValue.isEmpty()) + return indices; + + Vector<String> indexStrings; + indexValue.split(';', indexStrings); + + bool ok = false; + unsigned optionCount = SelectElement::optionCount(m_data, this); + + Vector<String>::const_iterator end = indexStrings.end(); + for (Vector<String>::const_iterator it = indexStrings.begin(); it != end; ++it) { + unsigned parsedValue = (*it).toUIntStrict(&ok); + // Spec: Remove all non-integer indices from the value. Remove all out-of-range indices + // from the value, where out-of-range is defined as any index with a value greater than + // the number of options in the select or with a value less than one. + if (!ok || parsedValue < 1 || parsedValue > optionCount) + continue; + + // Spec: Remove duplicate indices. + if (indices.find(parsedValue) == notFound) + indices.append(parsedValue); + } + + return indices; +} + +Vector<unsigned> WMLSelectElement::valueStringToOptionIndices(const String& value) const +{ + Vector<unsigned> indices; + if (value.isEmpty()) + return indices; + + const Vector<Element*>& items = m_data.listItems(this); + if (items.isEmpty()) + return indices; + + Vector<String> indexStrings; + value.split(';', indexStrings); + + unsigned optionIndex = 0; + + Vector<String>::const_iterator end = indexStrings.end(); + for (Vector<String>::const_iterator it = indexStrings.begin(); it != end; ++it) { + String value = *it; + + for (unsigned i = 0; i < items.size(); ++i) { + if (!isOptionElement(items[i])) + continue; + + ++optionIndex; + if (OptionElement* optionElement = toOptionElement(items[i])) { + if (optionElement->value() == value) { + indices.append(optionIndex); + break; + } + } + } + } + + return indices; +} + +String WMLSelectElement::optionIndicesToValueString() const +{ + String valueString; + if (m_defaultOptionIndices.isEmpty()) + return valueString; + + const Vector<Element*>& items = m_data.listItems(this); + if (items.isEmpty()) + return valueString; + + Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end(); + for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) { + unsigned optionIndex = (*it); + if (optionIndex < 1 || optionIndex > items.size()) + continue; + + int listIndex = optionToListIndex((*it) - 1); + ASSERT(listIndex >= 0); + ASSERT(listIndex < (int) items.size()); + + if (OptionElement* optionElement = toOptionElement(items[listIndex])) { + if (!valueString.isEmpty()) + valueString += ";"; + + valueString += optionElement->value(); + } + } + + return valueString; +} + +String WMLSelectElement::optionIndicesToString() const +{ + String valueString; + if (m_defaultOptionIndices.isEmpty()) + return valueString; + + Vector<unsigned>::const_iterator end = m_defaultOptionIndices.end(); + for (Vector<unsigned>::const_iterator it = m_defaultOptionIndices.begin(); it != end; ++it) { + if (!valueString.isEmpty()) + valueString += ";"; + + valueString += String::number(*it); + } + + return valueString; +} + +String WMLSelectElement::name() const +{ + return parseValueForbiddingVariableReferences(getAttribute(HTMLNames::nameAttr)); +} + +String WMLSelectElement::value() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(HTMLNames::valueAttr)); +} + +String WMLSelectElement::iname() const +{ + return parseValueForbiddingVariableReferences(getAttribute(inameAttr)); +} + +String WMLSelectElement::ivalue() const +{ + return parseValueSubstitutingVariableReferences(getAttribute(ivalueAttr)); +} + } #endif |