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 Apple Inc. All rights reserved. 6 * (C) 2006 Alexey Proskuryakov (ap (at) nypop.com) 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 * 23 */ 24 25 #include "config.h" 26 #include "HTMLFormControlElement.h" 27 28 #include "Chrome.h" 29 #include "ChromeClient.h" 30 #include "Document.h" 31 #include "Event.h" 32 #include "EventHandler.h" 33 #include "EventNames.h" 34 #include "Frame.h" 35 #include "HTMLFormElement.h" 36 #include "HTMLInputElement.h" 37 #include "HTMLNames.h" 38 #include "HTMLParser.h" 39 #include "HTMLTokenizer.h" 40 #include "MappedAttribute.h" 41 #include "Page.h" 42 #include "RenderBox.h" 43 #include "RenderTextControl.h" 44 #include "RenderTheme.h" 45 #include "ScriptEventListener.h" 46 #include "ValidityState.h" 47 48 namespace WebCore { 49 50 using namespace HTMLNames; 51 52 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) 53 : HTMLElement(tagName, doc) 54 , m_form(f) 55 , m_hasName(false) 56 , m_disabled(false) 57 , m_readOnly(false) 58 , m_required(false) 59 , m_valueMatchesRenderer(false) 60 { 61 if (!m_form) 62 m_form = findFormAncestor(); 63 if (m_form) 64 m_form->registerFormElement(this); 65 } 66 67 HTMLFormControlElement::~HTMLFormControlElement() 68 { 69 if (m_form) 70 m_form->removeFormElement(this); 71 } 72 73 bool HTMLFormControlElement::formNoValidate() const 74 { 75 return !getAttribute(formnovalidateAttr).isNull(); 76 } 77 78 void HTMLFormControlElement::setFormNoValidate(bool formnovalidate) 79 { 80 setAttribute(formnovalidateAttr, formnovalidate ? "" : 0); 81 } 82 83 ValidityState* HTMLFormControlElement::validity() 84 { 85 if (!m_validityState) 86 m_validityState = ValidityState::create(this); 87 88 return m_validityState.get(); 89 } 90 91 void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) 92 { 93 bool oldWillValidate = willValidate(); 94 if (attr->name() == nameAttr) 95 m_hasName = !attr->isEmpty(); 96 else if (attr->name() == disabledAttr) { 97 bool oldDisabled = m_disabled; 98 m_disabled = !attr->isNull(); 99 if (oldDisabled != m_disabled) { 100 setNeedsStyleRecalc(); 101 if (renderer() && renderer()->style()->hasAppearance()) 102 renderer()->theme()->stateChanged(renderer(), EnabledState); 103 } 104 } else if (attr->name() == readonlyAttr) { 105 bool oldReadOnly = m_readOnly; 106 m_readOnly = !attr->isNull(); 107 if (oldReadOnly != m_readOnly) { 108 setNeedsStyleRecalc(); 109 if (renderer() && renderer()->style()->hasAppearance()) 110 renderer()->theme()->stateChanged(renderer(), ReadOnlyState); 111 } 112 } else if (attr->name() == requiredAttr) { 113 bool oldRequired = m_required; 114 m_required = !attr->isNull(); 115 if (oldRequired != m_required) 116 setNeedsStyleRecalc(); 117 } else 118 HTMLElement::parseMappedAttribute(attr); 119 if (oldWillValidate != willValidate()) 120 setNeedsWillValidateCheck(); 121 } 122 123 void HTMLFormControlElement::attach() 124 { 125 ASSERT(!attached()); 126 127 HTMLElement::attach(); 128 129 // The call to updateFromElement() needs to go after the call through 130 // to the base class's attach() because that can sometimes do a close 131 // on the renderer. 132 if (renderer()) 133 renderer()->updateFromElement(); 134 135 // Focus the element if it should honour its autofocus attribute. 136 // We have to determine if the element is a TextArea/Input/Button/Select, 137 // if input type hidden ignore autofocus. So if disabled or readonly. 138 bool isInputTypeHidden = false; 139 if (hasTagName(inputTag)) 140 isInputTypeHidden = static_cast<HTMLInputElement*>(this)->isInputTypeHidden(); 141 142 if (autofocus() && renderer() && !document()->ignoreAutofocus() && !isReadOnlyFormControl() && 143 ((hasTagName(inputTag) && !isInputTypeHidden) || hasTagName(selectTag) || 144 hasTagName(buttonTag) || hasTagName(textareaTag))) 145 focus(); 146 } 147 148 void HTMLFormControlElement::insertedIntoTree(bool deep) 149 { 150 if (!m_form) { 151 // This handles the case of a new form element being created by 152 // JavaScript and inserted inside a form. In the case of the parser 153 // setting a form, we will already have a non-null value for m_form, 154 // and so we don't need to do anything. 155 m_form = findFormAncestor(); 156 if (m_form) { 157 m_form->registerFormElement(this); 158 setNeedsWillValidateCheck(); 159 } else 160 document()->checkedRadioButtons().addButton(this); 161 } 162 163 HTMLElement::insertedIntoTree(deep); 164 } 165 166 static inline Node* findRoot(Node* n) 167 { 168 Node* root = n; 169 for (; n; n = n->parentNode()) 170 root = n; 171 return root; 172 } 173 174 void HTMLFormControlElement::removedFromTree(bool deep) 175 { 176 // If the form and element are both in the same tree, preserve the connection to the form. 177 // Otherwise, null out our form and remove ourselves from the form's list of elements. 178 HTMLParser* parser = 0; 179 if (Tokenizer* tokenizer = document()->tokenizer()) 180 if (tokenizer->isHTMLTokenizer()) 181 parser = static_cast<HTMLTokenizer*>(tokenizer)->htmlParser(); 182 183 if (m_form && !(parser && parser->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) { 184 m_form->removeFormElement(this); 185 m_form = 0; 186 setNeedsWillValidateCheck(); 187 } 188 189 HTMLElement::removedFromTree(deep); 190 } 191 192 void HTMLFormControlElement::formDestroyed() 193 { 194 if (m_form) 195 setNeedsWillValidateCheck(); 196 m_form = 0; 197 } 198 199 const AtomicString& HTMLFormControlElement::formControlName() const 200 { 201 const AtomicString& n = getAttribute(nameAttr); 202 return n.isNull() ? emptyAtom : n; 203 } 204 205 void HTMLFormControlElement::setName(const AtomicString &value) 206 { 207 setAttribute(nameAttr, value); 208 } 209 210 void HTMLFormControlElement::dispatchFormControlChangeEvent() 211 { 212 dispatchEvent(Event::create(eventNames().changeEvent, true, false)); 213 } 214 215 void HTMLFormControlElement::setDisabled(bool b) 216 { 217 setAttribute(disabledAttr, b ? "" : 0); 218 } 219 220 void HTMLFormControlElement::setReadOnly(bool b) 221 { 222 setAttribute(readonlyAttr, b ? "" : 0); 223 } 224 225 bool HTMLFormControlElement::autofocus() const 226 { 227 return hasAttribute(autofocusAttr); 228 } 229 230 void HTMLFormControlElement::setAutofocus(bool b) 231 { 232 setAttribute(autofocusAttr, b ? "autofocus" : 0); 233 } 234 235 bool HTMLFormControlElement::required() const 236 { 237 return m_required; 238 } 239 240 void HTMLFormControlElement::setRequired(bool b) 241 { 242 setAttribute(requiredAttr, b ? "required" : 0); 243 } 244 245 static void updateFromElementCallback(Node* node) 246 { 247 ASSERT_ARG(node, node->isElementNode()); 248 ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement()); 249 ASSERT(node->renderer()); 250 if (RenderObject* renderer = node->renderer()) 251 renderer->updateFromElement(); 252 } 253 254 void HTMLFormControlElement::recalcStyle(StyleChange change) 255 { 256 HTMLElement::recalcStyle(change); 257 258 // updateFromElement() can cause the selection to change, and in turn 259 // trigger synchronous layout, so it must not be called during style recalc. 260 if (renderer()) 261 queuePostAttachCallback(updateFromElementCallback, this); 262 } 263 264 bool HTMLFormControlElement::supportsFocus() const 265 { 266 return !disabled(); 267 } 268 269 bool HTMLFormControlElement::isFocusable() const 270 { 271 if (!renderer() || 272 !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty()) 273 return false; 274 // HTMLElement::isFocusable handles visibility and calls suportsFocus which 275 // will cover the disabled case. 276 return HTMLElement::isFocusable(); 277 } 278 279 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const 280 { 281 if (isFocusable()) 282 if (document()->frame()) 283 return document()->frame()->eventHandler()->tabsToAllControls(event); 284 return false; 285 } 286 287 bool HTMLFormControlElement::isMouseFocusable() const 288 { 289 #if PLATFORM(GTK) 290 return HTMLElement::isMouseFocusable(); 291 #else 292 return false; 293 #endif 294 } 295 296 short HTMLFormControlElement::tabIndex() const 297 { 298 // Skip the supportsFocus check in HTMLElement. 299 return Element::tabIndex(); 300 } 301 302 bool HTMLFormControlElement::willValidate() const 303 { 304 // FIXME: Implementation shall be completed with these checks: 305 // The control does not have a repetition template as an ancestor. 306 // The control does not have a datalist element as an ancestor. 307 // The control is not an output element. 308 return m_form && m_hasName && !m_disabled && !m_readOnly; 309 } 310 311 String HTMLFormControlElement::validationMessage() 312 { 313 return validity()->validationMessage(); 314 } 315 316 void HTMLFormControlElement::setNeedsWillValidateCheck() 317 { 318 setNeedsStyleRecalc(); 319 // FIXME: Show/hide a validation message. 320 } 321 322 bool HTMLFormControlElement::checkValidity() 323 { 324 if (willValidate() && !isValidFormControlElement()) { 325 dispatchEvent(Event::create(eventNames().invalidEvent, false, true)); 326 return false; 327 } 328 329 return true; 330 } 331 332 void HTMLFormControlElement::setNeedsValidityCheck() 333 { 334 if (willValidate()) { 335 // Update style for pseudo classes such as :valid :invalid. 336 setNeedsStyleRecalc(); 337 } 338 // FIXME: show/hide a validation message. 339 } 340 341 void HTMLFormControlElement::setCustomValidity(const String& error) 342 { 343 validity()->setCustomErrorMessage(error); 344 } 345 346 void HTMLFormControlElement::dispatchFocusEvent() 347 { 348 if (document()->frame() && document()->frame()->page()) 349 document()->frame()->page()->chrome()->client()->formDidFocus(this); 350 351 HTMLElement::dispatchFocusEvent(); 352 } 353 354 void HTMLFormControlElement::dispatchBlurEvent() 355 { 356 if (document()->frame() && document()->frame()->page()) 357 document()->frame()->page()->chrome()->client()->formDidBlur(this); 358 359 HTMLElement::dispatchBlurEvent(); 360 } 361 362 HTMLFormElement* HTMLFormControlElement::virtualForm() const 363 { 364 return m_form; 365 } 366 367 bool HTMLFormControlElement::isDefaultButtonForForm() const 368 { 369 return isSuccessfulSubmitButton() && m_form && m_form->defaultButton() == this; 370 } 371 372 bool HTMLFormControlElement::isValidFormControlElement() 373 { 374 return validity()->valid(); 375 } 376 377 void HTMLFormControlElement::removeFromForm() 378 { 379 if (!m_form) 380 return; 381 m_form->removeFormElement(this); 382 m_form = 0; 383 } 384 385 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) 386 : HTMLFormControlElement(tagName, doc, f) 387 { 388 document()->registerFormElementWithState(this); 389 } 390 391 HTMLFormControlElementWithState::~HTMLFormControlElementWithState() 392 { 393 document()->unregisterFormElementWithState(this); 394 } 395 396 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument() 397 { 398 document()->unregisterFormElementWithState(this); 399 HTMLFormControlElement::willMoveToNewOwnerDocument(); 400 } 401 402 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument() 403 { 404 document()->registerFormElementWithState(this); 405 HTMLFormControlElement::didMoveToNewOwnerDocument(); 406 } 407 408 void HTMLFormControlElementWithState::finishParsingChildren() 409 { 410 HTMLFormControlElement::finishParsingChildren(); 411 Document* doc = document(); 412 if (doc->hasStateForNewFormElements()) { 413 String state; 414 if (doc->takeStateForFormElement(name().impl(), type().impl(), state)) 415 restoreFormControlState(state); 416 } 417 } 418 419 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form) 420 : HTMLFormControlElementWithState(tagName, doc, form) 421 { 422 } 423 424 HTMLTextFormControlElement::~HTMLTextFormControlElement() 425 { 426 } 427 428 void HTMLTextFormControlElement::dispatchFocusEvent() 429 { 430 if (supportsPlaceholder()) 431 updatePlaceholderVisibility(false); 432 handleFocusEvent(); 433 HTMLFormControlElementWithState::dispatchFocusEvent(); 434 } 435 436 void HTMLTextFormControlElement::dispatchBlurEvent() 437 { 438 if (supportsPlaceholder()) 439 updatePlaceholderVisibility(false); 440 handleBlurEvent(); 441 HTMLFormControlElementWithState::dispatchBlurEvent(); 442 } 443 444 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const 445 { 446 return supportsPlaceholder() 447 && isEmptyValue() 448 && document()->focusedNode() != this 449 && !getAttribute(placeholderAttr).isEmpty(); 450 } 451 452 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged) 453 { 454 if (supportsPlaceholder() && renderer()) 455 toRenderTextControl(renderer())->updatePlaceholderVisibility(placeholderShouldBeVisible(), placeholderValueChanged); 456 } 457 458 RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout() 459 { 460 if (!isTextFormControl()) 461 return 0; 462 document()->updateLayoutIgnorePendingStylesheets(); 463 return toRenderTextControl(renderer()); 464 } 465 466 void HTMLTextFormControlElement::setSelectionStart(int start) 467 { 468 if (RenderTextControl* renderer = textRendererAfterUpdateLayout()) 469 renderer->setSelectionStart(start); 470 } 471 472 void HTMLTextFormControlElement::setSelectionEnd(int end) 473 { 474 if (RenderTextControl* renderer = textRendererAfterUpdateLayout()) 475 renderer->setSelectionEnd(end); 476 } 477 478 void HTMLTextFormControlElement::select() 479 { 480 if (RenderTextControl* renderer = textRendererAfterUpdateLayout()) 481 renderer->select(); 482 } 483 484 void HTMLTextFormControlElement::setSelectionRange(int start, int end) 485 { 486 if (RenderTextControl* renderer = textRendererAfterUpdateLayout()) 487 renderer->setSelectionRange(start, end); 488 } 489 490 int HTMLTextFormControlElement::selectionStart() 491 { 492 if (!isTextFormControl()) 493 return 0; 494 if (document()->focusedNode() != this && cachedSelectionStart() >= 0) 495 return cachedSelectionStart(); 496 if (!renderer()) 497 return 0; 498 return toRenderTextControl(renderer())->selectionStart(); 499 } 500 501 int HTMLTextFormControlElement::selectionEnd() 502 { 503 if (!isTextFormControl()) 504 return 0; 505 if (document()->focusedNode() != this && cachedSelectionEnd() >= 0) 506 return cachedSelectionEnd(); 507 if (!renderer()) 508 return 0; 509 return toRenderTextControl(renderer())->selectionEnd(); 510 } 511 512 VisibleSelection HTMLTextFormControlElement::selection() const 513 { 514 if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0) 515 return VisibleSelection(); 516 return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd()); 517 } 518 519 void HTMLTextFormControlElement::parseMappedAttribute(MappedAttribute* attr) 520 { 521 if (attr->name() == placeholderAttr) 522 updatePlaceholderVisibility(true); 523 else if (attr->name() == onfocusAttr) 524 setAttributeEventListener(eventNames().focusEvent, createAttributeEventListener(this, attr)); 525 else if (attr->name() == onblurAttr) 526 setAttributeEventListener(eventNames().blurEvent, createAttributeEventListener(this, attr)); 527 else if (attr->name() == onselectAttr) 528 setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr)); 529 else if (attr->name() == onchangeAttr) 530 setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr)); 531 else 532 HTMLFormControlElementWithState::parseMappedAttribute(attr); 533 } 534 535 } // namespace Webcore 536