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 "config.h"
26 #include "HTMLFormControlElement.h"
27
28 #include "Attribute.h"
29 #include "Chrome.h"
30 #include "ChromeClient.h"
31 #include "Document.h"
32 #include "DocumentParser.h"
33 #include "ElementRareData.h"
34 #include "Event.h"
35 #include "EventHandler.h"
36 #include "EventNames.h"
37 #include "Frame.h"
38 #include "HTMLFormElement.h"
39 #include "HTMLInputElement.h"
40 #include "HTMLNames.h"
41 #include "LabelsNodeList.h"
42 #include "Page.h"
43 #include "RenderBox.h"
44 #include "RenderTextControl.h"
45 #include "RenderTheme.h"
46 #include "ScriptEventListener.h"
47 #include "ValidationMessage.h"
48 #include "ValidityState.h"
49 #include <limits>
50 #include <wtf/Vector.h>
51 #include <wtf/unicode/CharacterNames.h>
52
53 namespace WebCore {
54
55 using namespace HTMLNames;
56 using namespace std;
57
HTMLFormControlElement(const QualifiedName & tagName,Document * document,HTMLFormElement * form)58 HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* document, HTMLFormElement* form)
59 : HTMLElement(tagName, document)
60 , FormAssociatedElement(form)
61 , m_disabled(false)
62 , m_readOnly(false)
63 , m_required(false)
64 , m_valueMatchesRenderer(false)
65 , m_willValidateInitialized(false)
66 , m_willValidate(true)
67 , m_isValid(true)
68 , m_wasChangedSinceLastFormControlChangeEvent(false)
69 {
70 if (!this->form())
71 setForm(findFormAncestor());
72 if (this->form())
73 this->form()->registerFormElement(this);
74 }
75
~HTMLFormControlElement()76 HTMLFormControlElement::~HTMLFormControlElement()
77 {
78 if (form())
79 form()->removeFormElement(this);
80 }
81
detach()82 void HTMLFormControlElement::detach()
83 {
84 m_validationMessage = 0;
85 HTMLElement::detach();
86 }
87
formNoValidate() const88 bool HTMLFormControlElement::formNoValidate() const
89 {
90 return fastHasAttribute(formnovalidateAttr);
91 }
92
parseMappedAttribute(Attribute * attr)93 void HTMLFormControlElement::parseMappedAttribute(Attribute* attr)
94 {
95 if (attr->name() == disabledAttr) {
96 bool oldDisabled = m_disabled;
97 m_disabled = !attr->isNull();
98 if (oldDisabled != m_disabled) {
99 setNeedsStyleRecalc();
100 if (renderer() && renderer()->style()->hasAppearance())
101 renderer()->theme()->stateChanged(renderer(), EnabledState);
102 }
103 } else if (attr->name() == readonlyAttr) {
104 bool oldReadOnly = m_readOnly;
105 m_readOnly = !attr->isNull();
106 if (oldReadOnly != m_readOnly) {
107 setNeedsStyleRecalc();
108 if (renderer() && renderer()->style()->hasAppearance())
109 renderer()->theme()->stateChanged(renderer(), ReadOnlyState);
110 }
111 } else if (attr->name() == requiredAttr) {
112 bool oldRequired = m_required;
113 m_required = !attr->isNull();
114 if (oldRequired != m_required) {
115 setNeedsValidityCheck();
116 setNeedsStyleRecalc(); // Updates for :required :optional classes.
117 }
118 } else
119 HTMLElement::parseMappedAttribute(attr);
120 setNeedsWillValidateCheck();
121 }
122
shouldAutofocus(HTMLFormControlElement * element)123 static bool shouldAutofocus(HTMLFormControlElement* element)
124 {
125 if (!element->autofocus())
126 return false;
127 if (!element->renderer())
128 return false;
129 if (element->document()->ignoreAutofocus())
130 return false;
131 if (element->isReadOnlyFormControl())
132 return false;
133
134 // FIXME: Should this set of hasTagName checks be replaced by a
135 // virtual member function?
136 if (element->hasTagName(inputTag))
137 return !static_cast<HTMLInputElement*>(element)->isInputTypeHidden();
138 if (element->hasTagName(selectTag))
139 return true;
140 if (element->hasTagName(keygenTag))
141 return true;
142 if (element->hasTagName(buttonTag))
143 return true;
144 if (element->hasTagName(textareaTag))
145 return true;
146
147 return false;
148 }
149
focusPostAttach(Node * element)150 static void focusPostAttach(Node* element)
151 {
152 static_cast<Element*>(element)->focus();
153 element->deref();
154 }
155
attach()156 void HTMLFormControlElement::attach()
157 {
158 ASSERT(!attached());
159
160 suspendPostAttachCallbacks();
161
162 HTMLElement::attach();
163
164 // The call to updateFromElement() needs to go after the call through
165 // to the base class's attach() because that can sometimes do a close
166 // on the renderer.
167 if (renderer())
168 renderer()->updateFromElement();
169
170 if (shouldAutofocus(this)) {
171 ref();
172 queuePostAttachCallback(focusPostAttach, this);
173 }
174
175 resumePostAttachCallbacks();
176 }
177
willMoveToNewOwnerDocument()178 void HTMLFormControlElement::willMoveToNewOwnerDocument()
179 {
180 FormAssociatedElement::willMoveToNewOwnerDocument();
181 HTMLElement::willMoveToNewOwnerDocument();
182 }
183
insertedIntoTree(bool deep)184 void HTMLFormControlElement::insertedIntoTree(bool deep)
185 {
186 FormAssociatedElement::insertedIntoTree();
187 if (!form())
188 document()->checkedRadioButtons().addButton(this);
189
190 HTMLElement::insertedIntoTree(deep);
191 }
192
removedFromTree(bool deep)193 void HTMLFormControlElement::removedFromTree(bool deep)
194 {
195 FormAssociatedElement::removedFromTree();
196 HTMLElement::removedFromTree(deep);
197 }
198
insertedIntoDocument()199 void HTMLFormControlElement::insertedIntoDocument()
200 {
201 HTMLElement::insertedIntoDocument();
202 FormAssociatedElement::insertedIntoDocument();
203 }
204
removedFromDocument()205 void HTMLFormControlElement::removedFromDocument()
206 {
207 HTMLElement::removedFromDocument();
208 FormAssociatedElement::removedFromDocument();
209 }
210
formControlName() const211 const AtomicString& HTMLFormControlElement::formControlName() const
212 {
213 const AtomicString& name = fastGetAttribute(nameAttr);
214 return name.isNull() ? emptyAtom : name;
215 }
216
setName(const AtomicString & value)217 void HTMLFormControlElement::setName(const AtomicString& value)
218 {
219 setAttribute(nameAttr, value);
220 }
221
wasChangedSinceLastFormControlChangeEvent() const222 bool HTMLFormControlElement::wasChangedSinceLastFormControlChangeEvent() const
223 {
224 return m_wasChangedSinceLastFormControlChangeEvent;
225 }
226
setChangedSinceLastFormControlChangeEvent(bool changed)227 void HTMLFormControlElement::setChangedSinceLastFormControlChangeEvent(bool changed)
228 {
229 m_wasChangedSinceLastFormControlChangeEvent = changed;
230 }
231
dispatchFormControlChangeEvent()232 void HTMLFormControlElement::dispatchFormControlChangeEvent()
233 {
234 HTMLElement::dispatchChangeEvent();
235 setChangedSinceLastFormControlChangeEvent(false);
236 }
237
dispatchFormControlInputEvent()238 void HTMLFormControlElement::dispatchFormControlInputEvent()
239 {
240 setChangedSinceLastFormControlChangeEvent(true);
241 HTMLElement::dispatchInputEvent();
242 }
243
setDisabled(bool b)244 void HTMLFormControlElement::setDisabled(bool b)
245 {
246 setAttribute(disabledAttr, b ? "" : 0);
247 }
248
autofocus() const249 bool HTMLFormControlElement::autofocus() const
250 {
251 return hasAttribute(autofocusAttr);
252 }
253
required() const254 bool HTMLFormControlElement::required() const
255 {
256 return m_required;
257 }
258
updateFromElementCallback(Node * node)259 static void updateFromElementCallback(Node* node)
260 {
261 ASSERT_ARG(node, node->isElementNode());
262 ASSERT_ARG(node, static_cast<Element*>(node)->isFormControlElement());
263 ASSERT(node->renderer());
264 if (RenderObject* renderer = node->renderer())
265 renderer->updateFromElement();
266 }
267
recalcStyle(StyleChange change)268 void HTMLFormControlElement::recalcStyle(StyleChange change)
269 {
270 HTMLElement::recalcStyle(change);
271
272 // updateFromElement() can cause the selection to change, and in turn
273 // trigger synchronous layout, so it must not be called during style recalc.
274 if (renderer())
275 queuePostAttachCallback(updateFromElementCallback, this);
276 }
277
supportsFocus() const278 bool HTMLFormControlElement::supportsFocus() const
279 {
280 return !m_disabled;
281 }
282
isFocusable() const283 bool HTMLFormControlElement::isFocusable() const
284 {
285 if (!renderer() ||
286 !renderer()->isBox() || toRenderBox(renderer())->size().isEmpty())
287 return false;
288 // HTMLElement::isFocusable handles visibility and calls suportsFocus which
289 // will cover the disabled case.
290 return HTMLElement::isFocusable();
291 }
292
isKeyboardFocusable(KeyboardEvent * event) const293 bool HTMLFormControlElement::isKeyboardFocusable(KeyboardEvent* event) const
294 {
295 if (isFocusable())
296 if (document()->frame())
297 return document()->frame()->eventHandler()->tabsToAllFormControls(event);
298 return false;
299 }
300
isMouseFocusable() const301 bool HTMLFormControlElement::isMouseFocusable() const
302 {
303 #if PLATFORM(GTK) || PLATFORM(QT)
304 return HTMLElement::isMouseFocusable();
305 #else
306 return false;
307 #endif
308 }
309
tabIndex() const310 short HTMLFormControlElement::tabIndex() const
311 {
312 // Skip the supportsFocus check in HTMLElement.
313 return Element::tabIndex();
314 }
315
recalcWillValidate() const316 bool HTMLFormControlElement::recalcWillValidate() const
317 {
318 // FIXME: Should return false if this element has a datalist element as an
319 // ancestor. See HTML5 4.10.10 'The datalist element.'
320 return !m_disabled && !m_readOnly;
321 }
322
willValidate() const323 bool HTMLFormControlElement::willValidate() const
324 {
325 if (!m_willValidateInitialized) {
326 m_willValidateInitialized = true;
327 m_willValidate = recalcWillValidate();
328 } else {
329 // If the following assertion fails, setNeedsWillValidateCheck() is not
330 // called correctly when something which changes recalcWillValidate() result
331 // is updated.
332 ASSERT(m_willValidate == recalcWillValidate());
333 }
334 return m_willValidate;
335 }
336
setNeedsWillValidateCheck()337 void HTMLFormControlElement::setNeedsWillValidateCheck()
338 {
339 // We need to recalculate willValidte immediately because willValidate
340 // change can causes style change.
341 bool newWillValidate = recalcWillValidate();
342 if (m_willValidateInitialized && m_willValidate == newWillValidate)
343 return;
344 m_willValidateInitialized = true;
345 m_willValidate = newWillValidate;
346 setNeedsStyleRecalc();
347 if (!m_willValidate)
348 hideVisibleValidationMessage();
349 }
350
validationMessage()351 String HTMLFormControlElement::validationMessage()
352 {
353 return validity()->validationMessage();
354 }
355
updateVisibleValidationMessage()356 void HTMLFormControlElement::updateVisibleValidationMessage()
357 {
358 Page* page = document()->page();
359 if (!page)
360 return;
361 String message;
362 if (renderer() && willValidate()) {
363 message = validationMessage().stripWhiteSpace();
364 // HTML5 specification doesn't ask UA to show the title attribute value
365 // with the validationMessage. However, this behavior is same as Opera
366 // and the specification describes such behavior as an example.
367 const AtomicString& title = getAttribute(titleAttr);
368 if (!message.isEmpty() && !title.isEmpty()) {
369 message.append('\n');
370 message.append(title);
371 }
372 }
373 if (message.isEmpty()) {
374 hideVisibleValidationMessage();
375 return;
376 }
377 if (!m_validationMessage) {
378 m_validationMessage = ValidationMessage::create(this);
379 m_validationMessage->setMessage(message);
380 } else {
381 // Call setMessage() even if m_validationMesage->message() == message
382 // because the existing message might be to be hidden.
383 m_validationMessage->setMessage(message);
384 }
385 }
386
hideVisibleValidationMessage()387 void HTMLFormControlElement::hideVisibleValidationMessage()
388 {
389 if (m_validationMessage)
390 m_validationMessage->requestToHideMessage();
391 }
392
visibleValidationMessage() const393 String HTMLFormControlElement::visibleValidationMessage() const
394 {
395 return m_validationMessage ? m_validationMessage->message() : String();
396 }
397
checkValidity(Vector<RefPtr<FormAssociatedElement>> * unhandledInvalidControls)398 bool HTMLFormControlElement::checkValidity(Vector<RefPtr<FormAssociatedElement> >* unhandledInvalidControls)
399 {
400 if (!willValidate() || isValidFormControlElement())
401 return true;
402 // An event handler can deref this object.
403 RefPtr<HTMLFormControlElement> protector(this);
404 RefPtr<Document> originalDocument(document());
405 bool needsDefaultAction = dispatchEvent(Event::create(eventNames().invalidEvent, false, true));
406 if (needsDefaultAction && unhandledInvalidControls && inDocument() && originalDocument == document())
407 unhandledInvalidControls->append(this);
408 return false;
409 }
410
isValidFormControlElement()411 bool HTMLFormControlElement::isValidFormControlElement()
412 {
413 // If the following assertion fails, setNeedsValidityCheck() is not called
414 // correctly when something which changes validity is updated.
415 ASSERT(m_isValid == validity()->valid());
416 return m_isValid;
417 }
418
setNeedsValidityCheck()419 void HTMLFormControlElement::setNeedsValidityCheck()
420 {
421 bool newIsValid = validity()->valid();
422 if (willValidate() && newIsValid != m_isValid) {
423 // Update style for pseudo classes such as :valid :invalid.
424 setNeedsStyleRecalc();
425 }
426 m_isValid = newIsValid;
427
428 // Updates only if this control already has a validtion message.
429 if (!visibleValidationMessage().isEmpty()) {
430 // Calls updateVisibleValidationMessage() even if m_isValid is not
431 // changed because a validation message can be chagned.
432 updateVisibleValidationMessage();
433 }
434 }
435
setCustomValidity(const String & error)436 void HTMLFormControlElement::setCustomValidity(const String& error)
437 {
438 validity()->setCustomErrorMessage(error);
439 }
440
dispatchFocusEvent()441 void HTMLFormControlElement::dispatchFocusEvent()
442 {
443 if (document()->page())
444 document()->page()->chrome()->client()->formDidFocus(this);
445
446 HTMLElement::dispatchFocusEvent();
447 }
448
dispatchBlurEvent()449 void HTMLFormControlElement::dispatchBlurEvent()
450 {
451 if (document()->page())
452 document()->page()->chrome()->client()->formDidBlur(this);
453
454 HTMLElement::dispatchBlurEvent();
455 hideVisibleValidationMessage();
456 }
457
virtualForm() const458 HTMLFormElement* HTMLFormControlElement::virtualForm() const
459 {
460 return FormAssociatedElement::form();
461 }
462
isDefaultButtonForForm() const463 bool HTMLFormControlElement::isDefaultButtonForForm() const
464 {
465 return isSuccessfulSubmitButton() && form() && form()->defaultButton() == this;
466 }
467
attributeChanged(Attribute * attr,bool preserveDecls)468 void HTMLFormControlElement::attributeChanged(Attribute* attr, bool preserveDecls)
469 {
470 if (attr->name() == formAttr) {
471 formAttributeChanged();
472 if (!form())
473 document()->checkedRadioButtons().addButton(this);
474 } else
475 HTMLElement::attributeChanged(attr, preserveDecls);
476 }
477
isLabelable() const478 bool HTMLFormControlElement::isLabelable() const
479 {
480 // FIXME: Add meterTag and outputTag to the list once we support them.
481 return hasTagName(buttonTag) || hasTagName(inputTag) || hasTagName(keygenTag)
482 #if ENABLE(METER_TAG)
483 || hasTagName(meterTag)
484 #endif
485 #if ENABLE(PROGRESS_TAG)
486 || hasTagName(progressTag)
487 #endif
488 || hasTagName(selectTag) || hasTagName(textareaTag);
489 }
490
labels()491 PassRefPtr<NodeList> HTMLFormControlElement::labels()
492 {
493 if (!isLabelable())
494 return 0;
495 if (!document())
496 return 0;
497
498 NodeRareData* data = Node::ensureRareData();
499 if (!data->nodeLists()) {
500 data->setNodeLists(NodeListsNodeData::create());
501 document()->addNodeListCache();
502 }
503
504 return LabelsNodeList::create(this);
505 }
506
HTMLFormControlElementWithState(const QualifiedName & tagName,Document * doc,HTMLFormElement * f)507 HTMLFormControlElementWithState::HTMLFormControlElementWithState(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
508 : HTMLFormControlElement(tagName, doc, f)
509 {
510 document()->registerFormElementWithState(this);
511 }
512
~HTMLFormControlElementWithState()513 HTMLFormControlElementWithState::~HTMLFormControlElementWithState()
514 {
515 document()->unregisterFormElementWithState(this);
516 }
517
willMoveToNewOwnerDocument()518 void HTMLFormControlElementWithState::willMoveToNewOwnerDocument()
519 {
520 document()->unregisterFormElementWithState(this);
521 HTMLFormControlElement::willMoveToNewOwnerDocument();
522 }
523
didMoveToNewOwnerDocument()524 void HTMLFormControlElementWithState::didMoveToNewOwnerDocument()
525 {
526 document()->registerFormElementWithState(this);
527 HTMLFormControlElement::didMoveToNewOwnerDocument();
528 }
529
autoComplete() const530 bool HTMLFormControlElementWithState::autoComplete() const
531 {
532 if (!form())
533 return true;
534 return form()->autoComplete();
535 }
536
shouldSaveAndRestoreFormControlState() const537 bool HTMLFormControlElementWithState::shouldSaveAndRestoreFormControlState() const
538 {
539 // We don't save/restore control state in a form with autocomplete=off.
540 return attached() && autoComplete();
541 }
542
finishParsingChildren()543 void HTMLFormControlElementWithState::finishParsingChildren()
544 {
545 HTMLFormControlElement::finishParsingChildren();
546
547 // We don't save state of a control with shouldSaveAndRestoreFormControlState()=false.
548 // But we need to skip restoring process too because a control in another
549 // form might have the same pair of name and type and saved its state.
550 if (!shouldSaveAndRestoreFormControlState())
551 return;
552
553 Document* doc = document();
554 if (doc->hasStateForNewFormElements()) {
555 String state;
556 if (doc->takeStateForFormElement(name().impl(), type().impl(), state))
557 restoreFormControlState(state);
558 }
559 }
560
defaultEventHandler(Event * event)561 void HTMLFormControlElementWithState::defaultEventHandler(Event* event)
562 {
563 if (event->type() == eventNames().webkitEditableContentChangedEvent && renderer() && renderer()->isTextControl()) {
564 toRenderTextControl(renderer())->subtreeHasChanged();
565 return;
566 }
567
568 HTMLFormControlElement::defaultEventHandler(event);
569 }
570
HTMLTextFormControlElement(const QualifiedName & tagName,Document * doc,HTMLFormElement * form)571 HTMLTextFormControlElement::HTMLTextFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* form)
572 : HTMLFormControlElementWithState(tagName, doc, form)
573 {
574 }
575
~HTMLTextFormControlElement()576 HTMLTextFormControlElement::~HTMLTextFormControlElement()
577 {
578 }
579
insertedIntoDocument()580 void HTMLTextFormControlElement::insertedIntoDocument()
581 {
582 HTMLFormControlElement::insertedIntoDocument();
583 setTextAsOfLastFormControlChangeEvent(value());
584 }
585
dispatchFocusEvent()586 void HTMLTextFormControlElement::dispatchFocusEvent()
587 {
588 if (supportsPlaceholder())
589 updatePlaceholderVisibility(false);
590 handleFocusEvent();
591 HTMLFormControlElementWithState::dispatchFocusEvent();
592 }
593
dispatchBlurEvent()594 void HTMLTextFormControlElement::dispatchBlurEvent()
595 {
596 if (supportsPlaceholder())
597 updatePlaceholderVisibility(false);
598 handleBlurEvent();
599 HTMLFormControlElementWithState::dispatchBlurEvent();
600 }
601
strippedPlaceholder() const602 String HTMLTextFormControlElement::strippedPlaceholder() const
603 {
604 // According to the HTML5 specification, we need to remove CR and LF from
605 // the attribute value.
606 const AtomicString& attributeValue = getAttribute(placeholderAttr);
607 if (!attributeValue.contains(newlineCharacter) && !attributeValue.contains(carriageReturn))
608 return attributeValue;
609
610 Vector<UChar> stripped;
611 unsigned length = attributeValue.length();
612 stripped.reserveCapacity(length);
613 for (unsigned i = 0; i < length; ++i) {
614 UChar character = attributeValue[i];
615 if (character == newlineCharacter || character == carriageReturn)
616 continue;
617 stripped.append(character);
618 }
619 return String::adopt(stripped);
620 }
621
isNotLineBreak(UChar ch)622 static bool isNotLineBreak(UChar ch) { return ch != newlineCharacter && ch != carriageReturn; }
623
isPlaceholderEmpty() const624 bool HTMLTextFormControlElement::isPlaceholderEmpty() const
625 {
626 const AtomicString& attributeValue = getAttribute(placeholderAttr);
627 return attributeValue.string().find(isNotLineBreak) == notFound;
628 }
629
placeholderShouldBeVisible() const630 bool HTMLTextFormControlElement::placeholderShouldBeVisible() const
631 {
632 return supportsPlaceholder()
633 && isEmptyValue()
634 && isEmptySuggestedValue()
635 && !isPlaceholderEmpty()
636 && (document()->focusedNode() != this || (renderer() && renderer()->theme()->shouldShowPlaceholderWhenFocused()));
637 }
638
updatePlaceholderVisibility(bool placeholderValueChanged)639 void HTMLTextFormControlElement::updatePlaceholderVisibility(bool placeholderValueChanged)
640 {
641 if (supportsPlaceholder() && renderer())
642 toRenderTextControl(renderer())->updatePlaceholderVisibility(placeholderShouldBeVisible(), placeholderValueChanged);
643 }
644
textRendererAfterUpdateLayout()645 RenderTextControl* HTMLTextFormControlElement::textRendererAfterUpdateLayout()
646 {
647 if (!isTextFormControl())
648 return 0;
649 document()->updateLayoutIgnorePendingStylesheets();
650 return toRenderTextControl(renderer());
651 }
652
setSelectionStart(int start)653 void HTMLTextFormControlElement::setSelectionStart(int start)
654 {
655 setSelectionRange(start, max(start, selectionEnd()));
656 }
657
setSelectionEnd(int end)658 void HTMLTextFormControlElement::setSelectionEnd(int end)
659 {
660 setSelectionRange(min(end, selectionStart()), end);
661 }
662
select()663 void HTMLTextFormControlElement::select()
664 {
665 setSelectionRange(0, numeric_limits<int>::max());
666 }
667
dispatchFormControlChangeEvent()668 void HTMLTextFormControlElement::dispatchFormControlChangeEvent()
669 {
670 if (m_textAsOfLastFormControlChangeEvent != value()) {
671 HTMLElement::dispatchChangeEvent();
672 setTextAsOfLastFormControlChangeEvent(value());
673 }
674 setChangedSinceLastFormControlChangeEvent(false);
675 }
676
setSelectionRange(int start,int end)677 void HTMLTextFormControlElement::setSelectionRange(int start, int end)
678 {
679 WebCore::setSelectionRange(this, start, end);
680 }
681
selectionStart() const682 int HTMLTextFormControlElement::selectionStart() const
683 {
684 if (!isTextFormControl())
685 return 0;
686 if (document()->focusedNode() != this && cachedSelectionStart() >= 0)
687 return cachedSelectionStart();
688 if (!renderer())
689 return 0;
690 return toRenderTextControl(renderer())->selectionStart();
691 }
692
selectionEnd() const693 int HTMLTextFormControlElement::selectionEnd() const
694 {
695 if (!isTextFormControl())
696 return 0;
697 if (document()->focusedNode() != this && cachedSelectionEnd() >= 0)
698 return cachedSelectionEnd();
699 if (!renderer())
700 return 0;
701 return toRenderTextControl(renderer())->selectionEnd();
702 }
703
selection() const704 PassRefPtr<Range> HTMLTextFormControlElement::selection() const
705 {
706 if (!renderer() || !isTextFormControl() || cachedSelectionStart() < 0 || cachedSelectionEnd() < 0)
707 return 0;
708 return toRenderTextControl(renderer())->selection(cachedSelectionStart(), cachedSelectionEnd());
709 }
710
parseMappedAttribute(Attribute * attr)711 void HTMLTextFormControlElement::parseMappedAttribute(Attribute* attr)
712 {
713 if (attr->name() == placeholderAttr)
714 updatePlaceholderVisibility(true);
715 else if (attr->name() == onselectAttr)
716 setAttributeEventListener(eventNames().selectEvent, createAttributeEventListener(this, attr));
717 else if (attr->name() == onchangeAttr)
718 setAttributeEventListener(eventNames().changeEvent, createAttributeEventListener(this, attr));
719 else
720 HTMLFormControlElementWithState::parseMappedAttribute(attr);
721 }
722
723 } // namespace Webcore
724