1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 7 * Copyright (C) 2007 Samuel Weinig (sam (at) webkit.org) 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Library General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Library General Public License for more details. 18 * 19 * You should have received a copy of the GNU Library General Public License 20 * along with this library; see the file COPYING.LIB. If not, write to 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 * Boston, MA 02110-1301, USA. 23 * 24 */ 25 26 #include "config.h" 27 #include "HTMLInputElement.h" 28 29 #include "AXObjectCache.h" 30 #include "CSSPropertyNames.h" 31 #include "ChromeClient.h" 32 #include "DateComponents.h" 33 #include "Document.h" 34 #include "Editor.h" 35 #include "Event.h" 36 #include "EventHandler.h" 37 #include "EventNames.h" 38 #include "ExceptionCode.h" 39 #include "File.h" 40 #include "FileList.h" 41 #include "FocusController.h" 42 #include "FormDataList.h" 43 #include "Frame.h" 44 #include "HTMLDataListElement.h" 45 #include "HTMLFormElement.h" 46 #include "HTMLImageLoader.h" 47 #include "HTMLNames.h" 48 #include "HTMLOptionElement.h" 49 #include "ScriptEventListener.h" 50 #include "KeyboardEvent.h" 51 #include "LocalizedStrings.h" 52 #include "MappedAttribute.h" 53 #include "MouseEvent.h" 54 #include "Page.h" 55 #include "RegularExpression.h" 56 #include "RenderButton.h" 57 #include "RenderFileUploadControl.h" 58 #include "RenderImage.h" 59 #include "RenderSlider.h" 60 #include "RenderText.h" 61 #include "RenderTextControlSingleLine.h" 62 #include "RenderTheme.h" 63 #include "StringHash.h" 64 #include "TextEvent.h" 65 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 66 #include "WebViewCore.h" 67 #endif 68 #include <wtf/HashMap.h> 69 #include <wtf/MathExtras.h> 70 #include <wtf/StdLibExtras.h> 71 #include <wtf/dtoa.h> 72 73 using namespace std; 74 75 namespace WebCore { 76 77 using namespace HTMLNames; 78 79 const int maxSavedResults = 256; 80 81 // Constant values for getAllowedValueStep(). 82 static const double dateDefaultStep = 1.0; 83 static const double dateStepScaleFactor = 86400000.0; 84 static const double dateTimeDefaultStep = 60.0; 85 static const double dateTimeStepScaleFactor = 1000.0; 86 static const double monthDefaultStep = 1.0; 87 static const double monthStepScaleFactor = 1.0; 88 static const double numberDefaultStep = 1.0; 89 static const double numberStepScaleFactor = 1.0; 90 static const double timeDefaultStep = 60.0; 91 static const double timeStepScaleFactor = 1000.0; 92 static const double weekDefaultStep = 1.0; 93 static const double weekStepScaleFactor = 604800000.0; 94 95 // Constant values for minimum(). 96 static const double dateDefaultMinimum = -12219292800000.0; // This means 1582-10-15T00:00Z. 97 static const double dateTimeDefaultMinimum = -12219292800000.0; // ditto. 98 static const double monthDefaultMinimum = (1582.0 - 1970) * 12 + 10 - 1; // 1582-10 99 static const double numberDefaultMinimum = -DBL_MAX; 100 static const double rangeDefaultMinimum = 0.0; 101 static const double timeDefaultMinimum = 0.0; // 00:00:00.000 102 static const double weekDefaultMinimum = -12212380800000.0; // 1583-01-03, the first Monday of 1583. 103 104 // Constant values for maximum(). 105 static const double dateDefaultMaximum = DBL_MAX; 106 static const double dateTimeDefaultMaximum = DBL_MAX; 107 // DateComponents::m_year can't represent a year greater than INT_MAX. 108 static const double monthDefaultMaximum = (INT_MAX - 1970) * 12.0 + 12 - 1; 109 static const double numberDefaultMaximum = DBL_MAX; 110 static const double rangeDefaultMaximum = 100.0; 111 static const double timeDefaultMaximum = 86399999.0; // 23:59:59.999 112 static const double weekDefaultMaximum = DBL_MAX; 113 114 static const double defaultStepBase = 0.0; 115 static const double weekDefaultStepBase = -259200000.0; // The first day of 1970-W01. 116 117 static const double msecPerMinute = 60 * 1000; 118 static const double msecPerSecond = 1000; 119 120 HTMLInputElement::HTMLInputElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) 121 : HTMLTextFormControlElement(tagName, doc, f) 122 , m_xPos(0) 123 , m_yPos(0) 124 , m_maxResults(-1) 125 , m_type(TEXT) 126 , m_checked(false) 127 , m_defaultChecked(false) 128 , m_useDefaultChecked(true) 129 , m_indeterminate(false) 130 , m_haveType(false) 131 , m_activeSubmit(false) 132 , m_autocomplete(Uninitialized) 133 , m_autofilled(false) 134 , m_inited(false) 135 { 136 ASSERT(hasTagName(inputTag) || hasTagName(isindexTag)); 137 } 138 139 HTMLInputElement::~HTMLInputElement() 140 { 141 if (needsActivationCallback()) 142 document()->unregisterForDocumentActivationCallbacks(this); 143 144 document()->checkedRadioButtons().removeButton(this); 145 146 // Need to remove this from the form while it is still an HTMLInputElement, 147 // so can't wait for the base class's destructor to do it. 148 removeFromForm(); 149 } 150 151 const AtomicString& HTMLInputElement::formControlName() const 152 { 153 return m_data.name(); 154 } 155 156 bool HTMLInputElement::autoComplete() const 157 { 158 if (m_autocomplete != Uninitialized) 159 return m_autocomplete == On; 160 161 // Assuming we're still in a Form, respect the Form's setting 162 if (HTMLFormElement* form = this->form()) 163 return form->autoComplete(); 164 165 // The default is true 166 return true; 167 } 168 169 bool HTMLInputElement::valueMissing() const 170 { 171 if (!isRequiredFormControl() || readOnly() || disabled()) 172 return false; 173 174 switch (inputType()) { 175 case DATE: 176 case DATETIME: 177 case DATETIMELOCAL: 178 case EMAIL: 179 case FILE: 180 case MONTH: 181 case NUMBER: 182 case PASSWORD: 183 case SEARCH: 184 case TELEPHONE: 185 case TEXT: 186 case TIME: 187 case URL: 188 case WEEK: 189 return value().isEmpty(); 190 case CHECKBOX: 191 return !checked(); 192 case RADIO: 193 return !document()->checkedRadioButtons().checkedButtonForGroup(name()); 194 case COLOR: 195 return false; 196 case BUTTON: 197 case HIDDEN: 198 case IMAGE: 199 case ISINDEX: 200 case RANGE: 201 case RESET: 202 case SUBMIT: 203 break; 204 } 205 206 ASSERT_NOT_REACHED(); 207 return false; 208 } 209 210 bool HTMLInputElement::patternMismatch() const 211 { 212 switch (inputType()) { 213 case BUTTON: 214 case CHECKBOX: 215 case COLOR: 216 case DATE: 217 case DATETIME: 218 case DATETIMELOCAL: 219 case FILE: 220 case HIDDEN: 221 case IMAGE: 222 case ISINDEX: 223 case MONTH: 224 case NUMBER: 225 case RADIO: 226 case RANGE: 227 case RESET: 228 case SUBMIT: 229 case TIME: 230 case WEEK: 231 return false; 232 case EMAIL: 233 case PASSWORD: 234 case SEARCH: 235 case TELEPHONE: 236 case TEXT: 237 case URL: 238 const AtomicString& pattern = getAttribute(patternAttr); 239 String value = this->value(); 240 241 // Empty values can't be mismatched 242 if (pattern.isEmpty() || value.isEmpty()) 243 return false; 244 245 RegularExpression patternRegExp(pattern, TextCaseSensitive); 246 int matchLength = 0; 247 int valueLength = value.length(); 248 int matchOffset = patternRegExp.match(value, 0, &matchLength); 249 250 return matchOffset != 0 || matchLength != valueLength; 251 } 252 253 ASSERT_NOT_REACHED(); 254 return false; 255 } 256 257 bool HTMLInputElement::tooLong() const 258 { 259 switch (inputType()) { 260 case EMAIL: 261 case PASSWORD: 262 case SEARCH: 263 case TELEPHONE: 264 case TEXT: 265 case URL: { 266 int max = maxLength(); 267 if (max < 0) 268 return false; 269 // Return false for the default value even if it is longer than maxLength. 270 bool userEdited = !m_data.value().isNull(); 271 if (!userEdited) 272 return false; 273 return value().numGraphemeClusters() > static_cast<unsigned>(max); 274 } 275 case BUTTON: 276 case CHECKBOX: 277 case COLOR: 278 case DATE: 279 case DATETIME: 280 case DATETIMELOCAL: 281 case FILE: 282 case HIDDEN: 283 case IMAGE: 284 case ISINDEX: 285 case MONTH: 286 case NUMBER: 287 case RADIO: 288 case RANGE: 289 case RESET: 290 case SUBMIT: 291 case TIME: 292 case WEEK: 293 return false; 294 } 295 ASSERT_NOT_REACHED(); 296 return false; 297 } 298 299 bool HTMLInputElement::rangeUnderflow() const 300 { 301 const double nan = numeric_limits<double>::quiet_NaN(); 302 switch (inputType()) { 303 case DATE: 304 case DATETIME: 305 case DATETIMELOCAL: 306 case MONTH: 307 case NUMBER: 308 case RANGE: 309 case TIME: 310 case WEEK: { 311 double doubleValue = parseToDouble(value(), nan); 312 return isfinite(doubleValue) && doubleValue < minimum(); 313 } 314 case BUTTON: 315 case CHECKBOX: 316 case COLOR: 317 case EMAIL: 318 case FILE: 319 case HIDDEN: 320 case IMAGE: 321 case ISINDEX: 322 case PASSWORD: 323 case RADIO: 324 case RESET: 325 case SEARCH: 326 case SUBMIT: 327 case TELEPHONE: 328 case TEXT: 329 case URL: 330 break; 331 } 332 return false; 333 } 334 335 bool HTMLInputElement::rangeOverflow() const 336 { 337 const double nan = numeric_limits<double>::quiet_NaN(); 338 switch (inputType()) { 339 case DATE: 340 case DATETIME: 341 case DATETIMELOCAL: 342 case MONTH: 343 case NUMBER: 344 case RANGE: 345 case TIME: 346 case WEEK: { 347 double doubleValue = parseToDouble(value(), nan); 348 return isfinite(doubleValue) && doubleValue > maximum(); 349 } 350 case BUTTON: 351 case CHECKBOX: 352 case COLOR: 353 case EMAIL: 354 case FILE: 355 case HIDDEN: 356 case IMAGE: 357 case ISINDEX: 358 case PASSWORD: 359 case RADIO: 360 case RESET: 361 case SEARCH: 362 case SUBMIT: 363 case TELEPHONE: 364 case TEXT: 365 case URL: 366 break; 367 } 368 return false; 369 } 370 371 double HTMLInputElement::minimum() const 372 { 373 switch (inputType()) { 374 case DATE: 375 return parseToDouble(getAttribute(minAttr), dateDefaultMinimum); 376 case DATETIME: 377 case DATETIMELOCAL: 378 return parseToDouble(getAttribute(minAttr), dateTimeDefaultMinimum); 379 case MONTH: 380 return parseToDouble(getAttribute(minAttr), monthDefaultMinimum); 381 case NUMBER: 382 return parseToDouble(getAttribute(minAttr), numberDefaultMinimum); 383 case RANGE: 384 return parseToDouble(getAttribute(minAttr), rangeDefaultMinimum); 385 case TIME: 386 return parseToDouble(getAttribute(minAttr), timeDefaultMinimum); 387 case WEEK: 388 return parseToDouble(getAttribute(minAttr), weekDefaultMinimum); 389 case BUTTON: 390 case CHECKBOX: 391 case COLOR: 392 case EMAIL: 393 case FILE: 394 case HIDDEN: 395 case IMAGE: 396 case ISINDEX: 397 case PASSWORD: 398 case RADIO: 399 case RESET: 400 case SEARCH: 401 case SUBMIT: 402 case TELEPHONE: 403 case TEXT: 404 case URL: 405 break; 406 } 407 ASSERT_NOT_REACHED(); 408 return 0; 409 } 410 411 double HTMLInputElement::maximum() const 412 { 413 switch (inputType()) { 414 case DATE: 415 return parseToDouble(getAttribute(maxAttr), dateDefaultMaximum); 416 case DATETIME: 417 case DATETIMELOCAL: 418 return parseToDouble(getAttribute(maxAttr), dateTimeDefaultMaximum); 419 case MONTH: 420 return parseToDouble(getAttribute(maxAttr), monthDefaultMaximum); 421 case NUMBER: 422 return parseToDouble(getAttribute(maxAttr), numberDefaultMaximum); 423 case RANGE: { 424 double max = parseToDouble(getAttribute(maxAttr), rangeDefaultMaximum); 425 // A remedy for the inconsistent min/max values for RANGE. 426 // Sets the maximum to the default or the minimum value. 427 double min = minimum(); 428 if (max < min) 429 max = std::max(min, rangeDefaultMaximum); 430 return max; 431 } 432 case TIME: 433 return parseToDouble(getAttribute(maxAttr), timeDefaultMaximum); 434 case WEEK: 435 return parseToDouble(getAttribute(maxAttr), weekDefaultMaximum); 436 case BUTTON: 437 case CHECKBOX: 438 case COLOR: 439 case EMAIL: 440 case FILE: 441 case HIDDEN: 442 case IMAGE: 443 case ISINDEX: 444 case PASSWORD: 445 case RADIO: 446 case RESET: 447 case SEARCH: 448 case SUBMIT: 449 case TELEPHONE: 450 case TEXT: 451 case URL: 452 break; 453 } 454 ASSERT_NOT_REACHED(); 455 return 0; 456 } 457 458 double HTMLInputElement::stepBase() const 459 { 460 switch (inputType()) { 461 case RANGE: 462 return minimum(); 463 case DATE: 464 case DATETIME: 465 case DATETIMELOCAL: 466 case MONTH: 467 case NUMBER: 468 case TIME: 469 return parseToDouble(getAttribute(minAttr), defaultStepBase); 470 case WEEK: 471 return parseToDouble(getAttribute(minAttr), weekDefaultStepBase); 472 case BUTTON: 473 case CHECKBOX: 474 case COLOR: 475 case EMAIL: 476 case FILE: 477 case HIDDEN: 478 case IMAGE: 479 case ISINDEX: 480 case PASSWORD: 481 case RADIO: 482 case RESET: 483 case SEARCH: 484 case SUBMIT: 485 case TELEPHONE: 486 case TEXT: 487 case URL: 488 break; 489 } 490 ASSERT_NOT_REACHED(); 491 return 0.0; 492 } 493 494 bool HTMLInputElement::stepMismatch() const 495 { 496 double step; 497 if (!getAllowedValueStep(&step)) 498 return false; 499 switch (inputType()) { 500 case RANGE: 501 // stepMismatch doesn't occur for RANGE. RenderSlider guarantees the 502 // value matches to step. 503 return false; 504 case NUMBER: { 505 double doubleValue; 506 if (!formStringToDouble(value(), &doubleValue)) 507 return false; 508 doubleValue = fabs(doubleValue - stepBase()); 509 if (isinf(doubleValue)) 510 return false; 511 // double's fractional part size is DBL_MAN_DIG-bit. If the current 512 // value is greater than step*2^DBL_MANT_DIG, the following fmod() makes 513 // no sense. 514 if (doubleValue / pow(2.0, DBL_MANT_DIG) > step) 515 return false; 516 double remainder = fmod(doubleValue, step); 517 // Accepts errors in lower 7-bit. 518 double acceptableError = step / pow(2.0, DBL_MANT_DIG - 7); 519 return acceptableError < remainder && remainder < (step - acceptableError); 520 } 521 case DATE: 522 case DATETIME: 523 case DATETIMELOCAL: 524 case MONTH: 525 case TIME: 526 case WEEK: { 527 const double nan = numeric_limits<double>::quiet_NaN(); 528 double doubleValue = parseToDouble(value(), nan); 529 doubleValue = fabs(doubleValue - stepBase()); 530 if (!isfinite(doubleValue)) 531 return false; 532 ASSERT(round(doubleValue) == doubleValue); 533 ASSERT(round(step) == step); 534 return fmod(doubleValue, step); 535 } 536 case BUTTON: 537 case CHECKBOX: 538 case COLOR: 539 case EMAIL: 540 case FILE: 541 case HIDDEN: 542 case IMAGE: 543 case ISINDEX: 544 case PASSWORD: 545 case RADIO: 546 case RESET: 547 case SEARCH: 548 case SUBMIT: 549 case TELEPHONE: 550 case TEXT: 551 case URL: 552 break; 553 } 554 // Non-supported types should be rejected by getAllowedValueStep(). 555 ASSERT_NOT_REACHED(); 556 return false; 557 } 558 559 bool HTMLInputElement::getStepParameters(double* defaultStep, double* stepScaleFactor) const 560 { 561 ASSERT(defaultStep); 562 ASSERT(stepScaleFactor); 563 switch (inputType()) { 564 case NUMBER: 565 case RANGE: 566 *defaultStep = numberDefaultStep; 567 *stepScaleFactor = numberStepScaleFactor; 568 return true; 569 case DATE: 570 *defaultStep = dateDefaultStep; 571 *stepScaleFactor = dateStepScaleFactor; 572 return true; 573 case DATETIME: 574 case DATETIMELOCAL: 575 *defaultStep = dateTimeDefaultStep; 576 *stepScaleFactor = dateTimeStepScaleFactor; 577 return true; 578 case MONTH: 579 *defaultStep = monthDefaultStep; 580 *stepScaleFactor = monthStepScaleFactor; 581 return true; 582 case TIME: 583 *defaultStep = timeDefaultStep; 584 *stepScaleFactor = timeStepScaleFactor; 585 return true; 586 case WEEK: 587 *defaultStep = weekDefaultStep; 588 *stepScaleFactor = weekStepScaleFactor; 589 return true; 590 case BUTTON: 591 case CHECKBOX: 592 case COLOR: 593 case EMAIL: 594 case FILE: 595 case HIDDEN: 596 case IMAGE: 597 case ISINDEX: 598 case PASSWORD: 599 case RADIO: 600 case RESET: 601 case SEARCH: 602 case SUBMIT: 603 case TELEPHONE: 604 case TEXT: 605 case URL: 606 return false; 607 } 608 ASSERT_NOT_REACHED(); 609 return false; 610 } 611 612 bool HTMLInputElement::getAllowedValueStep(double* step) const 613 { 614 ASSERT(step); 615 double defaultStep; 616 double stepScaleFactor; 617 if (!getStepParameters(&defaultStep, &stepScaleFactor)) 618 return false; 619 const AtomicString& stepString = getAttribute(stepAttr); 620 if (stepString.isEmpty()) { 621 *step = defaultStep * stepScaleFactor; 622 return true; 623 } 624 if (equalIgnoringCase(stepString, "any")) 625 return false; 626 double parsed; 627 if (!formStringToDouble(stepString, &parsed) || parsed <= 0.0) { 628 *step = defaultStep * stepScaleFactor; 629 return true; 630 } 631 // For DATE, MONTH, WEEK, the parsed value should be an integer. 632 if (inputType() == DATE || inputType() == MONTH || inputType() == WEEK) 633 parsed = max(round(parsed), 1.0); 634 double result = parsed * stepScaleFactor; 635 // For DATETIME, DATETIMELOCAL, TIME, the result should be an integer. 636 if (inputType() == DATETIME || inputType() == DATETIMELOCAL || inputType() == TIME) 637 result = max(round(result), 1.0); 638 ASSERT(result > 0); 639 *step = result; 640 return true; 641 } 642 643 void HTMLInputElement::applyStep(double count, ExceptionCode& ec) 644 { 645 double step; 646 if (!getAllowedValueStep(&step)) { 647 ec = INVALID_STATE_ERR; 648 return; 649 } 650 const double nan = numeric_limits<double>::quiet_NaN(); 651 double current = parseToDouble(value(), nan); 652 if (!isfinite(current)) { 653 ec = INVALID_STATE_ERR; 654 return; 655 } 656 double newValue = current + step * count; 657 if (isinf(newValue)) { 658 ec = INVALID_STATE_ERR; 659 return; 660 } 661 if (newValue < minimum()) { 662 ec = INVALID_STATE_ERR; 663 return; 664 } 665 double base = stepBase(); 666 newValue = base + round((newValue - base) / step) * step; 667 if (newValue > maximum()) { 668 ec = INVALID_STATE_ERR; 669 return; 670 } 671 setValueAsNumber(newValue, ec); 672 } 673 674 void HTMLInputElement::stepUp(int n, ExceptionCode& ec) 675 { 676 applyStep(n, ec); 677 } 678 679 void HTMLInputElement::stepDown(int n, ExceptionCode& ec) 680 { 681 applyStep(-n, ec); 682 } 683 684 static inline CheckedRadioButtons& checkedRadioButtons(const HTMLInputElement *element) 685 { 686 if (HTMLFormElement* form = element->form()) 687 return form->checkedRadioButtons(); 688 689 return element->document()->checkedRadioButtons(); 690 } 691 692 bool HTMLInputElement::isKeyboardFocusable(KeyboardEvent* event) const 693 { 694 // If text fields can be focused, then they should always be keyboard focusable 695 if (isTextField()) 696 return HTMLFormControlElementWithState::isFocusable(); 697 698 // If the base class says we can't be focused, then we can stop now. 699 if (!HTMLFormControlElementWithState::isKeyboardFocusable(event)) 700 return false; 701 702 if (inputType() == RADIO) { 703 704 // Never allow keyboard tabbing to leave you in the same radio group. Always 705 // skip any other elements in the group. 706 Node* currentFocusedNode = document()->focusedNode(); 707 if (currentFocusedNode && currentFocusedNode->hasTagName(inputTag)) { 708 HTMLInputElement* focusedInput = static_cast<HTMLInputElement*>(currentFocusedNode); 709 if (focusedInput->inputType() == RADIO && focusedInput->form() == form() && 710 focusedInput->name() == name()) 711 return false; 712 } 713 714 // Allow keyboard focus if we're checked or if nothing in the group is checked. 715 return checked() || !checkedRadioButtons(this).checkedButtonForGroup(name()); 716 } 717 718 return true; 719 } 720 721 bool HTMLInputElement::isMouseFocusable() const 722 { 723 if (isTextField()) 724 return HTMLFormControlElementWithState::isFocusable(); 725 return HTMLFormControlElementWithState::isMouseFocusable(); 726 } 727 728 void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection) 729 { 730 if (isTextField()) 731 InputElement::updateFocusAppearance(m_data, this, this, restorePreviousSelection); 732 else 733 HTMLFormControlElementWithState::updateFocusAppearance(restorePreviousSelection); 734 } 735 736 void HTMLInputElement::aboutToUnload() 737 { 738 InputElement::aboutToUnload(this, this); 739 } 740 741 bool HTMLInputElement::shouldUseInputMethod() const 742 { 743 return m_type == TEXT || m_type == SEARCH || m_type == ISINDEX; 744 } 745 746 void HTMLInputElement::handleFocusEvent() 747 { 748 InputElement::dispatchFocusEvent(this, this); 749 750 if (isTextField()) 751 m_autofilled = false; 752 } 753 754 void HTMLInputElement::handleBlurEvent() 755 { 756 InputElement::dispatchBlurEvent(this, this); 757 } 758 759 void HTMLInputElement::setType(const String& t) 760 { 761 if (t.isEmpty()) { 762 int exccode; 763 removeAttribute(typeAttr, exccode); 764 } else 765 setAttribute(typeAttr, t); 766 } 767 768 typedef HashMap<String, HTMLInputElement::InputType, CaseFoldingHash> InputTypeMap; 769 static const InputTypeMap* createTypeMap() 770 { 771 InputTypeMap* map = new InputTypeMap; 772 map->add("button", HTMLInputElement::BUTTON); 773 map->add("checkbox", HTMLInputElement::CHECKBOX); 774 map->add("color", HTMLInputElement::COLOR); 775 map->add("date", HTMLInputElement::DATE); 776 map->add("datetime", HTMLInputElement::DATETIME); 777 map->add("datetime-local", HTMLInputElement::DATETIMELOCAL); 778 map->add("email", HTMLInputElement::EMAIL); 779 map->add("file", HTMLInputElement::FILE); 780 map->add("hidden", HTMLInputElement::HIDDEN); 781 map->add("image", HTMLInputElement::IMAGE); 782 map->add("khtml_isindex", HTMLInputElement::ISINDEX); 783 map->add("month", HTMLInputElement::MONTH); 784 map->add("number", HTMLInputElement::NUMBER); 785 map->add("password", HTMLInputElement::PASSWORD); 786 map->add("radio", HTMLInputElement::RADIO); 787 map->add("range", HTMLInputElement::RANGE); 788 map->add("reset", HTMLInputElement::RESET); 789 map->add("search", HTMLInputElement::SEARCH); 790 map->add("submit", HTMLInputElement::SUBMIT); 791 map->add("tel", HTMLInputElement::TELEPHONE); 792 map->add("time", HTMLInputElement::TIME); 793 map->add("url", HTMLInputElement::URL); 794 map->add("week", HTMLInputElement::WEEK); 795 // No need to register "text" because it is the default type. 796 return map; 797 } 798 799 void HTMLInputElement::setInputType(const String& t) 800 { 801 static const InputTypeMap* typeMap = createTypeMap(); 802 InputType newType = t.isNull() ? TEXT : typeMap->get(t); 803 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 804 if (newType == PASSWORD && document()->focusedNode() == this) 805 android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, true, String()); 806 #endif 807 808 // IMPORTANT: Don't allow the type to be changed to FILE after the first 809 // type change, otherwise a JavaScript programmer would be able to set a text 810 // field's value to something like /etc/passwd and then change it to a file field. 811 if (inputType() != newType) { 812 bool oldWillValidate = willValidate(); 813 if (newType == FILE && m_haveType) 814 // Set the attribute back to the old value. 815 // Useful in case we were called from inside parseMappedAttribute. 816 setAttribute(typeAttr, type()); 817 else { 818 checkedRadioButtons(this).removeButton(this); 819 820 if (newType == FILE && !m_fileList) 821 m_fileList = FileList::create(); 822 823 bool wasAttached = attached(); 824 if (wasAttached) 825 detach(); 826 827 bool didStoreValue = storesValueSeparateFromAttribute(); 828 bool wasPasswordField = inputType() == PASSWORD; 829 bool didRespectHeightAndWidth = respectHeightAndWidthAttrs(); 830 m_type = newType; 831 bool willStoreValue = storesValueSeparateFromAttribute(); 832 bool isPasswordField = inputType() == PASSWORD; 833 bool willRespectHeightAndWidth = respectHeightAndWidthAttrs(); 834 835 if (didStoreValue && !willStoreValue && !m_data.value().isNull()) { 836 setAttribute(valueAttr, m_data.value()); 837 m_data.setValue(String()); 838 } 839 if (!didStoreValue && willStoreValue) 840 m_data.setValue(sanitizeValue(getAttribute(valueAttr))); 841 else 842 InputElement::updateValueIfNeeded(m_data, this); 843 844 if (wasPasswordField && !isPasswordField) 845 unregisterForActivationCallbackIfNeeded(); 846 else if (!wasPasswordField && isPasswordField) 847 registerForActivationCallbackIfNeeded(); 848 849 if (didRespectHeightAndWidth != willRespectHeightAndWidth) { 850 NamedMappedAttrMap* map = mappedAttributes(); 851 ASSERT(map); 852 if (Attribute* height = map->getAttributeItem(heightAttr)) 853 attributeChanged(height, false); 854 if (Attribute* width = map->getAttributeItem(widthAttr)) 855 attributeChanged(width, false); 856 if (Attribute* align = map->getAttributeItem(alignAttr)) 857 attributeChanged(align, false); 858 } 859 860 if (wasAttached) { 861 attach(); 862 if (document()->focusedNode() == this) 863 updateFocusAppearance(true); 864 } 865 866 checkedRadioButtons(this).addButton(this); 867 } 868 869 setNeedsValidityCheck(); 870 if (oldWillValidate != willValidate()) 871 setNeedsWillValidateCheck(); 872 InputElement::notifyFormStateChanged(this); 873 } 874 m_haveType = true; 875 876 if (inputType() != IMAGE && m_imageLoader) 877 m_imageLoader.clear(); 878 } 879 880 static const AtomicString* createFormControlTypes() 881 { 882 AtomicString* types = new AtomicString[HTMLInputElement::numberOfTypes]; 883 // The values must be lowercased because they will be the return values of 884 // input.type and it must be lowercase according to DOM Level 2. 885 types[HTMLInputElement::BUTTON] = "button"; 886 types[HTMLInputElement::CHECKBOX] = "checkbox"; 887 types[HTMLInputElement::COLOR] = "color"; 888 types[HTMLInputElement::DATE] = "date"; 889 types[HTMLInputElement::DATETIME] = "datetime"; 890 types[HTMLInputElement::DATETIMELOCAL] = "datetime-local"; 891 types[HTMLInputElement::EMAIL] = "email"; 892 types[HTMLInputElement::FILE] = "file"; 893 types[HTMLInputElement::HIDDEN] = "hidden"; 894 types[HTMLInputElement::IMAGE] = "image"; 895 types[HTMLInputElement::ISINDEX] = emptyAtom; 896 types[HTMLInputElement::MONTH] = "month"; 897 types[HTMLInputElement::NUMBER] = "number"; 898 types[HTMLInputElement::PASSWORD] = "password"; 899 types[HTMLInputElement::RADIO] = "radio"; 900 types[HTMLInputElement::RANGE] = "range"; 901 types[HTMLInputElement::RESET] = "reset"; 902 types[HTMLInputElement::SEARCH] = "search"; 903 types[HTMLInputElement::SUBMIT] = "submit"; 904 types[HTMLInputElement::TELEPHONE] = "tel"; 905 types[HTMLInputElement::TEXT] = "text"; 906 types[HTMLInputElement::TIME] = "time"; 907 types[HTMLInputElement::URL] = "url"; 908 types[HTMLInputElement::WEEK] = "week"; 909 return types; 910 } 911 912 const AtomicString& HTMLInputElement::formControlType() const 913 { 914 static const AtomicString* formControlTypes = createFormControlTypes(); 915 return formControlTypes[inputType()]; 916 } 917 918 bool HTMLInputElement::saveFormControlState(String& result) const 919 { 920 if (!autoComplete()) 921 return false; 922 923 switch (inputType()) { 924 case BUTTON: 925 case COLOR: 926 case DATE: 927 case DATETIME: 928 case DATETIMELOCAL: 929 case EMAIL: 930 case FILE: 931 case HIDDEN: 932 case IMAGE: 933 case ISINDEX: 934 case MONTH: 935 case NUMBER: 936 case RANGE: 937 case RESET: 938 case SEARCH: 939 case SUBMIT: 940 case TELEPHONE: 941 case TEXT: 942 case TIME: 943 case URL: 944 case WEEK: 945 result = value(); 946 return true; 947 case CHECKBOX: 948 case RADIO: 949 result = checked() ? "on" : "off"; 950 return true; 951 case PASSWORD: 952 return false; 953 } 954 ASSERT_NOT_REACHED(); 955 return false; 956 } 957 958 void HTMLInputElement::restoreFormControlState(const String& state) 959 { 960 ASSERT(inputType() != PASSWORD); // should never save/restore password fields 961 switch (inputType()) { 962 case BUTTON: 963 case COLOR: 964 case DATE: 965 case DATETIME: 966 case DATETIMELOCAL: 967 case EMAIL: 968 case FILE: 969 case HIDDEN: 970 case IMAGE: 971 case ISINDEX: 972 case MONTH: 973 case NUMBER: 974 case RANGE: 975 case RESET: 976 case SEARCH: 977 case SUBMIT: 978 case TELEPHONE: 979 case TEXT: 980 case TIME: 981 case URL: 982 case WEEK: 983 setValue(state); 984 break; 985 case CHECKBOX: 986 case RADIO: 987 setChecked(state == "on"); 988 break; 989 case PASSWORD: 990 break; 991 } 992 } 993 994 bool HTMLInputElement::canStartSelection() const 995 { 996 if (!isTextField()) 997 return false; 998 return HTMLFormControlElementWithState::canStartSelection(); 999 } 1000 1001 bool HTMLInputElement::canHaveSelection() const 1002 { 1003 return isTextField(); 1004 } 1005 1006 void HTMLInputElement::accessKeyAction(bool sendToAnyElement) 1007 { 1008 switch (inputType()) { 1009 case BUTTON: 1010 case CHECKBOX: 1011 case FILE: 1012 case IMAGE: 1013 case RADIO: 1014 case RANGE: 1015 case RESET: 1016 case SUBMIT: 1017 focus(false); 1018 // send the mouse button events iff the caller specified sendToAnyElement 1019 dispatchSimulatedClick(0, sendToAnyElement); 1020 break; 1021 case HIDDEN: 1022 // a no-op for this type 1023 break; 1024 case COLOR: 1025 case DATE: 1026 case DATETIME: 1027 case DATETIMELOCAL: 1028 case EMAIL: 1029 case ISINDEX: 1030 case MONTH: 1031 case NUMBER: 1032 case PASSWORD: 1033 case SEARCH: 1034 case TELEPHONE: 1035 case TEXT: 1036 case TIME: 1037 case URL: 1038 case WEEK: 1039 // should never restore previous selection here 1040 focus(false); 1041 break; 1042 } 1043 } 1044 1045 bool HTMLInputElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const 1046 { 1047 if (((attrName == heightAttr || attrName == widthAttr) && respectHeightAndWidthAttrs()) || 1048 attrName == vspaceAttr || 1049 attrName == hspaceAttr) { 1050 result = eUniversal; 1051 return false; 1052 } 1053 1054 if (attrName == alignAttr) { 1055 if (inputType() == IMAGE) { 1056 // Share with <img> since the alignment behavior is the same. 1057 result = eReplaced; 1058 return false; 1059 } 1060 } 1061 1062 return HTMLElement::mapToEntry(attrName, result); 1063 } 1064 1065 void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) 1066 { 1067 if (attr->name() == nameAttr) { 1068 checkedRadioButtons(this).removeButton(this); 1069 m_data.setName(attr->value()); 1070 checkedRadioButtons(this).addButton(this); 1071 HTMLFormControlElementWithState::parseMappedAttribute(attr); 1072 } else if (attr->name() == autocompleteAttr) { 1073 if (equalIgnoringCase(attr->value(), "off")) { 1074 m_autocomplete = Off; 1075 registerForActivationCallbackIfNeeded(); 1076 } else { 1077 bool needsToUnregister = m_autocomplete == Off; 1078 1079 if (attr->isEmpty()) 1080 m_autocomplete = Uninitialized; 1081 else 1082 m_autocomplete = On; 1083 1084 if (needsToUnregister) 1085 unregisterForActivationCallbackIfNeeded(); 1086 } 1087 } else if (attr->name() == typeAttr) { 1088 setInputType(attr->value()); 1089 } else if (attr->name() == valueAttr) { 1090 // We only need to setChanged if the form is looking at the default value right now. 1091 if (m_data.value().isNull()) 1092 setNeedsStyleRecalc(); 1093 setFormControlValueMatchesRenderer(false); 1094 setNeedsValidityCheck(); 1095 } else if (attr->name() == checkedAttr) { 1096 m_defaultChecked = !attr->isNull(); 1097 if (m_useDefaultChecked) { 1098 setChecked(m_defaultChecked); 1099 m_useDefaultChecked = true; 1100 } 1101 setNeedsValidityCheck(); 1102 } else if (attr->name() == maxlengthAttr) { 1103 InputElement::parseMaxLengthAttribute(m_data, this, this, attr); 1104 setNeedsValidityCheck(); 1105 } else if (attr->name() == sizeAttr) 1106 InputElement::parseSizeAttribute(m_data, this, attr); 1107 else if (attr->name() == altAttr) { 1108 if (renderer() && inputType() == IMAGE) 1109 toRenderImage(renderer())->updateAltText(); 1110 } else if (attr->name() == srcAttr) { 1111 if (renderer() && inputType() == IMAGE) { 1112 if (!m_imageLoader) 1113 m_imageLoader.set(new HTMLImageLoader(this)); 1114 m_imageLoader->updateFromElementIgnoringPreviousError(); 1115 } 1116 } else if (attr->name() == usemapAttr || 1117 attr->name() == accesskeyAttr) { 1118 // FIXME: ignore for the moment 1119 } else if (attr->name() == vspaceAttr) { 1120 addCSSLength(attr, CSSPropertyMarginTop, attr->value()); 1121 addCSSLength(attr, CSSPropertyMarginBottom, attr->value()); 1122 } else if (attr->name() == hspaceAttr) { 1123 addCSSLength(attr, CSSPropertyMarginLeft, attr->value()); 1124 addCSSLength(attr, CSSPropertyMarginRight, attr->value()); 1125 } else if (attr->name() == alignAttr) { 1126 if (inputType() == IMAGE) 1127 addHTMLAlignment(attr); 1128 } else if (attr->name() == widthAttr) { 1129 if (respectHeightAndWidthAttrs()) 1130 addCSSLength(attr, CSSPropertyWidth, attr->value()); 1131 } else if (attr->name() == heightAttr) { 1132 if (respectHeightAndWidthAttrs()) 1133 addCSSLength(attr, CSSPropertyHeight, attr->value()); 1134 } 1135 // Search field and slider attributes all just cause updateFromElement to be called through style 1136 // recalcing. 1137 else if (attr->name() == onsearchAttr) { 1138 setAttributeEventListener(eventNames().searchEvent, createAttributeEventListener(this, attr)); 1139 } else if (attr->name() == resultsAttr) { 1140 int oldResults = m_maxResults; 1141 m_maxResults = !attr->isNull() ? std::min(attr->value().toInt(), maxSavedResults) : -1; 1142 // FIXME: Detaching just for maxResults change is not ideal. We should figure out the right 1143 // time to relayout for this change. 1144 if (m_maxResults != oldResults && (m_maxResults <= 0 || oldResults <= 0) && attached()) { 1145 detach(); 1146 attach(); 1147 } 1148 setNeedsStyleRecalc(); 1149 } else if (attr->name() == autosaveAttr 1150 || attr->name() == incrementalAttr) 1151 setNeedsStyleRecalc(); 1152 else if (attr->name() == minAttr 1153 || attr->name() == maxAttr 1154 || attr->name() == multipleAttr 1155 || attr->name() == patternAttr 1156 || attr->name() == precisionAttr 1157 || attr->name() == stepAttr) 1158 setNeedsValidityCheck(); 1159 #if ENABLE(DATALIST) 1160 else if (attr->name() == listAttr) 1161 m_hasNonEmptyList = !attr->isEmpty(); 1162 // FIXME: we need to tell this change to a renderer if the attribute affects the appearance. 1163 #endif 1164 else 1165 HTMLTextFormControlElement::parseMappedAttribute(attr); 1166 } 1167 1168 bool HTMLInputElement::rendererIsNeeded(RenderStyle *style) 1169 { 1170 if (inputType() == HIDDEN) 1171 return false; 1172 return HTMLFormControlElementWithState::rendererIsNeeded(style); 1173 } 1174 1175 RenderObject *HTMLInputElement::createRenderer(RenderArena *arena, RenderStyle *style) 1176 { 1177 switch (inputType()) { 1178 case BUTTON: 1179 case RESET: 1180 case SUBMIT: 1181 return new (arena) RenderButton(this); 1182 case CHECKBOX: 1183 case RADIO: 1184 return RenderObject::createObject(this, style); 1185 case FILE: 1186 return new (arena) RenderFileUploadControl(this); 1187 case HIDDEN: 1188 break; 1189 case IMAGE: 1190 return new (arena) RenderImage(this); 1191 case RANGE: 1192 return new (arena) RenderSlider(this); 1193 case COLOR: 1194 case DATE: 1195 case DATETIME: 1196 case DATETIMELOCAL: 1197 case EMAIL: 1198 case ISINDEX: 1199 case MONTH: 1200 case NUMBER: 1201 case PASSWORD: 1202 case SEARCH: 1203 case TELEPHONE: 1204 case TEXT: 1205 case TIME: 1206 case URL: 1207 case WEEK: 1208 return new (arena) RenderTextControlSingleLine(this, placeholderShouldBeVisible()); 1209 } 1210 ASSERT(false); 1211 return 0; 1212 } 1213 1214 void HTMLInputElement::attach() 1215 { 1216 if (!m_inited) { 1217 if (!m_haveType) 1218 setInputType(getAttribute(typeAttr)); 1219 m_inited = true; 1220 } 1221 1222 HTMLFormControlElementWithState::attach(); 1223 1224 if (inputType() == IMAGE) { 1225 if (!m_imageLoader) 1226 m_imageLoader.set(new HTMLImageLoader(this)); 1227 m_imageLoader->updateFromElement(); 1228 if (renderer() && m_imageLoader->haveFiredBeforeLoadEvent()) { 1229 RenderImage* imageObj = toRenderImage(renderer()); 1230 imageObj->setCachedImage(m_imageLoader->image()); 1231 1232 // If we have no image at all because we have no src attribute, set 1233 // image height and width for the alt text instead. 1234 if (!m_imageLoader->image() && !imageObj->cachedImage()) 1235 imageObj->setImageSizeForAltText(); 1236 } 1237 } 1238 1239 if (document()->focusedNode() == this) 1240 document()->updateFocusAppearanceSoon(true /* restore selection */); 1241 } 1242 1243 void HTMLInputElement::detach() 1244 { 1245 HTMLFormControlElementWithState::detach(); 1246 setFormControlValueMatchesRenderer(false); 1247 } 1248 1249 String HTMLInputElement::altText() const 1250 { 1251 // http://www.w3.org/TR/1998/REC-html40-19980424/appendix/notes.html#altgen 1252 // also heavily discussed by Hixie on bugzilla 1253 // note this is intentionally different to HTMLImageElement::altText() 1254 String alt = getAttribute(altAttr); 1255 // fall back to title attribute 1256 if (alt.isNull()) 1257 alt = getAttribute(titleAttr); 1258 if (alt.isNull()) 1259 alt = getAttribute(valueAttr); 1260 if (alt.isEmpty()) 1261 alt = inputElementAltText(); 1262 return alt; 1263 } 1264 1265 bool HTMLInputElement::isSuccessfulSubmitButton() const 1266 { 1267 // HTML spec says that buttons must have names to be considered successful. 1268 // However, other browsers do not impose this constraint. So we do likewise. 1269 return !disabled() && (inputType() == IMAGE || inputType() == SUBMIT); 1270 } 1271 1272 bool HTMLInputElement::isActivatedSubmit() const 1273 { 1274 return m_activeSubmit; 1275 } 1276 1277 void HTMLInputElement::setActivatedSubmit(bool flag) 1278 { 1279 m_activeSubmit = flag; 1280 } 1281 1282 bool HTMLInputElement::appendFormData(FormDataList& encoding, bool multipart) 1283 { 1284 // image generates its own names, but for other types there is no form data unless there's a name 1285 if (name().isEmpty() && inputType() != IMAGE) 1286 return false; 1287 1288 switch (inputType()) { 1289 case COLOR: 1290 case DATE: 1291 case DATETIME: 1292 case DATETIMELOCAL: 1293 case EMAIL: 1294 case HIDDEN: 1295 case ISINDEX: 1296 case MONTH: 1297 case NUMBER: 1298 case PASSWORD: 1299 case RANGE: 1300 case SEARCH: 1301 case TELEPHONE: 1302 case TEXT: 1303 case TIME: 1304 case URL: 1305 case WEEK: 1306 // always successful 1307 encoding.appendData(name(), value()); 1308 return true; 1309 1310 case CHECKBOX: 1311 case RADIO: 1312 if (checked()) { 1313 encoding.appendData(name(), value()); 1314 return true; 1315 } 1316 break; 1317 1318 case BUTTON: 1319 case RESET: 1320 // these types of buttons are never successful 1321 return false; 1322 1323 case IMAGE: 1324 if (m_activeSubmit) { 1325 encoding.appendData(name().isEmpty() ? "x" : (name() + ".x"), m_xPos); 1326 encoding.appendData(name().isEmpty() ? "y" : (name() + ".y"), m_yPos); 1327 if (!name().isEmpty() && !value().isEmpty()) 1328 encoding.appendData(name(), value()); 1329 return true; 1330 } 1331 break; 1332 1333 case SUBMIT: 1334 if (m_activeSubmit) { 1335 String enc_str = valueWithDefault(); 1336 encoding.appendData(name(), enc_str); 1337 return true; 1338 } 1339 break; 1340 1341 case FILE: { 1342 unsigned numFiles = m_fileList->length(); 1343 if (!multipart) { 1344 // Send only the basenames. 1345 // 4.10.16.4 and 4.10.16.6 sections in HTML5. 1346 1347 // Unlike the multipart case, we have no special 1348 // handling for the empty fileList because Netscape 1349 // doesn't support for non-multipart submission of 1350 // file inputs, and Firefox doesn't add "name=" query 1351 // parameter. 1352 1353 for (unsigned i = 0; i < numFiles; ++i) { 1354 encoding.appendData(name(), m_fileList->item(i)->fileName()); 1355 } 1356 return true; 1357 } 1358 1359 // If no filename at all is entered, return successful but empty. 1360 // Null would be more logical, but Netscape posts an empty file. Argh. 1361 if (!numFiles) { 1362 encoding.appendFile(name(), File::create("")); 1363 return true; 1364 } 1365 1366 for (unsigned i = 0; i < numFiles; ++i) 1367 encoding.appendFile(name(), m_fileList->item(i)); 1368 return true; 1369 } 1370 } 1371 return false; 1372 } 1373 1374 void HTMLInputElement::reset() 1375 { 1376 if (storesValueSeparateFromAttribute()) 1377 setValue(String()); 1378 1379 setChecked(m_defaultChecked); 1380 m_useDefaultChecked = true; 1381 } 1382 1383 bool HTMLInputElement::isTextField() const 1384 { 1385 switch (inputType()) { 1386 case COLOR: 1387 case DATE: 1388 case DATETIME: 1389 case DATETIMELOCAL: 1390 case EMAIL: 1391 case ISINDEX: 1392 case MONTH: 1393 case NUMBER: 1394 case PASSWORD: 1395 case SEARCH: 1396 case TELEPHONE: 1397 case TEXT: 1398 case TIME: 1399 case URL: 1400 case WEEK: 1401 return true; 1402 case BUTTON: 1403 case CHECKBOX: 1404 case FILE: 1405 case HIDDEN: 1406 case IMAGE: 1407 case RADIO: 1408 case RANGE: 1409 case RESET: 1410 case SUBMIT: 1411 return false; 1412 } 1413 ASSERT_NOT_REACHED(); 1414 return false; 1415 } 1416 1417 void HTMLInputElement::setChecked(bool nowChecked, bool sendChangeEvent) 1418 { 1419 if (checked() == nowChecked) 1420 return; 1421 1422 checkedRadioButtons(this).removeButton(this); 1423 1424 m_useDefaultChecked = false; 1425 m_checked = nowChecked; 1426 setNeedsStyleRecalc(); 1427 1428 checkedRadioButtons(this).addButton(this); 1429 1430 if (renderer() && renderer()->style()->hasAppearance()) 1431 renderer()->theme()->stateChanged(renderer(), CheckedState); 1432 1433 // Ideally we'd do this from the render tree (matching 1434 // RenderTextView), but it's not possible to do it at the moment 1435 // because of the way the code is structured. 1436 if (renderer() && AXObjectCache::accessibilityEnabled()) 1437 renderer()->document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXCheckedStateChanged, true); 1438 1439 // Only send a change event for items in the document (avoid firing during 1440 // parsing) and don't send a change event for a radio button that's getting 1441 // unchecked to match other browsers. DOM is not a useful standard for this 1442 // because it says only to fire change events at "lose focus" time, which is 1443 // definitely wrong in practice for these types of elements. 1444 if (sendChangeEvent && inDocument() && (inputType() != RADIO || nowChecked)) 1445 dispatchFormControlChangeEvent(); 1446 } 1447 1448 void HTMLInputElement::setIndeterminate(bool _indeterminate) 1449 { 1450 // Only checkboxes honor indeterminate. 1451 if (inputType() != CHECKBOX || indeterminate() == _indeterminate) 1452 return; 1453 1454 m_indeterminate = _indeterminate; 1455 1456 setNeedsStyleRecalc(); 1457 1458 if (renderer() && renderer()->style()->hasAppearance()) 1459 renderer()->theme()->stateChanged(renderer(), CheckedState); 1460 } 1461 1462 int HTMLInputElement::size() const 1463 { 1464 return m_data.size(); 1465 } 1466 1467 void HTMLInputElement::copyNonAttributeProperties(const Element* source) 1468 { 1469 const HTMLInputElement* sourceElement = static_cast<const HTMLInputElement*>(source); 1470 1471 m_data.setValue(sourceElement->m_data.value()); 1472 setChecked(sourceElement->m_checked); 1473 m_defaultChecked = sourceElement->m_defaultChecked; 1474 m_useDefaultChecked = sourceElement->m_useDefaultChecked; 1475 m_indeterminate = sourceElement->m_indeterminate; 1476 1477 HTMLFormControlElementWithState::copyNonAttributeProperties(source); 1478 } 1479 1480 String HTMLInputElement::value() const 1481 { 1482 // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control 1483 // but we don't want to break existing websites, who may be relying on being able to get the file name as a value. 1484 if (inputType() == FILE) { 1485 if (!m_fileList->isEmpty()) 1486 return m_fileList->item(0)->fileName(); 1487 return String(); 1488 } 1489 1490 String value = m_data.value(); 1491 if (value.isNull()) { 1492 value = sanitizeValue(getAttribute(valueAttr)); 1493 1494 // If no attribute exists, then just use "on" or "" based off the checked() state of the control. 1495 if (value.isNull() && (inputType() == CHECKBOX || inputType() == RADIO)) 1496 return checked() ? "on" : ""; 1497 } 1498 1499 return value; 1500 } 1501 1502 String HTMLInputElement::valueWithDefault() const 1503 { 1504 String v = value(); 1505 if (v.isNull()) { 1506 switch (inputType()) { 1507 case BUTTON: 1508 case CHECKBOX: 1509 case COLOR: 1510 case DATE: 1511 case DATETIME: 1512 case DATETIMELOCAL: 1513 case EMAIL: 1514 case FILE: 1515 case HIDDEN: 1516 case IMAGE: 1517 case ISINDEX: 1518 case MONTH: 1519 case NUMBER: 1520 case PASSWORD: 1521 case RADIO: 1522 case RANGE: 1523 case SEARCH: 1524 case TELEPHONE: 1525 case TEXT: 1526 case TIME: 1527 case URL: 1528 case WEEK: 1529 break; 1530 case RESET: 1531 v = resetButtonDefaultLabel(); 1532 break; 1533 case SUBMIT: 1534 v = submitButtonDefaultLabel(); 1535 break; 1536 } 1537 } 1538 return v; 1539 } 1540 1541 void HTMLInputElement::setValueForUser(const String& value) 1542 { 1543 // Call setValue and make it send a change event. 1544 setValue(value, true); 1545 } 1546 1547 const String& HTMLInputElement::suggestedValue() const 1548 { 1549 return m_data.suggestedValue(); 1550 } 1551 1552 void HTMLInputElement::setSuggestedValue(const String& value) 1553 { 1554 if (inputType() != TEXT) 1555 return; 1556 setFormControlValueMatchesRenderer(false); 1557 m_data.setSuggestedValue(sanitizeValue(value)); 1558 updatePlaceholderVisibility(false); 1559 if (renderer()) 1560 renderer()->updateFromElement(); 1561 setNeedsStyleRecalc(); 1562 } 1563 1564 void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) 1565 { 1566 // For security reasons, we don't allow setting the filename, but we do allow clearing it. 1567 // The HTML5 spec (as of the 10/24/08 working draft) says that the value attribute isn't applicable to the file upload control 1568 // but we don't want to break existing websites, who may be relying on this method to clear things. 1569 if (inputType() == FILE && !value.isEmpty()) 1570 return; 1571 1572 setFormControlValueMatchesRenderer(false); 1573 if (storesValueSeparateFromAttribute()) { 1574 if (inputType() == FILE) 1575 m_fileList->clear(); 1576 else { 1577 m_data.setValue(sanitizeValue(value)); 1578 if (isTextField()) { 1579 updatePlaceholderVisibility(false); 1580 if (inDocument()) 1581 document()->updateStyleIfNeeded(); 1582 } 1583 } 1584 if (renderer()) 1585 renderer()->updateFromElement(); 1586 setNeedsStyleRecalc(); 1587 } else 1588 setAttribute(valueAttr, sanitizeValue(value)); 1589 1590 if (isTextField()) { 1591 unsigned max = m_data.value().length(); 1592 #ifdef ANDROID_ACCEPT_CHANGES_TO_FOCUSED_TEXTFIELDS 1593 // Make sure our UI side textfield changes to match the RenderTextControl 1594 android::WebViewCore::getWebViewCore(document()->view())->updateTextfield(this, false, value); 1595 #endif 1596 if (document()->focusedNode() == this) 1597 InputElement::updateSelectionRange(this, this, max, max); 1598 else 1599 cacheSelection(max, max); 1600 m_data.setSuggestedValue(String()); 1601 } 1602 1603 // Don't dispatch the change event when focused, it will be dispatched 1604 // when the control loses focus. 1605 if (sendChangeEvent && document()->focusedNode() != this) 1606 dispatchFormControlChangeEvent(); 1607 1608 InputElement::notifyFormStateChanged(this); 1609 setNeedsValidityCheck(); 1610 } 1611 1612 double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const 1613 { 1614 switch (inputType()) { 1615 case DATE: 1616 case DATETIME: 1617 case DATETIMELOCAL: 1618 case TIME: 1619 case WEEK: { 1620 DateComponents date; 1621 if (!formStringToDateComponents(inputType(), src, &date)) 1622 return defaultValue; 1623 double msec = date.millisecondsSinceEpoch(); 1624 ASSERT(isfinite(msec)); 1625 return msec; 1626 } 1627 case MONTH: { 1628 DateComponents date; 1629 if (!formStringToDateComponents(inputType(), src, &date)) 1630 return defaultValue; 1631 double months = date.monthsSinceEpoch(); 1632 ASSERT(isfinite(months)); 1633 return months; 1634 } 1635 case NUMBER: 1636 case RANGE: { 1637 double numberValue; 1638 if (!formStringToDouble(src, &numberValue)) 1639 return defaultValue; 1640 ASSERT(isfinite(numberValue)); 1641 return numberValue; 1642 } 1643 1644 case BUTTON: 1645 case CHECKBOX: 1646 case COLOR: 1647 case EMAIL: 1648 case FILE: 1649 case HIDDEN: 1650 case IMAGE: 1651 case ISINDEX: 1652 case PASSWORD: 1653 case RADIO: 1654 case RESET: 1655 case SEARCH: 1656 case SUBMIT: 1657 case TELEPHONE: 1658 case TEXT: 1659 case URL: 1660 return defaultValue; 1661 } 1662 ASSERT_NOT_REACHED(); 1663 return defaultValue; 1664 } 1665 1666 double HTMLInputElement::valueAsDate() const 1667 { 1668 switch (inputType()) { 1669 case DATE: 1670 case DATETIME: 1671 case TIME: 1672 case WEEK: 1673 return parseToDouble(value(), DateComponents::invalidMilliseconds()); 1674 case MONTH: { 1675 DateComponents date; 1676 if (!formStringToDateComponents(inputType(), value(), &date)) 1677 return DateComponents::invalidMilliseconds(); 1678 double msec = date.millisecondsSinceEpoch(); 1679 ASSERT(isfinite(msec)); 1680 return msec; 1681 } 1682 1683 case BUTTON: 1684 case CHECKBOX: 1685 case COLOR: 1686 case DATETIMELOCAL: // valueAsDate doesn't work for the DATETIMELOCAL type according to the standard. 1687 case EMAIL: 1688 case FILE: 1689 case HIDDEN: 1690 case IMAGE: 1691 case ISINDEX: 1692 case NUMBER: 1693 case PASSWORD: 1694 case RADIO: 1695 case RANGE: 1696 case RESET: 1697 case SEARCH: 1698 case SUBMIT: 1699 case TELEPHONE: 1700 case TEXT: 1701 case URL: 1702 return DateComponents::invalidMilliseconds(); 1703 } 1704 ASSERT_NOT_REACHED(); 1705 return DateComponents::invalidMilliseconds(); 1706 } 1707 1708 void HTMLInputElement::setValueAsDate(double value, ExceptionCode& ec) 1709 { 1710 DateComponents date; 1711 bool success; 1712 switch (inputType()) { 1713 case DATE: 1714 success = date.setMillisecondsSinceEpochForDate(value); 1715 break; 1716 case DATETIME: 1717 success = date.setMillisecondsSinceEpochForDateTime(value); 1718 break; 1719 case MONTH: 1720 success = date.setMillisecondsSinceEpochForMonth(value); 1721 break; 1722 case TIME: 1723 success = date.setMillisecondsSinceMidnight(value); 1724 break; 1725 case WEEK: 1726 success = date.setMillisecondsSinceEpochForWeek(value); 1727 break; 1728 case BUTTON: 1729 case CHECKBOX: 1730 case COLOR: 1731 case DATETIMELOCAL: // valueAsDate doesn't work for the DATETIMELOCAL type according to the standard. 1732 case EMAIL: 1733 case FILE: 1734 case HIDDEN: 1735 case IMAGE: 1736 case ISINDEX: 1737 case NUMBER: 1738 case PASSWORD: 1739 case RADIO: 1740 case RANGE: 1741 case RESET: 1742 case SEARCH: 1743 case SUBMIT: 1744 case TELEPHONE: 1745 case TEXT: 1746 case URL: 1747 ec = INVALID_STATE_ERR; 1748 return; 1749 default: 1750 ASSERT_NOT_REACHED(); 1751 success = false; 1752 } 1753 if (!success) { 1754 setValue(String()); 1755 return; 1756 } 1757 setDateValue(date); 1758 } 1759 1760 void HTMLInputElement::setDateValue(const DateComponents& date) 1761 { 1762 double step; 1763 if (!getAllowedValueStep(&step)) { 1764 setValue(date.toString()); 1765 return; 1766 } 1767 if (!fmod(step, msecPerMinute)) { 1768 setValue(date.toString(DateComponents::None)); 1769 return; 1770 } 1771 if (!fmod(step, msecPerSecond)) { 1772 setValue(date.toString(DateComponents::Second)); 1773 return; 1774 } 1775 setValue(date.toString(DateComponents::Millisecond)); 1776 } 1777 1778 double HTMLInputElement::valueAsNumber() const 1779 { 1780 const double nan = numeric_limits<double>::quiet_NaN(); 1781 switch (inputType()) { 1782 case DATE: 1783 case DATETIME: 1784 case DATETIMELOCAL: 1785 case MONTH: 1786 case NUMBER: 1787 case RANGE: 1788 case TIME: 1789 case WEEK: 1790 return parseToDouble(value(), nan); 1791 1792 case BUTTON: 1793 case CHECKBOX: 1794 case COLOR: 1795 case EMAIL: 1796 case FILE: 1797 case HIDDEN: 1798 case IMAGE: 1799 case ISINDEX: 1800 case PASSWORD: 1801 case RADIO: 1802 case RESET: 1803 case SEARCH: 1804 case SUBMIT: 1805 case TELEPHONE: 1806 case TEXT: 1807 case URL: 1808 return nan; 1809 } 1810 ASSERT_NOT_REACHED(); 1811 return nan; 1812 } 1813 1814 void HTMLInputElement::setValueAsNumber(double newValue, ExceptionCode& ec) 1815 { 1816 if (!isfinite(newValue)) { 1817 ec = NOT_SUPPORTED_ERR; 1818 return; 1819 } 1820 switch (inputType()) { 1821 case DATE: 1822 case DATETIME: 1823 case TIME: 1824 case WEEK: 1825 setValueAsDate(newValue, ec); 1826 return; 1827 case MONTH: { 1828 DateComponents date; 1829 if (!date.setMonthsSinceEpoch(newValue)) { 1830 setValue(String()); 1831 return; 1832 } 1833 setValue(date.toString()); 1834 return; 1835 } 1836 case DATETIMELOCAL: { 1837 DateComponents date; 1838 if (!date.setMillisecondsSinceEpochForDateTimeLocal(newValue)) { 1839 setValue(String()); 1840 return; 1841 } 1842 setDateValue(date); 1843 return; 1844 } 1845 case NUMBER: 1846 case RANGE: 1847 setValue(formStringFromDouble(newValue)); 1848 return; 1849 1850 case BUTTON: 1851 case CHECKBOX: 1852 case COLOR: 1853 case EMAIL: 1854 case FILE: 1855 case HIDDEN: 1856 case IMAGE: 1857 case ISINDEX: 1858 case PASSWORD: 1859 case RADIO: 1860 case RESET: 1861 case SEARCH: 1862 case SUBMIT: 1863 case TELEPHONE: 1864 case TEXT: 1865 case URL: 1866 ec = INVALID_STATE_ERR; 1867 return; 1868 } 1869 ASSERT_NOT_REACHED(); 1870 return; 1871 } 1872 1873 String HTMLInputElement::placeholder() const 1874 { 1875 return getAttribute(placeholderAttr).string(); 1876 } 1877 1878 void HTMLInputElement::setPlaceholder(const String& value) 1879 { 1880 setAttribute(placeholderAttr, value); 1881 } 1882 1883 bool HTMLInputElement::searchEventsShouldBeDispatched() const 1884 { 1885 return hasAttribute(incrementalAttr); 1886 } 1887 1888 void HTMLInputElement::setValueFromRenderer(const String& value) 1889 { 1890 // File upload controls will always use setFileListFromRenderer. 1891 ASSERT(inputType() != FILE); 1892 m_data.setSuggestedValue(String()); 1893 updatePlaceholderVisibility(false); 1894 InputElement::setValueFromRenderer(m_data, this, this, value); 1895 setNeedsValidityCheck(); 1896 } 1897 1898 void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) 1899 { 1900 m_fileList->clear(); 1901 int size = paths.size(); 1902 for (int i = 0; i < size; i++) 1903 m_fileList->append(File::create(paths[i])); 1904 1905 setFormControlValueMatchesRenderer(true); 1906 InputElement::notifyFormStateChanged(this); 1907 setNeedsValidityCheck(); 1908 } 1909 1910 bool HTMLInputElement::storesValueSeparateFromAttribute() const 1911 { 1912 switch (inputType()) { 1913 case BUTTON: 1914 case CHECKBOX: 1915 case HIDDEN: 1916 case IMAGE: 1917 case RADIO: 1918 case RESET: 1919 case SUBMIT: 1920 return false; 1921 case COLOR: 1922 case DATE: 1923 case DATETIME: 1924 case DATETIMELOCAL: 1925 case EMAIL: 1926 case FILE: 1927 case ISINDEX: 1928 case MONTH: 1929 case NUMBER: 1930 case PASSWORD: 1931 case RANGE: 1932 case SEARCH: 1933 case TELEPHONE: 1934 case TEXT: 1935 case TIME: 1936 case URL: 1937 case WEEK: 1938 return true; 1939 } 1940 return false; 1941 } 1942 1943 void* HTMLInputElement::preDispatchEventHandler(Event *evt) 1944 { 1945 // preventDefault or "return false" are used to reverse the automatic checking/selection we do here. 1946 // This result gives us enough info to perform the "undo" in postDispatch of the action we take here. 1947 void* result = 0; 1948 if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() 1949 && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 1950 if (inputType() == CHECKBOX) { 1951 // As a way to store the state, we return 0 if we were unchecked, 1 if we were checked, and 2 for 1952 // indeterminate. 1953 if (indeterminate()) { 1954 result = (void*)0x2; 1955 setIndeterminate(false); 1956 } else { 1957 if (checked()) 1958 result = (void*)0x1; 1959 setChecked(!checked(), true); 1960 } 1961 } else { 1962 // For radio buttons, store the current selected radio object. 1963 // We really want radio groups to end up in sane states, i.e., to have something checked. 1964 // Therefore if nothing is currently selected, we won't allow this action to be "undone", since 1965 // we want some object in the radio group to actually get selected. 1966 HTMLInputElement* currRadio = checkedRadioButtons(this).checkedButtonForGroup(name()); 1967 if (currRadio) { 1968 // We have a radio button selected that is not us. Cache it in our result field and ref it so 1969 // that it can't be destroyed. 1970 currRadio->ref(); 1971 result = currRadio; 1972 } 1973 setChecked(true, true); 1974 } 1975 } 1976 return result; 1977 } 1978 1979 void HTMLInputElement::postDispatchEventHandler(Event *evt, void* data) 1980 { 1981 if ((inputType() == CHECKBOX || inputType() == RADIO) && evt->isMouseEvent() 1982 && evt->type() == eventNames().clickEvent && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 1983 if (inputType() == CHECKBOX) { 1984 // Reverse the checking we did in preDispatch. 1985 if (evt->defaultPrevented() || evt->defaultHandled()) { 1986 if (data == (void*)0x2) 1987 setIndeterminate(true); 1988 else 1989 setChecked(data); 1990 } 1991 } else if (data) { 1992 HTMLInputElement* input = static_cast<HTMLInputElement*>(data); 1993 if (evt->defaultPrevented() || evt->defaultHandled()) { 1994 // Restore the original selected radio button if possible. 1995 // Make sure it is still a radio button and only do the restoration if it still 1996 // belongs to our group. 1997 1998 if (input->form() == form() && input->inputType() == RADIO && input->name() == name()) { 1999 // Ok, the old radio button is still in our form and in our group and is still a 2000 // radio button, so it's safe to restore selection to it. 2001 input->setChecked(true); 2002 } 2003 } 2004 input->deref(); 2005 } 2006 2007 // Left clicks on radio buttons and check boxes already performed default actions in preDispatchEventHandler(). 2008 evt->setDefaultHandled(); 2009 } 2010 } 2011 2012 void HTMLInputElement::defaultEventHandler(Event* evt) 2013 { 2014 // FIXME: It would be better to refactor this for the different types of input element. 2015 // Having them all in one giant function makes this hard to read, and almost all the handling is type-specific. 2016 2017 bool clickDefaultFormButton = false; 2018 2019 if (isTextField() && evt->type() == eventNames().textInputEvent && evt->isTextEvent() && static_cast<TextEvent*>(evt)->data() == "\n") 2020 clickDefaultFormButton = true; 2021 2022 if (inputType() == IMAGE && evt->isMouseEvent() && evt->type() == eventNames().clickEvent) { 2023 // record the mouse position for when we get the DOMActivate event 2024 MouseEvent* me = static_cast<MouseEvent*>(evt); 2025 // FIXME: We could just call offsetX() and offsetY() on the event, 2026 // but that's currently broken, so for now do the computation here. 2027 if (me->isSimulated() || !renderer()) { 2028 m_xPos = 0; 2029 m_yPos = 0; 2030 } else { 2031 // FIXME: This doesn't work correctly with transforms. 2032 // FIXME: pageX/pageY need adjusting for pageZoomFactor(). Use actualPageLocation()? 2033 IntPoint absOffset = roundedIntPoint(renderer()->localToAbsolute()); 2034 m_xPos = me->pageX() - absOffset.x(); 2035 m_yPos = me->pageY() - absOffset.y(); 2036 } 2037 } 2038 2039 if (isTextField() 2040 && evt->type() == eventNames().keydownEvent 2041 && evt->isKeyboardEvent() 2042 && focused() 2043 && document()->frame() 2044 && document()->frame()->doTextFieldCommandFromEvent(this, static_cast<KeyboardEvent*>(evt))) { 2045 evt->setDefaultHandled(); 2046 return; 2047 } 2048 2049 if (inputType() == RADIO 2050 && evt->isMouseEvent() 2051 && evt->type() == eventNames().clickEvent 2052 && static_cast<MouseEvent*>(evt)->button() == LeftButton) { 2053 evt->setDefaultHandled(); 2054 return; 2055 } 2056 2057 // Call the base event handler before any of our own event handling for almost all events in text fields. 2058 // Makes editing keyboard handling take precedence over the keydown and keypress handling in this function. 2059 bool callBaseClassEarly = isTextField() && !clickDefaultFormButton 2060 && (evt->type() == eventNames().keydownEvent || evt->type() == eventNames().keypressEvent); 2061 if (callBaseClassEarly) { 2062 HTMLFormControlElementWithState::defaultEventHandler(evt); 2063 if (evt->defaultHandled()) 2064 return; 2065 } 2066 2067 // DOMActivate events cause the input to be "activated" - in the case of image and submit inputs, this means 2068 // actually submitting the form. For reset inputs, the form is reset. These events are sent when the user clicks 2069 // on the element, or presses enter while it is the active element. JavaScript code wishing to activate the element 2070 // must dispatch a DOMActivate event - a click event will not do the job. 2071 if (evt->type() == eventNames().DOMActivateEvent && !disabled()) { 2072 if (inputType() == IMAGE || inputType() == SUBMIT || inputType() == RESET) { 2073 if (!form()) 2074 return; 2075 if (inputType() == RESET) 2076 form()->reset(); 2077 else { 2078 m_activeSubmit = true; 2079 // FIXME: Would be cleaner to get m_xPos and m_yPos out of the underlying mouse 2080 // event (if any) here instead of relying on the variables set above when 2081 // processing the click event. Even better, appendFormData could pass the 2082 // event in, and then we could get rid of m_xPos and m_yPos altogether! 2083 if (!form()->prepareSubmit(evt)) { 2084 m_xPos = 0; 2085 m_yPos = 0; 2086 } 2087 m_activeSubmit = false; 2088 } 2089 } else if (inputType() == FILE && renderer()) 2090 toRenderFileUploadControl(renderer())->click(); 2091 } 2092 2093 // Use key press event here since sending simulated mouse events 2094 // on key down blocks the proper sending of the key press event. 2095 if (evt->type() == eventNames().keypressEvent && evt->isKeyboardEvent()) { 2096 bool clickElement = false; 2097 2098 int charCode = static_cast<KeyboardEvent*>(evt)->charCode(); 2099 2100 if (charCode == '\r') { 2101 switch (inputType()) { 2102 case CHECKBOX: 2103 case COLOR: 2104 case DATE: 2105 case DATETIME: 2106 case DATETIMELOCAL: 2107 case EMAIL: 2108 case HIDDEN: 2109 case ISINDEX: 2110 case MONTH: 2111 case NUMBER: 2112 case PASSWORD: 2113 case RANGE: 2114 case SEARCH: 2115 case TELEPHONE: 2116 case TEXT: 2117 case TIME: 2118 case URL: 2119 case WEEK: 2120 // Simulate mouse click on the default form button for enter for these types of elements. 2121 clickDefaultFormButton = true; 2122 break; 2123 case BUTTON: 2124 case FILE: 2125 case IMAGE: 2126 case RESET: 2127 case SUBMIT: 2128 // Simulate mouse click for enter for these types of elements. 2129 clickElement = true; 2130 break; 2131 case RADIO: 2132 break; // Don't do anything for enter on a radio button. 2133 } 2134 } else if (charCode == ' ') { 2135 switch (inputType()) { 2136 case BUTTON: 2137 case CHECKBOX: 2138 case FILE: 2139 case IMAGE: 2140 case RESET: 2141 case SUBMIT: 2142 case RADIO: 2143 // Prevent scrolling down the page. 2144 evt->setDefaultHandled(); 2145 return; 2146 default: 2147 break; 2148 } 2149 } 2150 2151 if (clickElement) { 2152 dispatchSimulatedClick(evt); 2153 evt->setDefaultHandled(); 2154 return; 2155 } 2156 } 2157 2158 if (evt->type() == eventNames().keydownEvent && evt->isKeyboardEvent()) { 2159 String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); 2160 2161 if (key == "U+0020") { 2162 switch (inputType()) { 2163 case BUTTON: 2164 case CHECKBOX: 2165 case FILE: 2166 case IMAGE: 2167 case RESET: 2168 case SUBMIT: 2169 case RADIO: 2170 setActive(true, true); 2171 // No setDefaultHandled(), because IE dispatches a keypress in this case 2172 // and the caller will only dispatch a keypress if we don't call setDefaultHandled. 2173 return; 2174 default: 2175 break; 2176 } 2177 } 2178 2179 // allow enter to change state of radio 2180 if (inputType() == RADIO && (key == "Up" || key == "Down" || key == "Left" || key == "Right")) { 2181 // Left and up mean "previous radio button". 2182 // Right and down mean "next radio button". 2183 // Tested in WinIE, and even for RTL, left still means previous radio button (and so moves 2184 // to the right). Seems strange, but we'll match it. 2185 bool forward = (key == "Down" || key == "Right"); 2186 2187 // We can only stay within the form's children if the form hasn't been demoted to a leaf because 2188 // of malformed HTML. 2189 Node* n = this; 2190 while ((n = (forward ? n->traverseNextNode() : n->traversePreviousNode()))) { 2191 // Once we encounter a form element, we know we're through. 2192 if (n->hasTagName(formTag)) 2193 break; 2194 2195 // Look for more radio buttons. 2196 if (n->hasTagName(inputTag)) { 2197 HTMLInputElement* elt = static_cast<HTMLInputElement*>(n); 2198 if (elt->form() != form()) 2199 break; 2200 if (n->hasTagName(inputTag)) { 2201 HTMLInputElement* inputElt = static_cast<HTMLInputElement*>(n); 2202 if (inputElt->inputType() == RADIO && inputElt->name() == name() && inputElt->isFocusable()) { 2203 inputElt->setChecked(true); 2204 document()->setFocusedNode(inputElt); 2205 inputElt->dispatchSimulatedClick(evt, false, false); 2206 evt->setDefaultHandled(); 2207 break; 2208 } 2209 } 2210 } 2211 } 2212 } 2213 } 2214 2215 if (evt->type() == eventNames().keyupEvent && evt->isKeyboardEvent()) { 2216 bool clickElement = false; 2217 2218 String key = static_cast<KeyboardEvent*>(evt)->keyIdentifier(); 2219 2220 if (key == "U+0020") { 2221 switch (inputType()) { 2222 case BUTTON: 2223 case CHECKBOX: 2224 case FILE: 2225 case IMAGE: 2226 case RESET: 2227 case SUBMIT: 2228 // Simulate mouse click for spacebar for these types of elements. 2229 // The AppKit already does this for some, but not all, of them. 2230 clickElement = true; 2231 break; 2232 case RADIO: 2233 // If an unselected radio is tabbed into (because the entire group has nothing 2234 // checked, or because of some explicit .focus() call), then allow space to check it. 2235 if (!checked()) 2236 clickElement = true; 2237 break; 2238 case COLOR: 2239 case DATE: 2240 case DATETIME: 2241 case DATETIMELOCAL: 2242 case EMAIL: 2243 case HIDDEN: 2244 case ISINDEX: 2245 case MONTH: 2246 case NUMBER: 2247 case PASSWORD: 2248 case RANGE: 2249 case SEARCH: 2250 case TELEPHONE: 2251 case TEXT: 2252 case TIME: 2253 case URL: 2254 case WEEK: 2255 break; 2256 } 2257 } 2258 2259 if (clickElement) { 2260 if (active()) 2261 dispatchSimulatedClick(evt); 2262 evt->setDefaultHandled(); 2263 return; 2264 } 2265 } 2266 2267 if (clickDefaultFormButton) { 2268 if (isSearchField()) { 2269 addSearchResult(); 2270 onSearch(); 2271 } 2272 // Fire onChange for text fields. 2273 RenderObject* r = renderer(); 2274 if (r && r->isTextField() && toRenderTextControl(r)->wasChangedSinceLastChangeEvent()) { 2275 dispatchFormControlChangeEvent(); 2276 // Refetch the renderer since arbitrary JS code run during onchange can do anything, including destroying it. 2277 r = renderer(); 2278 if (r && r->isTextField()) 2279 toRenderTextControl(r)->setChangedSinceLastChangeEvent(false); 2280 } 2281 2282 RefPtr<HTMLFormElement> formForSubmission = form(); 2283 // If there is no form and the element is an <isindex>, then create a temporary form just to be used for submission. 2284 if (!formForSubmission && inputType() == ISINDEX) 2285 formForSubmission = createTemporaryFormForIsIndex(); 2286 2287 // Form may never have been present, or may have been destroyed by code responding to the change event. 2288 if (formForSubmission) 2289 formForSubmission->submitClick(evt); 2290 2291 evt->setDefaultHandled(); 2292 return; 2293 } 2294 2295 if (evt->isBeforeTextInsertedEvent()) 2296 InputElement::handleBeforeTextInsertedEvent(m_data, this, this, evt); 2297 2298 if (isTextField() && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent() || evt->type() == eventNames().blurEvent || evt->type() == eventNames().focusEvent)) 2299 toRenderTextControlSingleLine(renderer())->forwardEvent(evt); 2300 2301 if (inputType() == RANGE && renderer() && (evt->isMouseEvent() || evt->isDragEvent() || evt->isWheelEvent())) 2302 toRenderSlider(renderer())->forwardEvent(evt); 2303 2304 if (!callBaseClassEarly && !evt->defaultHandled()) 2305 HTMLFormControlElementWithState::defaultEventHandler(evt); 2306 } 2307 2308 PassRefPtr<HTMLFormElement> HTMLInputElement::createTemporaryFormForIsIndex() 2309 { 2310 RefPtr<HTMLFormElement> form = new HTMLFormElement(formTag, document()); 2311 form->registerFormElement(this); 2312 form->setMethod("GET"); 2313 if (!document()->baseURL().isEmpty()) { 2314 // We treat the href property of the <base> element as the form action, as per section 7.5 2315 // "Queries and Indexes" of the HTML 2.0 spec. <http://www.w3.org/MarkUp/html-spec/html-spec_7.html#SEC7.5>. 2316 form->setAction(document()->baseURL().string()); 2317 } 2318 return form.release(); 2319 } 2320 2321 bool HTMLInputElement::isURLAttribute(Attribute *attr) const 2322 { 2323 return (attr->name() == srcAttr); 2324 } 2325 2326 String HTMLInputElement::defaultValue() const 2327 { 2328 return getAttribute(valueAttr); 2329 } 2330 2331 void HTMLInputElement::setDefaultValue(const String &value) 2332 { 2333 setAttribute(valueAttr, value); 2334 } 2335 2336 bool HTMLInputElement::defaultChecked() const 2337 { 2338 return !getAttribute(checkedAttr).isNull(); 2339 } 2340 2341 void HTMLInputElement::setDefaultChecked(bool defaultChecked) 2342 { 2343 setAttribute(checkedAttr, defaultChecked ? "" : 0); 2344 } 2345 2346 void HTMLInputElement::setDefaultName(const AtomicString& name) 2347 { 2348 m_data.setName(name); 2349 } 2350 2351 String HTMLInputElement::accept() const 2352 { 2353 return getAttribute(acceptAttr); 2354 } 2355 2356 void HTMLInputElement::setAccept(const String &value) 2357 { 2358 setAttribute(acceptAttr, value); 2359 } 2360 2361 String HTMLInputElement::accessKey() const 2362 { 2363 return getAttribute(accesskeyAttr); 2364 } 2365 2366 void HTMLInputElement::setAccessKey(const String &value) 2367 { 2368 setAttribute(accesskeyAttr, value); 2369 } 2370 2371 String HTMLInputElement::align() const 2372 { 2373 return getAttribute(alignAttr); 2374 } 2375 2376 void HTMLInputElement::setAlign(const String &value) 2377 { 2378 setAttribute(alignAttr, value); 2379 } 2380 2381 String HTMLInputElement::alt() const 2382 { 2383 return getAttribute(altAttr); 2384 } 2385 2386 void HTMLInputElement::setAlt(const String &value) 2387 { 2388 setAttribute(altAttr, value); 2389 } 2390 2391 int HTMLInputElement::maxLength() const 2392 { 2393 return m_data.maxLength(); 2394 } 2395 2396 void HTMLInputElement::setMaxLength(int maxLength, ExceptionCode& ec) 2397 { 2398 if (maxLength < 0) 2399 ec = INDEX_SIZE_ERR; 2400 else 2401 setAttribute(maxlengthAttr, String::number(maxLength)); 2402 } 2403 2404 bool HTMLInputElement::multiple() const 2405 { 2406 return !getAttribute(multipleAttr).isNull(); 2407 } 2408 2409 void HTMLInputElement::setMultiple(bool multiple) 2410 { 2411 setAttribute(multipleAttr, multiple ? "" : 0); 2412 } 2413 2414 void HTMLInputElement::setSize(unsigned _size) 2415 { 2416 setAttribute(sizeAttr, String::number(_size)); 2417 } 2418 2419 KURL HTMLInputElement::src() const 2420 { 2421 return document()->completeURL(getAttribute(srcAttr)); 2422 } 2423 2424 void HTMLInputElement::setSrc(const String &value) 2425 { 2426 setAttribute(srcAttr, value); 2427 } 2428 2429 String HTMLInputElement::useMap() const 2430 { 2431 return getAttribute(usemapAttr); 2432 } 2433 2434 void HTMLInputElement::setUseMap(const String &value) 2435 { 2436 setAttribute(usemapAttr, value); 2437 } 2438 2439 void HTMLInputElement::setAutofilled(bool b) 2440 { 2441 if (b == m_autofilled) 2442 return; 2443 2444 m_autofilled = b; 2445 setNeedsStyleRecalc(); 2446 } 2447 2448 FileList* HTMLInputElement::files() 2449 { 2450 if (inputType() != FILE) 2451 return 0; 2452 return m_fileList.get(); 2453 } 2454 2455 String HTMLInputElement::sanitizeValue(const String& proposedValue) const 2456 { 2457 if (isTextField()) 2458 return InputElement::sanitizeValue(this, proposedValue); 2459 return proposedValue; 2460 } 2461 2462 bool HTMLInputElement::needsActivationCallback() 2463 { 2464 return inputType() == PASSWORD || m_autocomplete == Off; 2465 } 2466 2467 void HTMLInputElement::registerForActivationCallbackIfNeeded() 2468 { 2469 if (needsActivationCallback()) 2470 document()->registerForDocumentActivationCallbacks(this); 2471 } 2472 2473 void HTMLInputElement::unregisterForActivationCallbackIfNeeded() 2474 { 2475 if (!needsActivationCallback()) 2476 document()->unregisterForDocumentActivationCallbacks(this); 2477 } 2478 2479 bool HTMLInputElement::isRequiredFormControl() const 2480 { 2481 if (!required()) 2482 return false; 2483 2484 switch (inputType()) { 2485 case CHECKBOX: 2486 case DATE: 2487 case DATETIME: 2488 case DATETIMELOCAL: 2489 case EMAIL: 2490 case FILE: 2491 case MONTH: 2492 case NUMBER: 2493 case PASSWORD: 2494 case RADIO: 2495 case SEARCH: 2496 case TELEPHONE: 2497 case TEXT: 2498 case TIME: 2499 case URL: 2500 case WEEK: 2501 return true; 2502 case BUTTON: 2503 case COLOR: 2504 case HIDDEN: 2505 case IMAGE: 2506 case ISINDEX: 2507 case RANGE: 2508 case RESET: 2509 case SUBMIT: 2510 return false; 2511 } 2512 2513 ASSERT_NOT_REACHED(); 2514 return false; 2515 } 2516 2517 void HTMLInputElement::cacheSelection(int start, int end) 2518 { 2519 m_data.setCachedSelectionStart(start); 2520 m_data.setCachedSelectionEnd(end); 2521 } 2522 2523 void HTMLInputElement::addSearchResult() 2524 { 2525 ASSERT(isSearchField()); 2526 if (renderer()) 2527 toRenderTextControlSingleLine(renderer())->addSearchResult(); 2528 } 2529 2530 void HTMLInputElement::onSearch() 2531 { 2532 ASSERT(isSearchField()); 2533 if (renderer()) 2534 toRenderTextControlSingleLine(renderer())->stopSearchEventTimer(); 2535 dispatchEvent(Event::create(eventNames().searchEvent, true, false)); 2536 } 2537 2538 void HTMLInputElement::documentDidBecomeActive() 2539 { 2540 ASSERT(needsActivationCallback()); 2541 reset(); 2542 } 2543 2544 void HTMLInputElement::willMoveToNewOwnerDocument() 2545 { 2546 // Always unregister for cache callbacks when leaving a document, even if we would otherwise like to be registered 2547 if (needsActivationCallback()) 2548 document()->unregisterForDocumentActivationCallbacks(this); 2549 2550 document()->checkedRadioButtons().removeButton(this); 2551 2552 HTMLFormControlElementWithState::willMoveToNewOwnerDocument(); 2553 } 2554 2555 void HTMLInputElement::didMoveToNewOwnerDocument() 2556 { 2557 registerForActivationCallbackIfNeeded(); 2558 2559 HTMLFormControlElementWithState::didMoveToNewOwnerDocument(); 2560 } 2561 2562 void HTMLInputElement::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const 2563 { 2564 HTMLFormControlElementWithState::addSubresourceAttributeURLs(urls); 2565 2566 addSubresourceURL(urls, src()); 2567 } 2568 2569 bool HTMLInputElement::willValidate() const 2570 { 2571 // FIXME: This shall check for new WF2 input types too 2572 return HTMLFormControlElementWithState::willValidate() && inputType() != HIDDEN && 2573 inputType() != BUTTON && inputType() != RESET; 2574 } 2575 2576 String HTMLInputElement::formStringFromDouble(double number) 2577 { 2578 // According to HTML5, "the best representation of the number n as a floating 2579 // point number" is a string produced by applying ToString() to n. 2580 DtoaBuffer buffer; 2581 unsigned length; 2582 doubleToStringInJavaScriptFormat(number, buffer, &length); 2583 return String(buffer, length); 2584 } 2585 2586 bool HTMLInputElement::formStringToDouble(const String& src, double* out) 2587 { 2588 // See HTML5 2.4.4.3 `Real numbers.' 2589 2590 if (src.isEmpty()) 2591 return false; 2592 // String::toDouble() accepts leading + \t \n \v \f \r and SPACE, which are invalid in HTML5. 2593 // So, check the first character. 2594 if (src[0] != '-' && (src[0] < '0' || src[0] > '9')) 2595 return false; 2596 2597 bool valid = false; 2598 double value = src.toDouble(&valid); 2599 if (!valid) 2600 return false; 2601 // NaN and Infinity are not valid numbers according to the standard. 2602 if (!isfinite(value)) 2603 return false; 2604 // -0 -> 0 2605 if (!value) 2606 value = 0; 2607 if (out) 2608 *out = value; 2609 return true; 2610 } 2611 2612 bool HTMLInputElement::formStringToDateComponents(InputType type, const String& formString, DateComponents* out) 2613 { 2614 if (formString.isEmpty()) 2615 return false; 2616 DateComponents ignoredResult; 2617 if (!out) 2618 out = &ignoredResult; 2619 const UChar* characters = formString.characters(); 2620 unsigned length = formString.length(); 2621 unsigned end; 2622 2623 switch (type) { 2624 case DATE: 2625 return out->parseDate(characters, length, 0, end) && end == length; 2626 case DATETIME: 2627 return out->parseDateTime(characters, length, 0, end) && end == length; 2628 case DATETIMELOCAL: 2629 return out->parseDateTimeLocal(characters, length, 0, end) && end == length; 2630 case MONTH: 2631 return out->parseMonth(characters, length, 0, end) && end == length; 2632 case WEEK: 2633 return out->parseWeek(characters, length, 0, end) && end == length; 2634 case TIME: 2635 return out->parseTime(characters, length, 0, end) && end == length; 2636 default: 2637 ASSERT_NOT_REACHED(); 2638 return false; 2639 } 2640 } 2641 2642 #if ENABLE(DATALIST) 2643 HTMLElement* HTMLInputElement::list() const 2644 { 2645 return dataList(); 2646 } 2647 2648 HTMLDataListElement* HTMLInputElement::dataList() const 2649 { 2650 if (!m_hasNonEmptyList) 2651 return 0; 2652 2653 switch (inputType()) { 2654 case COLOR: 2655 case DATE: 2656 case DATETIME: 2657 case DATETIMELOCAL: 2658 case EMAIL: 2659 case MONTH: 2660 case NUMBER: 2661 case RANGE: 2662 case SEARCH: 2663 case TELEPHONE: 2664 case TEXT: 2665 case TIME: 2666 case URL: 2667 case WEEK: { 2668 Element* element = document()->getElementById(getAttribute(listAttr)); 2669 if (element && element->hasTagName(datalistTag)) 2670 return static_cast<HTMLDataListElement*>(element); 2671 break; 2672 } 2673 case BUTTON: 2674 case CHECKBOX: 2675 case FILE: 2676 case HIDDEN: 2677 case IMAGE: 2678 case ISINDEX: 2679 case PASSWORD: 2680 case RADIO: 2681 case RESET: 2682 case SUBMIT: 2683 break; 2684 } 2685 return 0; 2686 } 2687 2688 HTMLOptionElement* HTMLInputElement::selectedOption() const 2689 { 2690 String currentValue = value(); 2691 // The empty value never matches to a datalist option because it 2692 // doesn't represent a suggestion according to the standard. 2693 if (currentValue.isEmpty()) 2694 return 0; 2695 2696 HTMLDataListElement* sourceElement = dataList(); 2697 if (!sourceElement) 2698 return 0; 2699 RefPtr<HTMLCollection> options = sourceElement->options(); 2700 for (unsigned i = 0; options && i < options->length(); ++i) { 2701 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(options->item(i)); 2702 if (!option->disabled() && currentValue == option->value()) 2703 return option; 2704 } 2705 return 0; 2706 } 2707 #endif // ENABLE(DATALIST) 2708 2709 } // namespace 2710