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 "core/html/FormAssociatedElement.h"
     27 
     28 #include "HTMLNames.h"
     29 #include "core/dom/IdTargetObserver.h"
     30 #include "core/html/HTMLFormControlElement.h"
     31 #include "core/html/HTMLFormElement.h"
     32 #include "core/html/HTMLObjectElement.h"
     33 #include "core/html/ValidityState.h"
     34 
     35 namespace WebCore {
     36 
     37 using namespace HTMLNames;
     38 
     39 class FormAttributeTargetObserver : IdTargetObserver {
     40     WTF_MAKE_FAST_ALLOCATED;
     41 public:
     42     static PassOwnPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
     43     virtual void idTargetChanged() OVERRIDE;
     44 
     45 private:
     46     FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);
     47 
     48     FormAssociatedElement* m_element;
     49 };
     50 
     51 FormAssociatedElement::FormAssociatedElement()
     52     : m_form(0)
     53 {
     54 }
     55 
     56 FormAssociatedElement::~FormAssociatedElement()
     57 {
     58     // We can't call setForm here because it contains virtual calls.
     59 }
     60 
     61 ValidityState* FormAssociatedElement::validity()
     62 {
     63     if (!m_validityState)
     64         m_validityState = ValidityState::create(this);
     65 
     66     return m_validityState.get();
     67 }
     68 
     69 void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
     70 {
     71     HTMLElement* element = toHTMLElement(this);
     72     if (element->fastHasAttribute(formAttr))
     73         m_formAttributeTargetObserver = nullptr;
     74 }
     75 
     76 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
     77 {
     78     if (m_form && insertionPoint->highestAncestor() != m_form->highestAncestor())
     79         setForm(0);
     80 
     81     resetFormOwner();
     82     if (!insertionPoint->inDocument())
     83         return;
     84 
     85     HTMLElement* element = toHTMLElement(this);
     86     if (element->fastHasAttribute(formAttr))
     87         resetFormAttributeTargetObserver();
     88 }
     89 
     90 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
     91 {
     92     HTMLElement* element = toHTMLElement(this);
     93     if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
     94         m_formAttributeTargetObserver = nullptr;
     95     // If the form and element are both in the same tree, preserve the connection to the form.
     96     // Otherwise, null out our form and remove ourselves from the form's list of elements.
     97     if (m_form && element->highestAncestor() != m_form->highestAncestor())
     98         setForm(0);
     99 }
    100 
    101 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element, HTMLFormElement* currentAssociatedForm)
    102 {
    103     const AtomicString& formId(element->fastGetAttribute(formAttr));
    104     if (!formId.isNull() && element->inDocument()) {
    105         // The HTML5 spec says that the element should be associated with
    106         // the first element in the document to have an ID that equal to
    107         // the value of form attribute, so we put the result of
    108         // treeScope()->getElementById() over the given element.
    109         HTMLFormElement* newForm = 0;
    110         Element* newFormCandidate = element->treeScope().getElementById(formId);
    111         if (newFormCandidate && newFormCandidate->hasTagName(formTag))
    112             newForm = toHTMLFormElement(newFormCandidate);
    113         return newForm;
    114     }
    115 
    116     if (!currentAssociatedForm)
    117         return element->findFormAncestor();
    118 
    119     return currentAssociatedForm;
    120 }
    121 
    122 void FormAssociatedElement::formRemovedFromTree(const Node* formRoot)
    123 {
    124     ASSERT(m_form);
    125     if (toHTMLElement(this)->highestAncestor() == formRoot)
    126         return;
    127     setForm(0);
    128 }
    129 
    130 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
    131 {
    132     if (m_form == newForm)
    133         return;
    134     willChangeForm();
    135     if (m_form)
    136         m_form->removeFormElement(this);
    137     m_form = newForm;
    138     if (m_form)
    139         m_form->registerFormElement(*this);
    140     didChangeForm();
    141 }
    142 
    143 void FormAssociatedElement::willChangeForm()
    144 {
    145 }
    146 
    147 void FormAssociatedElement::didChangeForm()
    148 {
    149 }
    150 
    151 void FormAssociatedElement::formWillBeDestroyed()
    152 {
    153     ASSERT(m_form);
    154     if (!m_form)
    155         return;
    156     willChangeForm();
    157     m_form = 0;
    158     didChangeForm();
    159 }
    160 
    161 void FormAssociatedElement::resetFormOwner()
    162 {
    163     HTMLFormElement* originalForm = m_form;
    164     setForm(findAssociatedForm(toHTMLElement(this), m_form));
    165     HTMLElement* element = toHTMLElement(this);
    166     if (m_form && m_form != originalForm && m_form->inDocument())
    167         element->document().didAssociateFormControl(element);
    168 }
    169 
    170 void FormAssociatedElement::formAttributeChanged()
    171 {
    172     HTMLElement* element = toHTMLElement(this);
    173     if (!element->fastHasAttribute(formAttr)) {
    174         // The form attribute removed. We need to reset form owner here.
    175         HTMLFormElement* originalForm = m_form;
    176         setForm(element->findFormAncestor());
    177         HTMLElement* element = toHTMLElement(this);
    178         if (m_form && m_form != originalForm && m_form->inDocument())
    179             element->document().didAssociateFormControl(element);
    180         m_formAttributeTargetObserver = nullptr;
    181     } else {
    182         resetFormOwner();
    183         if (element->inDocument())
    184             resetFormAttributeTargetObserver();
    185     }
    186 }
    187 
    188 bool FormAssociatedElement::customError() const
    189 {
    190     const HTMLElement* element = toHTMLElement(this);
    191     return element->willValidate() && !m_customValidationMessage.isEmpty();
    192 }
    193 
    194 bool FormAssociatedElement::hasBadInput() const
    195 {
    196     return false;
    197 }
    198 
    199 bool FormAssociatedElement::patternMismatch() const
    200 {
    201     return false;
    202 }
    203 
    204 bool FormAssociatedElement::rangeOverflow() const
    205 {
    206     return false;
    207 }
    208 
    209 bool FormAssociatedElement::rangeUnderflow() const
    210 {
    211     return false;
    212 }
    213 
    214 bool FormAssociatedElement::stepMismatch() const
    215 {
    216     return false;
    217 }
    218 
    219 bool FormAssociatedElement::tooLong() const
    220 {
    221     return false;
    222 }
    223 
    224 bool FormAssociatedElement::typeMismatch() const
    225 {
    226     return false;
    227 }
    228 
    229 bool FormAssociatedElement::valid() const
    230 {
    231     bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
    232         || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
    233     return !someError;
    234 }
    235 
    236 bool FormAssociatedElement::valueMissing() const
    237 {
    238     return false;
    239 }
    240 
    241 String FormAssociatedElement::customValidationMessage() const
    242 {
    243     return m_customValidationMessage;
    244 }
    245 
    246 String FormAssociatedElement::validationMessage() const
    247 {
    248     return customError() ? m_customValidationMessage : String();
    249 }
    250 
    251 void FormAssociatedElement::setCustomValidity(const String& error)
    252 {
    253     m_customValidationMessage = error;
    254 }
    255 
    256 void FormAssociatedElement::resetFormAttributeTargetObserver()
    257 {
    258     ASSERT(toHTMLElement(this)->inDocument());
    259     m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this);
    260 }
    261 
    262 void FormAssociatedElement::formAttributeTargetChanged()
    263 {
    264     resetFormOwner();
    265 }
    266 
    267 const AtomicString& FormAssociatedElement::name() const
    268 {
    269     const AtomicString& name = toHTMLElement(this)->getNameAttribute();
    270     return name.isNull() ? emptyAtom : name;
    271 }
    272 
    273 bool FormAssociatedElement::isFormControlElementWithState() const
    274 {
    275     return false;
    276 }
    277 
    278 const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement)
    279 {
    280     if (associatedElement.isFormControlElement())
    281         return toHTMLFormControlElement(associatedElement);
    282     // Assumes the element is an HTMLObjectElement
    283     return toHTMLObjectElement(associatedElement);
    284 }
    285 
    286 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
    287 {
    288     ASSERT(associatedElement);
    289     return &toHTMLElement(*associatedElement);
    290 }
    291 
    292 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
    293 {
    294     return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
    295 }
    296 
    297 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
    298 {
    299     return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
    300 }
    301 
    302 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
    303 {
    304     return adoptPtr(new FormAttributeTargetObserver(id, element));
    305 }
    306 
    307 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
    308     : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
    309     , m_element(element)
    310 {
    311 }
    312 
    313 void FormAttributeTargetObserver::idTargetChanged()
    314 {
    315     m_element->formAttributeTargetChanged();
    316 }
    317 
    318 } // namespace Webcore
    319