RESOLVED FIXED Bug 21248
Support placeholder on textarea
https://bugs.webkit.org/show_bug.cgi?id=21248
Summary Support placeholder on textarea
Andy Lyttle
Reported 2008-09-30 12:01:55 PDT
There's no reason why <textarea> shouldn't support the placeholder property, just like other text input fields do.
Attachments
Proposed patch (32.02 KB, patch)
2009-06-25 22:30 PDT, Kent Tamura
no flags
Proposed patch (rev.2) (31.87 KB, patch)
2009-06-26 01:48 PDT, Kent Tamura
no flags
Proposed patch (rev.3) (31.88 KB, patch)
2009-06-30 23:32 PDT, Kent Tamura
darin: review-
Proposed patch (rev.4) (42.71 KB, patch)
2009-08-10 19:11 PDT, Kent Tamura
eric: review+
eric: commit-queue-
Proposed patch (rev.5) (45.16 KB, patch)
2009-08-23 22:40 PDT, Kent Tamura
no flags
Proposed patch (rev.6) (45.24 KB, patch)
2009-08-23 22:46 PDT, Kent Tamura
no flags
Ojan Vafai
Comment 1 2008-10-13 15:24:52 PDT
I'd add also that contentEditable elements and designMode documents should support it as well. Really any text-input should support it.
Adele Peterson
Comment 2 2009-03-30 11:51:56 PDT
This has now been added in the HTML5 draft.
Kent Tamura
Comment 4 2009-06-25 04:35:28 PDT
*** Bug 26507 has been marked as a duplicate of this bug. ***
Kent Tamura
Comment 5 2009-06-25 04:36:19 PDT
I'm making a patch for this.
Kent Tamura
Comment 6 2009-06-25 22:30:04 PDT
Created attachment 31906 [details] Proposed patch
Eric Seidel (no email)
Comment 7 2009-06-26 01:23:08 PDT
Comment on attachment 31906 [details] Proposed patch It's sad we can't share more code here. Adele should really comment here.
Kent Tamura
Comment 8 2009-06-26 01:48:25 PDT
Created attachment 31919 [details] Proposed patch (rev.2) Some small changes.
Kent Tamura
Comment 9 2009-06-30 23:32:12 PDT
Created attachment 32114 [details] Proposed patch (rev.3) Update for the rename of css/html4.css.
Darin Adler
Comment 10 2009-08-07 08:02:42 PDT
Comment on attachment 32114 [details] Proposed patch (rev.3) Looks really good. Just a few comments. > +String HTMLTextAreaElement::placeholder() const > +{ > + return getAttribute(placeholderAttr).string(); > +} > + > +void HTMLTextAreaElement::setPlaceholder(const String& value) > +{ > + setAttribute(placeholderAttr, value); > +} These are not great. There's no need to convert to a plain string here, and in fact it's bad for performance. The right way to do this nowadays is to just put [Reflect] in the IDL file and not define a setPlaceholder function in the .h and .cpp file at all, so that should be done here. Since there are a couple call sites that do want placeholder, it would be OK to keep it but it could return const AtomicString& instead of String to avoid a bit of reference count churn and you probably would only have to use the string() function in one place. > + if ((oldPlaceholderShouldBeVisible != m_placeholderShouldBeVisible || placeholderValueChanged) > + && renderer()) > + static_cast<RenderTextControlMultiLine*>(renderer())->updatePlaceholderVisibility(); Indenting here is awkward. > + bool placeholderShouldBeVisible() const { return m_placeholderShouldBeVisible; } I think it would be a better design for the HTMLTextAreaElement to tell the > + virtual void dispatchFocusEvent(); > + virtual void dispatchBlurEvent(); These overrides should be private, not public, because we generally want all functions to be as private as possible. > + void setPlaceholderShouldBeVisible(bool visible) { m_placeholderShouldBeVisible = visible; } I don't think you need this setter function. It doesn't seem to add any abstraction. > + attribute DOMString placeholder; Just adding the [Reflect] attribute here will do the trick. > +void RenderTextControl::updatePlaceholderVisibility() > +{ > + RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(parentStyle()); > + HTMLElement* innerText = innerTextElement(); > + innerText->renderer()->setStyle(textBlockStyle); > + > + for (Node* n = innerText->firstChild(); n; n = n->traverseNextNode(innerText)) { > + if (RenderObject* renderer = n->renderer()) > + renderer->setStyle(textBlockStyle); > + } > + > + updateFromElement(); > +} I know you must moved this from one class to another, but this function needs some comments. It's unclear why updatePlaceholderVisibility needs to update the style of all the renderers and then call updateFromElement. A comment could explain the relationship. Also, we could consider moving code to set the text block style into a separate function, since the name of that function would help document it. > - if (result.innerNode() == node() || result.innerNode() == innerTextElement()) > + HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node()); > + if (result.innerNode() == node() > + || !textArea->placeholderShouldBeVisible() && result.innerNode() == innerTextElement() > + || textArea->placeholderShouldBeVisible() && result.innerNode()->isDescendantOf(innerTextElement())) > hitInnerTextElement(result, x, y, tx, ty); The way the formatting makes the clauses of the if statement line up with its body makes things like this hard to read. I think you could consider fixing that by using a boolean local variable; the name of the boolean could even help document a bit. I think the code also needs a comment. The rule here is slightly unclear unless the reader really aware of how placeholders should behave. I'm not so sure that it's great to move the m_placeholderVisible data member into the RenderTextControl base class. While it's true that both derived classes use it, the base class does not. > +RenderStyle* RenderTextControlMultiLine::parentStyle() I don't understand the use of "parent" in this name. This isn't really the style of the renderer's parent, because if so it wouldn't need to be a virtual function. I know the local variable was named that, but a local variable has less scope than a member function, and naming is slightly less critical when the name is that tightly scoped. But could we give this function a name that's more precise? Sorry, I don't have a specific name to suggest. > +protected: > + virtual RenderStyle* parentStyle(); This can and should be private instead of protected. You can override a function with a private function, and we should make things as private as possible. If we ever did want to derive from this class we could make it protected at that time. > +protected: > + virtual RenderStyle* parentStyle(); Ditto. review- because at least some of the changes above should be made
Kent Tamura
Comment 11 2009-08-10 19:03:34 PDT
Thank you for the comments! (In reply to comment #10) > (From update of attachment 32114 [details]) > Looks really good. Just a few comments. > > > +String HTMLTextAreaElement::placeholder() const > > +{ > > + return getAttribute(placeholderAttr).string(); > > +} > > + > > +void HTMLTextAreaElement::setPlaceholder(const String& value) > > +{ > > + setAttribute(placeholderAttr, value); > > +} > > These are not great. There's no need to convert to a plain string here, and in > fact it's bad for performance. The right way to do this nowadays is to just put > [Reflect] in the IDL file and not define a setPlaceholder function in the .h > and .cpp file at all, so that should be done here. Ok, I changed this to [Reflect]. > Indenting here is awkward. Fixed. > > + bool placeholderShouldBeVisible() const { return m_placeholderShouldBeVisible; } > > I think it would be a better design for the HTMLTextAreaElement to tell the I agree. When I looked at the existing placeholder code first time, I had an impression that the code was complex. I think the reason is that both of a DOM node and a renderer have flags for placeholder visibility. I have removed the flag of InputElemntData, and updated many place to tell the visibility from a DOM node to a renderer. > > + virtual void dispatchFocusEvent(); > > + virtual void dispatchBlurEvent(); > > These overrides should be private, not public, because we generally want all > functions to be as private as possible. Fixed. > > + void setPlaceholderShouldBeVisible(bool visible) { m_placeholderShouldBeVisible = visible; } > > I don't think you need this setter function. It doesn't seem to add any > abstraction. Removed. > > +void RenderTextControl::updatePlaceholderVisibility() > > +{ > > + RefPtr<RenderStyle> textBlockStyle = createInnerTextStyle(parentStyle()); > > + HTMLElement* innerText = innerTextElement(); > > + innerText->renderer()->setStyle(textBlockStyle); > > + > > + for (Node* n = innerText->firstChild(); n; n = n->traverseNextNode(innerText)) { > > + if (RenderObject* renderer = n->renderer()) > > + renderer->setStyle(textBlockStyle); > > + } > > + > > + updateFromElement(); > > +} > > I know you must moved this from one class to another, but this function needs > some comments. It's unclear why updatePlaceholderVisibility needs to update the > style of all the renderers and then call updateFromElement. A comment could > explain the relationship. Also, we could consider moving code to set the text > block style into a separate function, since the name of that function would > help document it. I have addded a new method, setInnerTextStyle(). > > - if (result.innerNode() == node() || result.innerNode() == innerTextElement()) > > + HTMLTextAreaElement* textArea = static_cast<HTMLTextAreaElement*>(node()); > > + if (result.innerNode() == node() > > + || !textArea->placeholderShouldBeVisible() && result.innerNode() == innerTextElement() > > + || textArea->placeholderShouldBeVisible() && result.innerNode()->isDescendantOf(innerTextElement())) > > hitInnerTextElement(result, x, y, tx, ty); > > The way the formatting makes the clauses of the if statement line up with its > body makes things like this hard to read. > > I think you could consider fixing that by using a boolean local variable; the > name of the boolean could even help document a bit. I think the code also needs > a comment. The rule here is slightly unclear unless the reader really aware of > how placeholders should behave. Done. > I'm not so sure that it's great to move the m_placeholderVisible data member > into the RenderTextControl base class. While it's true that both derived > classes use it, the base class does not. In the next patch, RenderTextControl refers m_placeholderVisible. > > +RenderStyle* RenderTextControlMultiLine::parentStyle() Renamed it to textBaseStyle(). > > +protected: > > + virtual RenderStyle* parentStyle(); > > This can and should be private instead of protected. You can override a > function with a private function, and we should make things as private as > possible. If we ever did want to derive from this class we could make it > protected at that time. Fixed.
Kent Tamura
Comment 12 2009-08-10 19:11:12 PDT
Created attachment 34534 [details] Proposed patch (rev.4) Sorry for the large patch. * The most of changes in HTMLInputElment, InputElment, WMLInputElement are trivial. (removal of unused parameters) * We have a bug about maxlength. The patch accidentally fixes it because of RenderTextControlSingleLine::updateFromElement() change. input-text-maxlength-expected.txt had wrong expected data.
Eric Seidel (no email)
Comment 13 2009-08-21 09:47:05 PDT
Comment on attachment 34534 [details] Proposed patch (rev.4) This looks great. I'm just sad we can's share implementations: + static void dispatchFocusEvent(InputElement*, Element*); + static void dispatchBlurEvent(InputElement*, Element*); + static bool placeholderShouldBeVisible(const InputElement*, const Element*); + static void updatePlaceholderVisibility(InputElement*, Element*, bool placeholderValueChanged = false); We could put those on HTMLFormControlElement... or on a new HTMLTextControlElement subclass. Or on some class which both of these used (since "having" placeholder text does not necessarily mean you need to "be" a classs which can have placehodler text. We could use 'has a' instead of 'is a' to share code.) I'm going to approve this as is. I would like you to consider a follow-up patch to share more of this code.
Eric Seidel (no email)
Comment 14 2009-08-21 12:07:12 PDT
Comment on attachment 34534 [details] Proposed patch (rev.4) Rejecting patch 34534 from commit-queue. This patch will require manual commit. ['WebKitTools/Scripts/run-webkit-tests', '--no-launch-safari', '--quiet', '--exit-after-n-failures=1'] failed with exit code 1
Eric Seidel (no email)
Comment 15 2009-08-21 12:07:40 PDT
fast/forms/input-text-maxlength.html -> failed
Kent Tamura
Comment 16 2009-08-23 22:40:35 PDT
Created attachment 38467 [details] Proposed patch (rev.5) Updated test cases.
Kent Tamura
Comment 17 2009-08-23 22:46:24 PDT
Created attachment 38468 [details] Proposed patch (rev.6) Oops, I found LayoutTests/ChangeLog in the rev.5 was incomplete. Corrected it.
Kent Tamura
Comment 18 2009-08-23 22:49:18 PDT
(In reply to comment #13) > I'm going to approve this as is. I would like you to consider a follow-up > patch to share more of this code. Sure. I'll try it.
Eric Seidel (no email)
Comment 19 2009-08-24 01:15:44 PDT
Comment on attachment 38468 [details] Proposed patch (rev.6) LGTM.
Eric Seidel (no email)
Comment 20 2009-08-24 01:28:58 PDT
Comment on attachment 38468 [details] Proposed patch (rev.6) Clearing flags on attachment: 38468 Committed r47702: <http://trac.webkit.org/changeset/47702>
Eric Seidel (no email)
Comment 21 2009-08-24 01:29:01 PDT
All reviewed patches have been landed. Closing bug.
Simon Fraser (smfr)
Comment 22 2009-08-24 11:11:01 PDT
4 textarea tests are still failing after this change.
Eric Seidel (no email)
Comment 23 2009-08-24 11:40:28 PDT
(In reply to comment #22) > 4 textarea tests are still failing after this change. On what platform? I assume windows since mac is green.
Eric Seidel (no email)
Comment 24 2009-08-24 11:41:54 PDT
http://build.webkit.org/results/Windows%20Release%20(Tests)/r47719%20(3707)/results.html Looks like windows will need new baselines or these tests will need to be converted not to be render tree dumps. tkent could do the test conversion, or we can just land the windows results from the bots.
Eric Seidel (no email)
Comment 25 2009-08-24 11:46:21 PDT
Will land windows results from the bot, shortly.
Eric Seidel (no email)
Comment 26 2009-08-24 12:10:24 PDT
Note You need to log in before you can comment on or make changes to this bug.