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     setForm(0);
     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 (oldDocument && 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         setForm(0);
    127 }
    128 
    129 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
    130 {
    131     if (m_form == newForm)
    132         return;
    133     willChangeForm();
    134     if (m_form)
    135         m_form->removeFormElement(this);
    136     m_form = newForm;
    137     if (m_form)
    138         m_form->registerFormElement(this);
    139     didChangeForm();
    140 }
    141 
    142 void FormAssociatedElement::willChangeForm()
    143 {
    144 }
    145 
    146 void FormAssociatedElement::didChangeForm()
    147 {
    148 }
    149 
    150 void FormAssociatedElement::formWillBeDestroyed()
    151 {
    152     ASSERT(m_form);
    153     if (!m_form)
    154         return;
    155     willChangeForm();
    156     m_form = 0;
    157     didChangeForm();
    158 }
    159 
    160 void FormAssociatedElement::resetFormOwner()
    161 {
    162     HTMLFormElement* originalForm = m_form;
    163     setForm(findAssociatedForm(toHTMLElement(this), m_form));
    164     HTMLElement* element = toHTMLElement(this);
    165     if (m_form && m_form != originalForm && m_form->inDocument())
    166         element->document()->didAssociateFormControl(element);
    167 }
    168 
    169 void FormAssociatedElement::formAttributeChanged()
    170 {
    171     HTMLElement* element = toHTMLElement(this);
    172     if (!element->fastHasAttribute(formAttr)) {
    173         // The form attribute removed. We need to reset form owner here.
    174         HTMLFormElement* originalForm = m_form;
    175         setForm(element->findFormAncestor());
    176         HTMLElement* element = toHTMLElement(this);
    177         if (m_form && m_form != originalForm && m_form->inDocument())
    178             element->document()->didAssociateFormControl(element);
    179         m_formAttributeTargetObserver = nullptr;
    180     } else {
    181         resetFormOwner();
    182         if (element->inDocument())
    183             resetFormAttributeTargetObserver();
    184     }
    185 }
    186 
    187 bool FormAssociatedElement::customError() const
    188 {
    189     const HTMLElement* element = toHTMLElement(this);
    190     return element->willValidate() && !m_customValidationMessage.isEmpty();
    191 }
    192 
    193 bool FormAssociatedElement::hasBadInput() const
    194 {
    195     return false;
    196 }
    197 
    198 bool FormAssociatedElement::patternMismatch() const
    199 {
    200     return false;
    201 }
    202 
    203 bool FormAssociatedElement::rangeOverflow() const
    204 {
    205     return false;
    206 }
    207 
    208 bool FormAssociatedElement::rangeUnderflow() const
    209 {
    210     return false;
    211 }
    212 
    213 bool FormAssociatedElement::stepMismatch() const
    214 {
    215     return false;
    216 }
    217 
    218 bool FormAssociatedElement::tooLong() const
    219 {
    220     return false;
    221 }
    222 
    223 bool FormAssociatedElement::typeMismatch() const
    224 {
    225     return false;
    226 }
    227 
    228 bool FormAssociatedElement::valid() const
    229 {
    230     bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
    231         || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
    232     return !someError;
    233 }
    234 
    235 bool FormAssociatedElement::valueMissing() const
    236 {
    237     return false;
    238 }
    239 
    240 String FormAssociatedElement::customValidationMessage() const
    241 {
    242     return m_customValidationMessage;
    243 }
    244 
    245 String FormAssociatedElement::validationMessage() const
    246 {
    247     return customError() ? m_customValidationMessage : String();
    248 }
    249 
    250 void FormAssociatedElement::setCustomValidity(const String& error)
    251 {
    252     m_customValidationMessage = error;
    253 }
    254 
    255 void FormAssociatedElement::resetFormAttributeTargetObserver()
    256 {
    257     ASSERT(toHTMLElement(this)->inDocument());
    258     m_formAttributeTargetObserver = FormAttributeTargetObserver::create(toHTMLElement(this)->fastGetAttribute(formAttr), this);
    259 }
    260 
    261 void FormAssociatedElement::formAttributeTargetChanged()
    262 {
    263     resetFormOwner();
    264 }
    265 
    266 const AtomicString& FormAssociatedElement::name() const
    267 {
    268     const AtomicString& name = toHTMLElement(this)->getNameAttribute();
    269     return name.isNull() ? emptyAtom : name;
    270 }
    271 
    272 bool FormAssociatedElement::isFormControlElementWithState() const
    273 {
    274     return false;
    275 }
    276 
    277 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
    278 {
    279     if (associatedElement->isFormControlElement())
    280         return static_cast<const HTMLFormControlElement*>(associatedElement);
    281     // Assumes the element is an HTMLObjectElement
    282     const HTMLElement* element = static_cast<const HTMLObjectElement*>(associatedElement);
    283     ASSERT(element->hasTagName(objectTag));
    284     return element;
    285 }
    286 
    287 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
    288 {
    289     return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
    290 }
    291 
    292 PassOwnPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
    293 {
    294     return adoptPtr(new FormAttributeTargetObserver(id, element));
    295 }
    296 
    297 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
    298     : IdTargetObserver(toHTMLElement(element)->treeScope()->idTargetObserverRegistry(), id)
    299     , m_element(element)
    300 {
    301 }
    302 
    303 void FormAttributeTargetObserver::idTargetChanged()
    304 {
    305     m_element->formAttributeTargetChanged();
    306 }
    307 
    308 } // namespace Webcore
    309