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