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