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