Closed
Bug 231081
Opened 21 years ago
Closed 21 years ago
Checkboxes and radio buttons with dynamic selector :checked and adjacent combinator does not reresolve style
Categories
(Core :: CSS Parsing and Computation, defect)
Core
CSS Parsing and Computation
Tracking
()
RESOLVED
FIXED
People
(Reporter: martijn.martijn, Assigned: dbaron)
Details
Attachments
(3 files, 2 obsolete files)
1.92 KB,
text/html
|
Details | |
19.93 KB,
patch
|
bzbarsky
:
review+
jst
:
superreview+
|
Details | Diff | Splinter Review |
5.14 KB,
patch
|
Details | Diff | Splinter Review |
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6b) Gecko/20031216 Firebird/0.7+ Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.6b) Gecko/20031216 Firebird/0.7+ From: http://bugzilla.mozilla.org/show_bug.cgi?id=15608#c60 See testcase that I'm attaching. Using this snippet in html: <input type="checkbox" name="test" id="c1"><label for="c1">check #c1</label> and this style: input{display:none;} input:checked+label{background-color:green;} you can still check the checkbox and the label becomes green, but unchecking the checkbox (which works with display:none), the label stays green. Checking/unchecking a checkbox to the left of the original does reresolve the style in the right way. Reproducible: Always Steps to Reproduce: 1. Press button: toggle display radio/checkbox buttons -> inputs have display:none 2. check/uncheck the checkboxes 3. Actual Results: See Details Expected Results: Reresolve the style of the labels in the right way. An easy workaround for this problem is to use: input {visibility:hidden;position:absolute;} This works and has the same effect as display:none
Reporter | ||
Comment 1•21 years ago
|
||
Comment 2•21 years ago
|
||
The bug seems to be in the code at http://lxr.mozilla.org/seamonkey/source/content/html/content/src/nsHTMLInputElement.cpp#1122
Comment 3•21 years ago
|
||
So the problem seems to be that this is a misuse of the nsIDocument/nsIDocumentObserver apis, pure and simple -- BeginUpdate and EndUpdate are not getting called around the ContentStatesChanged call. The right fix would be, imo: 1) Add an aNotify arg to SetCheckedInternal 2) Change callers to pass TRUE or FALSE as needed (eg DoneCreatingElement should end up passing FALSE). 3) If aNotify is true, BeginUpdate, do the content state change, and EndUpdate. Steps 1 and 2 are really optional, but will keep us from flushing the content sink on every single checkbox that has the checked attr set. David, let me know whether you have time to deal with this; if not, I could do it, I think.
Status: UNCONFIRMED → NEW
Ever confirmed: true
OS: Windows 2000 → All
Hardware: PC → All
Assignee | ||
Comment 4•21 years ago
|
||
This doesn't fix the problem with radio inputs.
Assignee | ||
Comment 5•21 years ago
|
||
Of course, the problem is that nsHTMLInputElement::SetCheckedInternal has to do *more* when there's no frame...
Comment 6•21 years ago
|
||
I apologize for the unclear comment. Here's a patch to illustrate what I was talking about (-w for discussion; once we decide what the right thing to do is I'll make a patch that can actually go in). The reason this bug happens is that ContentStatesChanged doesn't get called on the input when there is no frame. As a result, the restyling doesn't happen. The fix for that is to make sure to call ContentStatesChanged no matter whether we have a frame (that's what this patch does, and it fixes the bug for me). That's what the code looked like when we had bug 134560 -- it called ContentStatesChanged on the node (which had no frame _yet_) and the frame constructor saw there was no frame and called RecreateFramesForContent which created the frame; then control unwound back to the content sink, which called ContentAppended on the node, which caused the frame constructor to create another frame for it. Hence my comment about adding a BeginUpdate() call -- that makes the sink call ContentAppended on whatever it currently has that's not been "officially" appended yet before control returns to the caller of BeginUpdate(). The thing is, we no longer call RecreateFramesForContent from content state notification code -- we call MaybeRecreateFramesForContent. This doesn't construct a frame unless the node is in the undisplayed map, and nodes that have never been notified for are not in the undisplayed map. So even if I remove the BeginUpdate/EndUpdate calls here I don't get bug 134560 with the testcase in that bug. I could probably produce bug 134560 with a more complicated setup in the current world, eg if the checked state of the checkbox caused a reframe of the parent, and not all of the parent's kids had had ContentAppended called on them yet (probably need to use our IB stuff and selectors that affect preceding siblings, or just selectors that affect the parent). So to summarize: 1) To fix this bug we need to call ContentStatesChanged no matter whether we have the frame. 2) I don't _think_ that will regress bug 134560 immediately. 3) To make sure we don't regress bug 134560 we should call BeginUpdate/EndUpdate 4) To prevent this being a performance problem and to prevent the content sink from confusing itself, we should not do any of this when the code is being called from the content sink. Does that make sense?
Updated•21 years ago
|
Attachment #139231 -
Attachment is obsolete: true
Assignee | ||
Comment 7•21 years ago
|
||
I'd come to pretty much the same patch when I wrote comment 5. I probably need to split pretty much all of SetChecked into DoSetChecked and add an aNotify parameter to DoSetChecked and a bunch of other functions (including SetCheckedInternal).
Assignee | ||
Comment 8•21 years ago
|
||
Attachment #139248 -
Attachment is obsolete: true
Assignee | ||
Updated•21 years ago
|
Attachment #139251 -
Flags: review?(bz-vacation)
Comment 9•21 years ago
|
||
Comment on attachment 139251 [details] [diff] [review] patch >Index: src/nsHTMLInputElement.cpp >+nsHTMLInputElement::RadioSetChecked(PRBool aNotify) > rv = NS_STATIC_CAST(nsHTMLInputElement*, > NS_STATIC_CAST(nsIDOMHTMLInputElement*, currentlySelected) >- )->SetCheckedInternal(PR_FALSE); >+ )->SetCheckedInternal(PR_FALSE, PR_TRUE); Why PR_TRUE there instead of aNotify? I guess we need to make sure that any radios that are already in the doc that this affects get notified properly, right? Add a comment to that effect? r=bzbarsky with that.
Attachment #139251 -
Flags: review?(bz-vacation) → review+
Assignee | ||
Updated•21 years ago
|
Attachment #139251 -
Flags: superreview?(jst)
Comment 10•21 years ago
|
||
Comment on attachment 139251 [details] [diff] [review] patch - In nsHTMLInputElement::MaybeSubmitForm(): + if (mDocument && aNotify) { + mDocument->BeginUpdate(UPDATE_CONTENT_STATE); mDocument->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_CHECKED); + mDocument->EndUpdate(UPDATE_CONTENT_STATE); } Wanna use mozAutoDocUpdate(mDocument, UPDATE_CONTENT_STATE, aNotify) here in stead of writing it out? - In nsHTMLOptionElement::SetSelectedInternal(): + if (aNotify && mDocument) { + mDocument->BeginUpdate(UPDATE_CONTENT_STATE); mDocument->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_CHECKED); + mDocument->EndUpdate(UPDATE_CONTENT_STATE); + } Same here. sr=jst either way.
Attachment #139251 -
Flags: superreview?(jst) → superreview+
Assignee | ||
Comment 11•21 years ago
|
||
Fix checked in to trunk, 2004-01-20 20:28 -0800.
Status: NEW → RESOLVED
Closed: 21 years ago
Resolution: --- → FIXED
Assignee | ||
Comment 12•19 years ago
|
||
Comment on attachment 139251 [details] [diff] [review] patch >-nsHTMLInputElement::AddedToRadioGroup() >+nsHTMLInputElement::AddedToRadioGroup(PRBool aNotify) > { >+ if (aNotify) >+ aNotify = GET_BOOLBIT(mBitField, BF_PARSER_CREATING) != 0; bzbarsky poinst out this should have been == 0, or just a !. He even commented it since as thought it was written that way.
Comment 13•16 years ago
|
||
These pass on trunk. The display:none parts fail in "Firebird 2004-01-17-02-trunk", but not in exactly the same way as the original testcase. I guess clicking is special?
Comment 14•16 years ago
|
||
Clicking shouldn't be special here.
Comment 15•16 years ago
|
||
One difference between clicking and script when checking multiple things is that when clicking we'll process restyles between clicks. Does adding flushes between the scripted sets change behavior?
Comment 16•16 years ago
|
||
The difference between clicking and js-setting persists even if I add flushes or only toggle one checkbox at a time. Clicking can turn items yellow (but not white); js-setting does not change the color at all. That's all with Firebird 2004-01-17-02-trunk. Trunk does fine.
Comment 17•16 years ago
|
||
The tests pass in Firebird 2004-01-21-02-trunk (that's four days after the other build I tested), so I think they're at least testing the same bug :) Using cb.click() instead of cb.checked=!cb.checked doesn't affect the result in the older build.
Comment 18•16 years ago
|
||
Should I worry about this, or should I just check in the tests? :)
Comment 19•16 years ago
|
||
Checked in tests: http://hg.mozilla.org/mozilla-central/rev/e467c9f03ada
Flags: in-testsuite+
Comment 20•16 years ago
|
||
Oh, display:none.... No color change at all is sorta what I'd expect there for those builds.
You need to log in
before you can comment on or make changes to this bug.
Description
•