Commit 8a6d7d4f authored by tkent@chromium.org's avatar tkent@chromium.org

2010-02-02 Kent Tamura <tkent@chromium.org>

        Reviewed by Darin Adler.

        Fix a bug that changes for some constraint attributes doesn't
        update validation CSS selectors.
        https://bugs.webkit.org/show_bug.cgi?id=31716

        Add tests for maxLength changes and step changes.

        * fast/forms/input-live-pseudo-selectors-expected.txt:
        * fast/forms/resources/input-live-pseudo-selectors.js:
        * fast/forms/resources/textarea-live-pseudo-selectors.js:
        * fast/forms/textarea-live-pseudo-selectors-expected.txt:

2010-02-02  Kent Tamura  <tkent@chromium.org>

        Reviewed by Darin Adler.

        Fix a bug that changes for some constraint attributes doesn't
        update validation CSS selectors.
        https://bugs.webkit.org/show_bug.cgi?id=31716

        - Rename HTMLFormControlElement::updateValidity() to setNeedsValidityCheck()
        - Introduce HTMLFormControlElement::setNeedsWillValidate()
        - Introduce HTMLFormControlElement::m_hasName to make willValidate()
          work in parseMappedAttribute().
        - We need to call setNeedsValidityCheck() when HTMLInputElement::step or
          HTMLTextAreaElement::maxLength is changed.

        * html/HTMLFormControlElement.cpp:
        (WebCore::HTMLFormControlElement::HTMLFormControlElement):
        (WebCore::HTMLFormControlElement::parseMappedAttribute):
        (WebCore::HTMLFormControlElement::insertedIntoTree):
        (WebCore::HTMLFormControlElement::removedFromTree):
        (WebCore::HTMLFormControlElement::formDestroyed):
        (WebCore::HTMLFormControlElement::willValidate): Avoids function calls.
        (WebCore::HTMLFormControlElement::setNeedsWillValidateCheck):
        (WebCore::HTMLFormControlElement::setNeedsValidityCheck):
        * html/HTMLFormControlElement.h:
        (WebCore::HTMLFormControlElement::disabled): Move the code from .cpp.
        * html/HTMLInputElement.cpp:
        (WebCore::HTMLInputElement::setInputType):
        (WebCore::HTMLInputElement::parseMappedAttribute):
        (WebCore::HTMLInputElement::setValue):
        (WebCore::HTMLInputElement::setValueFromRenderer):
        (WebCore::HTMLInputElement::setFileListFromRenderer):
        * html/HTMLTextAreaElement.cpp:
        (WebCore::HTMLTextAreaElement::parseMappedAttribute):
        (WebCore::HTMLTextAreaElement::setValue):
        * rendering/RenderTextControlMultiLine.cpp:
        (WebCore::RenderTextControlMultiLine::subtreeHasChanged):

git-svn-id: svn://svn.chromium.org/blink/trunk@54274 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent fc1b7e3b
2010-02-02 Kent Tamura <tkent@chromium.org>
Reviewed by Darin Adler.
Fix a bug that changes for some constraint attributes doesn't
update validation CSS selectors.
https://bugs.webkit.org/show_bug.cgi?id=31716
Add tests for maxLength changes and step changes.
* fast/forms/input-live-pseudo-selectors-expected.txt:
* fast/forms/resources/input-live-pseudo-selectors.js:
* fast/forms/resources/textarea-live-pseudo-selectors.js:
* fast/forms/textarea-live-pseudo-selectors-expected.txt:
2010-02-02 Roland Steiner <rolandsteiner@chromium.org> 2010-02-02 Roland Steiner <rolandsteiner@chromium.org>
Reviewed by Adele Peterson. Reviewed by Adele Peterson.
......
...@@ -30,6 +30,10 @@ Change pattern: ...@@ -30,6 +30,10 @@ Change pattern:
PASS backgroundOf(el) is validColor PASS backgroundOf(el) is validColor
PASS backgroundOf(el) is invalidColor PASS backgroundOf(el) is invalidColor
PASS backgroundOf(el) is validColor PASS backgroundOf(el) is validColor
Change step:
PASS backgroundOf(el) is validColor
PASS backgroundOf(el) is invalidColor
PASS backgroundOf(el) is validColor
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
...@@ -98,5 +98,14 @@ shouldBe(elBackground, 'invalidColor'); ...@@ -98,5 +98,14 @@ shouldBe(elBackground, 'invalidColor');
el.pattern = 'a.c'; el.pattern = 'a.c';
shouldBe(elBackground, 'validColor'); shouldBe(elBackground, 'validColor');
debug('Change step:');
el = makeInvalid();
el.value = '1';
el.type = 'number';
shouldBe(elBackground, 'validColor');
el.step = '2';
shouldBe(elBackground, 'invalidColor');
el.step = '0.5';
shouldBe(elBackground, 'validColor');
var successfullyParsed = true; var successfullyParsed = true;
...@@ -89,5 +89,17 @@ shouldBe(elBackground, 'validColor'); ...@@ -89,5 +89,17 @@ shouldBe(elBackground, 'validColor');
el.required = true; el.required = true;
shouldBe(elBackground, 'invalidColor'); shouldBe(elBackground, 'invalidColor');
debug('Change maxlength:');
el = makeInvalid();
el.value = '1234567890';
shouldBe(elBackground, 'validColor');
// Make the value dirty by deleting the last character.
el.focus();
el.setSelectionRange(10, 10);
document.execCommand('delete');
el.maxLength = 5;
shouldBe(elBackground, 'invalidColor');
el.maxLength = 10;
shouldBe(elBackground, 'validColor');
var successfullyParsed = true; var successfullyParsed = true;
...@@ -26,6 +26,10 @@ PASS backgroundOf(el) is invalidColor ...@@ -26,6 +26,10 @@ PASS backgroundOf(el) is invalidColor
Change required: Change required:
PASS backgroundOf(el) is validColor PASS backgroundOf(el) is validColor
PASS backgroundOf(el) is invalidColor PASS backgroundOf(el) is invalidColor
Change maxlength:
PASS backgroundOf(el) is validColor
PASS backgroundOf(el) is invalidColor
PASS backgroundOf(el) is validColor
PASS successfullyParsed is true PASS successfullyParsed is true
TEST COMPLETE TEST COMPLETE
......
2010-02-02 Kent Tamura <tkent@chromium.org>
Reviewed by Darin Adler.
Fix a bug that changes for some constraint attributes doesn't
update validation CSS selectors.
https://bugs.webkit.org/show_bug.cgi?id=31716
- Rename HTMLFormControlElement::updateValidity() to setNeedsValidityCheck()
- Introduce HTMLFormControlElement::setNeedsWillValidate()
- Introduce HTMLFormControlElement::m_hasName to make willValidate()
work in parseMappedAttribute().
- We need to call setNeedsValidityCheck() when HTMLInputElement::step or
HTMLTextAreaElement::maxLength is changed.
* html/HTMLFormControlElement.cpp:
(WebCore::HTMLFormControlElement::HTMLFormControlElement):
(WebCore::HTMLFormControlElement::parseMappedAttribute):
(WebCore::HTMLFormControlElement::insertedIntoTree):
(WebCore::HTMLFormControlElement::removedFromTree):
(WebCore::HTMLFormControlElement::formDestroyed):
(WebCore::HTMLFormControlElement::willValidate): Avoids function calls.
(WebCore::HTMLFormControlElement::setNeedsWillValidateCheck):
(WebCore::HTMLFormControlElement::setNeedsValidityCheck):
* html/HTMLFormControlElement.h:
(WebCore::HTMLFormControlElement::disabled): Move the code from .cpp.
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::setInputType):
(WebCore::HTMLInputElement::parseMappedAttribute):
(WebCore::HTMLInputElement::setValue):
(WebCore::HTMLInputElement::setValueFromRenderer):
(WebCore::HTMLInputElement::setFileListFromRenderer):
* html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::parseMappedAttribute):
(WebCore::HTMLTextAreaElement::setValue):
* rendering/RenderTextControlMultiLine.cpp:
(WebCore::RenderTextControlMultiLine::subtreeHasChanged):
2010-02-02 Roland Steiner <rolandsteiner@chromium.org> 2010-02-02 Roland Steiner <rolandsteiner@chromium.org>
Reviewed by Adele Peterson. Reviewed by Adele Peterson.
......
...@@ -52,6 +52,7 @@ using namespace HTMLNames; ...@@ -52,6 +52,7 @@ using namespace HTMLNames;
HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f) HTMLFormControlElement::HTMLFormControlElement(const QualifiedName& tagName, Document* doc, HTMLFormElement* f)
: HTMLElement(tagName, doc) : HTMLElement(tagName, doc)
, m_form(f) , m_form(f)
, m_hasName(false)
, m_disabled(false) , m_disabled(false)
, m_readOnly(false) , m_readOnly(false)
, m_required(false) , m_required(false)
...@@ -89,8 +90,9 @@ ValidityState* HTMLFormControlElement::validity() ...@@ -89,8 +90,9 @@ ValidityState* HTMLFormControlElement::validity()
void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr)
{ {
bool oldWillValidate = willValidate();
if (attr->name() == nameAttr) if (attr->name() == nameAttr)
setNeedsStyleRecalc(); m_hasName = !attr->isEmpty();
else if (attr->name() == disabledAttr) { else if (attr->name() == disabledAttr) {
bool oldDisabled = m_disabled; bool oldDisabled = m_disabled;
m_disabled = !attr->isNull(); m_disabled = !attr->isNull();
...@@ -114,6 +116,8 @@ void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr) ...@@ -114,6 +116,8 @@ void HTMLFormControlElement::parseMappedAttribute(MappedAttribute *attr)
setNeedsStyleRecalc(); setNeedsStyleRecalc();
} else } else
HTMLElement::parseMappedAttribute(attr); HTMLElement::parseMappedAttribute(attr);
if (oldWillValidate != willValidate())
setNeedsWillValidateCheck();
} }
void HTMLFormControlElement::attach() void HTMLFormControlElement::attach()
...@@ -149,9 +153,10 @@ void HTMLFormControlElement::insertedIntoTree(bool deep) ...@@ -149,9 +153,10 @@ void HTMLFormControlElement::insertedIntoTree(bool deep)
// setting a form, we will already have a non-null value for m_form, // setting a form, we will already have a non-null value for m_form,
// and so we don't need to do anything. // and so we don't need to do anything.
m_form = findFormAncestor(); m_form = findFormAncestor();
if (m_form) if (m_form) {
m_form->registerFormElement(this); m_form->registerFormElement(this);
else setNeedsWillValidateCheck();
} else
document()->checkedRadioButtons().addButton(this); document()->checkedRadioButtons().addButton(this);
} }
...@@ -178,11 +183,19 @@ void HTMLFormControlElement::removedFromTree(bool deep) ...@@ -178,11 +183,19 @@ void HTMLFormControlElement::removedFromTree(bool deep)
if (m_form && !(parser && parser->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) { if (m_form && !(parser && parser->isHandlingResidualStyleAcrossBlocks()) && findRoot(this) != findRoot(m_form)) {
m_form->removeFormElement(this); m_form->removeFormElement(this);
m_form = 0; m_form = 0;
setNeedsWillValidateCheck();
} }
HTMLElement::removedFromTree(deep); HTMLElement::removedFromTree(deep);
} }
void HTMLFormControlElement::formDestroyed()
{
if (m_form)
setNeedsWillValidateCheck();
m_form = 0;
}
const AtomicString& HTMLFormControlElement::formControlName() const const AtomicString& HTMLFormControlElement::formControlName() const
{ {
const AtomicString& n = getAttribute(nameAttr); const AtomicString& n = getAttribute(nameAttr);
...@@ -199,11 +212,6 @@ void HTMLFormControlElement::dispatchFormControlChangeEvent() ...@@ -199,11 +212,6 @@ void HTMLFormControlElement::dispatchFormControlChangeEvent()
dispatchEvent(Event::create(eventNames().changeEvent, true, false)); dispatchEvent(Event::create(eventNames().changeEvent, true, false));
} }
bool HTMLFormControlElement::disabled() const
{
return m_disabled;
}
void HTMLFormControlElement::setDisabled(bool b) void HTMLFormControlElement::setDisabled(bool b)
{ {
setAttribute(disabledAttr, b ? "" : 0); setAttribute(disabledAttr, b ? "" : 0);
...@@ -297,7 +305,7 @@ bool HTMLFormControlElement::willValidate() const ...@@ -297,7 +305,7 @@ bool HTMLFormControlElement::willValidate() const
// The control does not have a repetition template as an ancestor. // The control does not have a repetition template as an ancestor.
// The control does not have a datalist element as an ancestor. // The control does not have a datalist element as an ancestor.
// The control is not an output element. // The control is not an output element.
return form() && !name().isEmpty() && !disabled() && !isReadOnlyFormControl(); return m_form && m_hasName && !m_disabled && !m_readOnly;
} }
String HTMLFormControlElement::validationMessage() String HTMLFormControlElement::validationMessage()
...@@ -305,6 +313,12 @@ String HTMLFormControlElement::validationMessage() ...@@ -305,6 +313,12 @@ String HTMLFormControlElement::validationMessage()
return validity()->validationMessage(); return validity()->validationMessage();
} }
void HTMLFormControlElement::setNeedsWillValidateCheck()
{
setNeedsStyleRecalc();
// FIXME: Show/hide a validation message.
}
bool HTMLFormControlElement::checkValidity() bool HTMLFormControlElement::checkValidity()
{ {
if (willValidate() && !isValidFormControlElement()) { if (willValidate() && !isValidFormControlElement()) {
...@@ -315,12 +329,13 @@ bool HTMLFormControlElement::checkValidity() ...@@ -315,12 +329,13 @@ bool HTMLFormControlElement::checkValidity()
return true; return true;
} }
void HTMLFormControlElement::updateValidity() void HTMLFormControlElement::setNeedsValidityCheck()
{ {
if (willValidate()) { if (willValidate()) {
// Update style for pseudo classes such as :valid :invalid. // Update style for pseudo classes such as :valid :invalid.
setNeedsStyleRecalc(); setNeedsStyleRecalc();
} }
// FIXME: show/hide a validation message.
} }
void HTMLFormControlElement::setCustomValidity(const String& error) void HTMLFormControlElement::setCustomValidity(const String& error)
......
...@@ -63,7 +63,7 @@ public: ...@@ -63,7 +63,7 @@ public:
virtual void dispatchFormControlChangeEvent(); virtual void dispatchFormControlChangeEvent();
bool disabled() const; bool disabled() const { return m_disabled; }
void setDisabled(bool); void setDisabled(bool);
virtual bool supportsFocus() const; virtual bool supportsFocus() const;
...@@ -109,19 +109,22 @@ public: ...@@ -109,19 +109,22 @@ public:
virtual bool willValidate() const; virtual bool willValidate() const;
String validationMessage(); String validationMessage();
bool checkValidity(); bool checkValidity();
void updateValidity(); // This must be called when a validation constraint or control value is changed.
void setNeedsValidityCheck();
void setCustomValidity(const String&); void setCustomValidity(const String&);
virtual bool valueMissing() const { return false; } virtual bool valueMissing() const { return false; }
virtual bool patternMismatch() const { return false; } virtual bool patternMismatch() const { return false; }
virtual bool tooLong() const { return false; } virtual bool tooLong() const { return false; }
void formDestroyed() { m_form = 0; } void formDestroyed();
virtual void dispatchFocusEvent(); virtual void dispatchFocusEvent();
virtual void dispatchBlurEvent(); virtual void dispatchBlurEvent();
protected: protected:
void removeFromForm(); void removeFromForm();
// This must be called any time the result of willValidate() has changed.
void setNeedsWillValidateCheck();
private: private:
virtual HTMLFormElement* virtualForm() const; virtual HTMLFormElement* virtualForm() const;
...@@ -130,6 +133,7 @@ private: ...@@ -130,6 +133,7 @@ private:
HTMLFormElement* m_form; HTMLFormElement* m_form;
OwnPtr<ValidityState> m_validityState; OwnPtr<ValidityState> m_validityState;
bool m_hasName : 1;
bool m_disabled : 1; bool m_disabled : 1;
bool m_readOnly : 1; bool m_readOnly : 1;
bool m_required : 1; bool m_required : 1;
......
...@@ -713,6 +713,7 @@ void HTMLInputElement::setInputType(const String& t) ...@@ -713,6 +713,7 @@ void HTMLInputElement::setInputType(const String& t)
// type change, otherwise a JavaScript programmer would be able to set a text // type change, otherwise a JavaScript programmer would be able to set a text
// field's value to something like /etc/passwd and then change it to a file field. // field's value to something like /etc/passwd and then change it to a file field.
if (inputType() != newType) { if (inputType() != newType) {
bool oldWillValidate = willValidate();
if (newType == FILE && m_haveType) if (newType == FILE && m_haveType)
// Set the attribute back to the old value. // Set the attribute back to the old value.
// Useful in case we were called from inside parseMappedAttribute. // Useful in case we were called from inside parseMappedAttribute.
...@@ -769,8 +770,10 @@ void HTMLInputElement::setInputType(const String& t) ...@@ -769,8 +770,10 @@ void HTMLInputElement::setInputType(const String& t)
checkedRadioButtons(this).addButton(this); checkedRadioButtons(this).addButton(this);
} }
setNeedsValidityCheck();
if (oldWillValidate != willValidate())
setNeedsWillValidateCheck();
InputElement::notifyFormStateChanged(this); InputElement::notifyFormStateChanged(this);
updateValidity();
} }
m_haveType = true; m_haveType = true;
...@@ -992,17 +995,18 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) ...@@ -992,17 +995,18 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
if (m_data.value().isNull()) if (m_data.value().isNull())
setNeedsStyleRecalc(); setNeedsStyleRecalc();
setFormControlValueMatchesRenderer(false); setFormControlValueMatchesRenderer(false);
updateValidity(); setNeedsValidityCheck();
} else if (attr->name() == checkedAttr) { } else if (attr->name() == checkedAttr) {
m_defaultChecked = !attr->isNull(); m_defaultChecked = !attr->isNull();
if (m_useDefaultChecked) { if (m_useDefaultChecked) {
setChecked(m_defaultChecked); setChecked(m_defaultChecked);
m_useDefaultChecked = true; m_useDefaultChecked = true;
} }
updateValidity(); setNeedsValidityCheck();
} else if (attr->name() == maxlengthAttr) } else if (attr->name() == maxlengthAttr) {
InputElement::parseMaxLengthAttribute(m_data, this, this, attr); InputElement::parseMaxLengthAttribute(m_data, this, this, attr);
else if (attr->name() == sizeAttr) setNeedsValidityCheck();
} else if (attr->name() == sizeAttr)
InputElement::parseSizeAttribute(m_data, this, attr); InputElement::parseSizeAttribute(m_data, this, attr);
else if (attr->name() == altAttr) { else if (attr->name() == altAttr) {
if (renderer() && inputType() == IMAGE) if (renderer() && inputType() == IMAGE)
...@@ -1046,15 +1050,16 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr) ...@@ -1046,15 +1050,16 @@ void HTMLInputElement::parseMappedAttribute(MappedAttribute *attr)
attach(); attach();
} }
setNeedsStyleRecalc(); setNeedsStyleRecalc();
} else if (attr->name() == autosaveAttr || } else if (attr->name() == autosaveAttr
attr->name() == incrementalAttr || || attr->name() == incrementalAttr)
attr->name() == minAttr ||
attr->name() == maxAttr ||
attr->name() == multipleAttr ||
attr->name() == precisionAttr)
setNeedsStyleRecalc(); setNeedsStyleRecalc();
else if (attr->name() == patternAttr) else if (attr->name() == minAttr
updateValidity(); || attr->name() == maxAttr
|| attr->name() == multipleAttr
|| attr->name() == patternAttr
|| attr->name() == precisionAttr
|| attr->name() == stepAttr)
setNeedsValidityCheck();
#if ENABLE(DATALIST) #if ENABLE(DATALIST)
else if (attr->name() == listAttr) else if (attr->name() == listAttr)
m_hasNonEmptyList = !attr->isEmpty(); m_hasNonEmptyList = !attr->isEmpty();
...@@ -1496,7 +1501,7 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent) ...@@ -1496,7 +1501,7 @@ void HTMLInputElement::setValue(const String& value, bool sendChangeEvent)
dispatchFormControlChangeEvent(); dispatchFormControlChangeEvent();
InputElement::notifyFormStateChanged(this); InputElement::notifyFormStateChanged(this);
updateValidity(); setNeedsValidityCheck();
} }
double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const double HTMLInputElement::parseToDouble(const String& src, double defaultValue) const
...@@ -1770,7 +1775,7 @@ void HTMLInputElement::setValueFromRenderer(const String& value) ...@@ -1770,7 +1775,7 @@ void HTMLInputElement::setValueFromRenderer(const String& value)
m_data.setSuggestedValue(String()); m_data.setSuggestedValue(String());
updatePlaceholderVisibility(false); updatePlaceholderVisibility(false);
InputElement::setValueFromRenderer(m_data, this, this, value); InputElement::setValueFromRenderer(m_data, this, this, value);
updateValidity(); setNeedsValidityCheck();
} }
void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
...@@ -1782,7 +1787,7 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths) ...@@ -1782,7 +1787,7 @@ void HTMLInputElement::setFileListFromRenderer(const Vector<String>& paths)
setFormControlValueMatchesRenderer(true); setFormControlValueMatchesRenderer(true);
InputElement::notifyFormStateChanged(this); InputElement::notifyFormStateChanged(this);
updateValidity(); setNeedsValidityCheck();
} }
bool HTMLInputElement::storesValueSeparateFromAttribute() const bool HTMLInputElement::storesValueSeparateFromAttribute() const
......
...@@ -150,7 +150,9 @@ void HTMLTextAreaElement::parseMappedAttribute(MappedAttribute* attr) ...@@ -150,7 +150,9 @@ void HTMLTextAreaElement::parseMappedAttribute(MappedAttribute* attr)
} else if (attr->name() == alignAttr) { } else if (attr->name() == alignAttr) {
// Don't map 'align' attribute. This matches what Firefox, Opera and IE do. // Don't map 'align' attribute. This matches what Firefox, Opera and IE do.
// See http://bugs.webkit.org/show_bug.cgi?id=7075 // See http://bugs.webkit.org/show_bug.cgi?id=7075
} else } else if (attr->name() == maxlengthAttr)
setNeedsValidityCheck();
else
HTMLTextFormControlElement::parseMappedAttribute(attr); HTMLTextFormControlElement::parseMappedAttribute(attr);
} }
...@@ -297,9 +299,8 @@ void HTMLTextAreaElement::setValue(const String& value) ...@@ -297,9 +299,8 @@ void HTMLTextAreaElement::setValue(const String& value)
setSelectionRange(endOfString, endOfString); setSelectionRange(endOfString, endOfString);
} }
setNeedsStyleRecalc(); setNeedsValidityCheck();
notifyFormStateChanged(this); notifyFormStateChanged(this);
updateValidity();
} }
String HTMLTextAreaElement::defaultValue() const String HTMLTextAreaElement::defaultValue() const
......
...@@ -47,7 +47,7 @@ void RenderTextControlMultiLine::subtreeHasChanged() ...@@ -47,7 +47,7 @@ void RenderTextControlMultiLine::subtreeHasChanged()
RenderTextControl::subtreeHasChanged(); RenderTextControl::subtreeHasChanged();
HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node()); HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node());
textArea->setFormControlValueMatchesRenderer(false); textArea->setFormControlValueMatchesRenderer(false);
textArea->updateValidity(); textArea->setNeedsValidityCheck();
if (!node()->focused()) if (!node()->focused())
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment