Home | History | Annotate | Download | only in html
      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