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 "core/HTMLNames.h"
     29 #include "core/dom/IdTargetObserver.h"
     30 #include "core/dom/NodeTraversal.h"
     31 #include "core/html/HTMLFormControlElement.h"
     32 #include "core/html/HTMLFormElement.h"
     33 #include "core/html/HTMLLabelElement.h"
     34 #include "core/html/HTMLObjectElement.h"
     35 #include "core/html/ValidityState.h"
     36 
     37 namespace blink {
     38 
     39 using namespace HTMLNames;
     40 
     41 class FormAttributeTargetObserver : public IdTargetObserver {
     42     WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
     43 public:
     44     static PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> create(const AtomicString& id, FormAssociatedElement*);
     45     virtual void trace(Visitor*) OVERRIDE;
     46     virtual void idTargetChanged() OVERRIDE;
     47 
     48 private:
     49     FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement*);
     50 
     51     RawPtrWillBeMember<FormAssociatedElement> m_element;
     52 };
     53 
     54 FormAssociatedElement::FormAssociatedElement()
     55     : m_formWasSetByParser(false)
     56 {
     57 }
     58 
     59 FormAssociatedElement::~FormAssociatedElement()
     60 {
     61     // We can't call setForm here because it contains virtual calls.
     62 }
     63 
     64 void FormAssociatedElement::trace(Visitor* visitor)
     65 {
     66     visitor->trace(m_formAttributeTargetObserver);
     67     visitor->trace(m_form);
     68     visitor->trace(m_validityState);
     69 }
     70 
     71 ValidityState* FormAssociatedElement::validity()
     72 {
     73     if (!m_validityState)
     74         m_validityState = ValidityState::create(this);
     75 
     76     return m_validityState.get();
     77 }
     78 
     79 void FormAssociatedElement::didMoveToNewDocument(Document& oldDocument)
     80 {
     81     HTMLElement* element = toHTMLElement(this);
     82     if (element->fastHasAttribute(formAttr))
     83         setFormAttributeTargetObserver(nullptr);
     84 }
     85 
     86 void FormAssociatedElement::insertedInto(ContainerNode* insertionPoint)
     87 {
     88     if (!m_formWasSetByParser || !m_form || NodeTraversal::highestAncestorOrSelf(*insertionPoint) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
     89         resetFormOwner();
     90 
     91     if (!insertionPoint->inDocument())
     92         return;
     93 
     94     HTMLElement* element = toHTMLElement(this);
     95     if (element->fastHasAttribute(formAttr))
     96         resetFormAttributeTargetObserver();
     97 }
     98 
     99 void FormAssociatedElement::removedFrom(ContainerNode* insertionPoint)
    100 {
    101     HTMLElement* element = toHTMLElement(this);
    102     if (insertionPoint->inDocument() && element->fastHasAttribute(formAttr))
    103         setFormAttributeTargetObserver(nullptr);
    104     // If the form and element are both in the same tree, preserve the connection to the form.
    105     // Otherwise, null out our form and remove ourselves from the form's list of elements.
    106     if (m_form && NodeTraversal::highestAncestorOrSelf(*element) != NodeTraversal::highestAncestorOrSelf(*m_form.get()))
    107         resetFormOwner();
    108 }
    109 
    110 HTMLFormElement* FormAssociatedElement::findAssociatedForm(const HTMLElement* element)
    111 {
    112     const AtomicString& formId(element->fastGetAttribute(formAttr));
    113     // 3. If the element is reassociateable, has a form content attribute, and
    114     // is itself in a Document, then run these substeps:
    115     if (!formId.isNull() && element->inDocument()) {
    116         // 3.1. If the first element in the Document to have an ID that is
    117         // case-sensitively equal to the element's form content attribute's
    118         // value is a form element, then associate the form-associated element
    119         // with that form element.
    120         // 3.2. Abort the "reset the form owner" steps.
    121         Element* newFormCandidate = element->treeScope().getElementById(formId);
    122         return isHTMLFormElement(newFormCandidate) ? toHTMLFormElement(newFormCandidate) : 0;
    123     }
    124     // 4. Otherwise, if the form-associated element in question has an ancestor
    125     // form element, then associate the form-associated element with the nearest
    126     // such ancestor form element.
    127     return element->findFormAncestor();
    128 }
    129 
    130 void FormAssociatedElement::formRemovedFromTree(const Node& formRoot)
    131 {
    132     ASSERT(m_form);
    133     if (NodeTraversal::highestAncestorOrSelf(toHTMLElement(*this)) == formRoot)
    134         return;
    135     resetFormOwner();
    136 }
    137 
    138 void FormAssociatedElement::associateByParser(HTMLFormElement* form)
    139 {
    140     if (form && form->inDocument()) {
    141         m_formWasSetByParser = true;
    142         setForm(form);
    143         form->didAssociateByParser();
    144     }
    145 }
    146 
    147 void FormAssociatedElement::setForm(HTMLFormElement* newForm)
    148 {
    149     if (m_form.get() == newForm)
    150         return;
    151     willChangeForm();
    152     if (m_form)
    153         m_form->disassociate(*this);
    154     if (newForm) {
    155 #if ENABLE(OILPAN)
    156         m_form = newForm;
    157 #else
    158         m_form = newForm->createWeakPtr();
    159 #endif
    160         m_form->associate(*this);
    161     } else {
    162 #if ENABLE(OILPAN)
    163         m_form = nullptr;
    164 #else
    165         m_form = WeakPtr<HTMLFormElement>();
    166 #endif
    167     }
    168     didChangeForm();
    169 }
    170 
    171 void FormAssociatedElement::willChangeForm()
    172 {
    173 }
    174 
    175 void FormAssociatedElement::didChangeForm()
    176 {
    177 }
    178 
    179 void FormAssociatedElement::resetFormOwner()
    180 {
    181     m_formWasSetByParser = false;
    182     HTMLElement* element = toHTMLElement(this);
    183     const AtomicString& formId(element->fastGetAttribute(formAttr));
    184     HTMLFormElement* nearestForm = element->findFormAncestor();
    185     // 1. If the element's form owner is not null, and either the element is not
    186     // reassociateable or its form content attribute is not present, and the
    187     // element's form owner is its nearest form element ancestor after the
    188     // change to the ancestor chain, then do nothing, and abort these steps.
    189     if (m_form && formId.isNull() && m_form.get() == nearestForm)
    190         return;
    191 
    192     HTMLFormElement* originalForm = m_form.get();
    193     setForm(findAssociatedForm(element));
    194     // FIXME: Move didAssociateFormControl call to didChangeForm or
    195     // HTMLFormElement::associate.
    196     if (m_form && m_form.get() != originalForm && m_form->inDocument())
    197         element->document().didAssociateFormControl(element);
    198 }
    199 
    200 void FormAssociatedElement::formAttributeChanged()
    201 {
    202     resetFormOwner();
    203     resetFormAttributeTargetObserver();
    204 }
    205 
    206 bool FormAssociatedElement::customError() const
    207 {
    208     const HTMLElement* element = toHTMLElement(this);
    209     return element->willValidate() && !m_customValidationMessage.isEmpty();
    210 }
    211 
    212 bool FormAssociatedElement::hasBadInput() const
    213 {
    214     return false;
    215 }
    216 
    217 bool FormAssociatedElement::patternMismatch() const
    218 {
    219     return false;
    220 }
    221 
    222 bool FormAssociatedElement::rangeOverflow() const
    223 {
    224     return false;
    225 }
    226 
    227 bool FormAssociatedElement::rangeUnderflow() const
    228 {
    229     return false;
    230 }
    231 
    232 bool FormAssociatedElement::stepMismatch() const
    233 {
    234     return false;
    235 }
    236 
    237 bool FormAssociatedElement::tooLong() const
    238 {
    239     return false;
    240 }
    241 
    242 bool FormAssociatedElement::typeMismatch() const
    243 {
    244     return false;
    245 }
    246 
    247 bool FormAssociatedElement::valid() const
    248 {
    249     bool someError = typeMismatch() || stepMismatch() || rangeUnderflow() || rangeOverflow()
    250         || tooLong() || patternMismatch() || valueMissing() || hasBadInput() || customError();
    251     return !someError;
    252 }
    253 
    254 bool FormAssociatedElement::valueMissing() const
    255 {
    256     return false;
    257 }
    258 
    259 String FormAssociatedElement::customValidationMessage() const
    260 {
    261     return m_customValidationMessage;
    262 }
    263 
    264 String FormAssociatedElement::validationMessage() const
    265 {
    266     return customError() ? m_customValidationMessage : String();
    267 }
    268 
    269 void FormAssociatedElement::setCustomValidity(const String& error)
    270 {
    271     m_customValidationMessage = error;
    272 }
    273 
    274 void FormAssociatedElement::setFormAttributeTargetObserver(PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> newObserver)
    275 {
    276     if (m_formAttributeTargetObserver)
    277         m_formAttributeTargetObserver->unregister();
    278     m_formAttributeTargetObserver = newObserver;
    279 }
    280 
    281 void FormAssociatedElement::resetFormAttributeTargetObserver()
    282 {
    283     HTMLElement* element = toHTMLElement(this);
    284     const AtomicString& formId(element->fastGetAttribute(formAttr));
    285     if (!formId.isNull() && element->inDocument())
    286         setFormAttributeTargetObserver(FormAttributeTargetObserver::create(formId, this));
    287     else
    288         setFormAttributeTargetObserver(nullptr);
    289 }
    290 
    291 void FormAssociatedElement::formAttributeTargetChanged()
    292 {
    293     resetFormOwner();
    294 }
    295 
    296 const AtomicString& FormAssociatedElement::name() const
    297 {
    298     const AtomicString& name = toHTMLElement(this)->getNameAttribute();
    299     return name.isNull() ? emptyAtom : name;
    300 }
    301 
    302 bool FormAssociatedElement::isFormControlElementWithState() const
    303 {
    304     return false;
    305 }
    306 
    307 const HTMLElement& toHTMLElement(const FormAssociatedElement& associatedElement)
    308 {
    309     if (associatedElement.isFormControlElement())
    310         return toHTMLFormControlElement(associatedElement);
    311     else if (associatedElement.isLabelElement())
    312         return toHTMLLabelElement(associatedElement);
    313     else
    314         return toHTMLObjectElement(associatedElement);
    315 }
    316 
    317 const HTMLElement* toHTMLElement(const FormAssociatedElement* associatedElement)
    318 {
    319     ASSERT(associatedElement);
    320     return &toHTMLElement(*associatedElement);
    321 }
    322 
    323 HTMLElement* toHTMLElement(FormAssociatedElement* associatedElement)
    324 {
    325     return const_cast<HTMLElement*>(toHTMLElement(static_cast<const FormAssociatedElement*>(associatedElement)));
    326 }
    327 
    328 HTMLElement& toHTMLElement(FormAssociatedElement& associatedElement)
    329 {
    330     return const_cast<HTMLElement&>(toHTMLElement(static_cast<const FormAssociatedElement&>(associatedElement)));
    331 }
    332 
    333 PassOwnPtrWillBeRawPtr<FormAttributeTargetObserver> FormAttributeTargetObserver::create(const AtomicString& id, FormAssociatedElement* element)
    334 {
    335     return adoptPtrWillBeNoop(new FormAttributeTargetObserver(id, element));
    336 }
    337 
    338 FormAttributeTargetObserver::FormAttributeTargetObserver(const AtomicString& id, FormAssociatedElement* element)
    339     : IdTargetObserver(toHTMLElement(element)->treeScope().idTargetObserverRegistry(), id)
    340     , m_element(element)
    341 {
    342 }
    343 
    344 void FormAttributeTargetObserver::trace(Visitor* visitor)
    345 {
    346     visitor->trace(m_element);
    347     IdTargetObserver::trace(visitor);
    348 }
    349 
    350 void FormAttributeTargetObserver::idTargetChanged()
    351 {
    352     m_element->formAttributeTargetChanged();
    353 }
    354 
    355 } // namespace blink
    356