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