Closed Bug 271720 Opened 20 years ago Closed 19 years ago

Use pseudoclasses instead of attributes

Categories

(Core Graveyard :: XForms, enhancement)

enhancement
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: allan, Assigned: allan)

References

()

Details

(Keywords: css3, fixed1.8)

Attachments

(4 files, 15 obsolete files)

(deleted), application/xhtml+xml
Details
(deleted), application/xhtml+xml
Details
(deleted), application/xhtml+xml
Details
(deleted), patch
doronr
: review+
aaronr
: review+
Details | Diff | Splinter Review
We need to support the pseudoclasses specified in the spec (see URL), that is :disabled, :enabled, :read-only, etc.
It depends on two patches to extensions/xforms.
Attached patch Patch to extensions/xforms (obsolete) (deleted) — Splinter Review
This patch patches the patch from bug 265467, os it utilitzes the two pseudoclasses (only for xforms:input though).
Attached file Document that shows the pseudoclass usage (obsolete) (deleted) —
I have only implemented enabled and disabled, so we can discuss how to implement this. :enabled and :disabled are general pseudoclasses I think, but we also need to have :read-only, :read-write, etc. that, as far as I know, are XForms specific. 1) How should the interface look like? As I see it, nsXFormsControl should have a getNodeState() function, that could return the current node state (read-only, read-write, etc.), or specific functions as in the patch: isRelative, isReadonly, isValid, etc. Through use of nsXFormsNodeState, they could be handled the same way for all controls, either through a inheritance or through nsXFormsUtils. 2) Should the interface live? We could either implement it through nsIXFormsControl, og a more generic pseudoclass interface, if other controls should have the same pseudoclasses? (Somebody with more "Mozilla-community knowledge" should probably CC the appropriate people...)
Status: NEW → ASSIGNED
These pseudo-classes also apply to HTML controls. Don't we already support :enabled/:disabled and some of the others? I'm sure I've seen bugs on these pseudo-classes, maybe they haven't yet had patches checked in.
Depends on: 84400
It's not clear to me how using a single flag manages to implement both enabled and disabled.... (unless we assume they are mutually exclusive, which they are not). What those should be are two separate content states. I have a partial patch to that effect in my tree (see discussion in bug 84400 for why it's not attached anywhere or checked in).
Heh, searched the tree but not Bugzilla, silly me... oh well, that clarifies a lot :) To bzbarsky: Absolutely right, we cannot use a single state, as elements could be in a state where they are neither disabled or enabled. To ian: We still need :in-range, :out-of-range, :read-only, and :read-write, and as bzbarsky correctly noted, f.x. enabled and disabled are not mutually exclusive. Should we not try to be as close to the CSS3-UI as possible?
...maybe we should keep CSS3-UI discussion on bug 84400, and only have the XForms related stuff on this bug?
:enabled and :disabled are mutually exclusive, but not all elements match both, true. The spec should be updated (it is indeed out of date); my point was just that we should use an API along those lines. (That spec doesn't cover :in-range yet either because it was written before :in-range was added to CSS3 UI.)
(In reply to comment #9) > ...maybe we should keep CSS3-UI discussion on bug 84400, and only have the > XForms related stuff on this bug? I guess there should be separate bugs for other pseudo-classes (and pseudo-elements) from CSS3 UI. That bug is just for :disabled and :enabled.
(In reply to comment #11) > (In reply to comment #9) > > ...maybe we should keep CSS3-UI discussion on bug 84400, and only have the > > XForms related stuff on this bug? > > I guess there should be separate bugs for other pseudo-classes (and > pseudo-elements) from CSS3 UI. That bug is just for :disabled and :enabled. Fair enough, how about creating a CSS3 UI tracking bug?
Blocks: 265467
I'm ok with it though I believe most people don't like tracking bugs. You could mark them as blocking bug 65133 though. Since they are selectors, after all.
Blocks: 278370
No longer blocks: 278370
Attached patch Patch v2 (obsolete) (deleted) — Splinter Review
Here's another go at it. I'm not too fond of it though. nsIDOMCSS3UIPseudoClass is a "nice looking" interface, but I would rather return two bit-vector PRInt8s. One for the "presence" (applicability?) of the state and the other for the state itself. That would only need one function call, and most of the implementation could be done by bit operators. Arguments for/against, comments to the code, etc? I'm all ears.
Attachment #167022 - Attachment is obsolete: true
Comment on attachment 174289 [details] [diff] [review] Patch v2 This whole tri-state boolean business is all wrong. :not() matches whenever its argument doesn't. The interface name nsIDOMCSS3UIPseudoClass is wrong. An object implementing it is not a pseudo-class. The interface name should be something that it is.
Attachment #174289 - Flags: review-
Thanks for looking at it right away. (In reply to comment #15) > (From update of attachment 174289 [details] [diff] [review] [edit]) > This whole tri-state boolean business is all wrong. :not() matches whenever > its argument doesn't. I'm not sure I'm following you. I'm possibly returning the wrong value in result. I thought I should return localTrue or localFalse, but I should compare with them instead? result = (aStateMask & NS_EVENT_STATE_READONLY) || (localTrue == (data.mIsReadonly == checkVal)); ? As far as I can see, we need the "tri-state boolean business". > The interface name nsIDOMCSS3UIPseudoClass is wrong. An object implementing it > is not a pseudo-class. The interface name should be something that it is. nsIDOMCSS3UIElement? Should then include the pseudo-elements too I guess? How about the bit-vector vs. "niceness" issue for the interface?
Sorry, I misread your selector matching code, so never mind the :not() bit. But I still don't see the need for the tri-state boolean.
Comment on attachment 174289 [details] [diff] [review] Patch v2 Never mind, I see now. But you still need a better name for the interface.
However, for dynamic change handling, I think you're probably better off using the event state manager and having a bit for each pseudo-class (rather than pair). It looks like this patch is very incomplete, though, so it's hard to tell.
Actually, maybenever mind about using the event state manager -- I don't think you gain much -- except in the case of things that should be supported by a whole bunch of other types of elements, like :enabled and :disabled, :default, or :read-only and :read-write. But I'm not sure if the ESM is the right place for them, either. But I still don't see the other side of the code for anything other than NS_EVENT_STATE_RELEVANT. (And we shouldn't start parsing them until we really support them.) Speaking of which, the state names could also probably use some improvement. They should probably all (except :default) be NS_EVENT_STATE_PAIR_* since it's a pair of states represented by a single bit, and you should probably use NS_EVENT_STATE_PAIR_ENABLED rather than RELEVANT since there's nothing called :relevant (but there could be in the future). But the ones that apply elsewhere probably can't be implemented as a single bit in the long term.
(In reply to comment #20) > Actually, maybenever mind about using the event state manager -- I don't think > you gain much -- except in the case of things that should be supported by a > whole bunch of other types of elements, like :enabled and :disabled, :default, > or :read-only and :read-write. But I'm not sure if the ESM is the right place > for them, either. I'm not the guy to ask. I was hoping you were :) > But I still don't see the other side of the code for anything other than > NS_EVENT_STATE_RELEVANT. (And we shouldn't start parsing them until we really > support them.) nsXFormsControlStub::ToggleProperty() is setting attributes for the moment, it should set the pseudoclasses http://lxr.mozilla.org/seamonkey/source/extensions/xforms/nsXFormsControlStub.cpp#236 I did not want to code it before the interface was agreed upon. > Speaking of which, the state names could also probably use some improvement. > They should probably all (except :default) be NS_EVENT_STATE_PAIR_* since it's a > pair of states represented by a single bit, and you should probably use > NS_EVENT_STATE_PAIR_ENABLED rather than RELEVANT since there's nothing called > :relevant (but there could be in the future). Consider it done. I've also renamed defaultState to defaultPseudo. > But the ones that apply elsewhere probably can't be implemented as a single > bit in the long term. Sorry?
Attached patch Patch v3 (obsolete) (deleted) — Splinter Review
Still tri-state, but the comments I've understood are implemented.
Attachment #174289 - Attachment is obsolete: true
Attachment #176728 - Flags: review?(dbaron)
Attached patch Full patch for extensions/xforms (obsolete) (deleted) — Splinter Review
Attachment #167023 - Attachment is obsolete: true
Attached file Testdocument (deleted) —
This document shows the usage of the different classes (except :in-range/:out-of-range).
Attachment #167024 - Attachment is obsolete: true
You haven't addressed the key comment, which I probably should have made clearer in comment 20 (although I think I may have in email), which is that this is fundamentally the wrong design and doesn't extend outside of XForms. Because of that, I'm against taking the patch, since once we start parsing a selector we should be doing it right -- that's what allows authors to write stylesheets that work cross-browser by depending on the CSS forward-compatible parsing rules. Doing it right is harder, and I haven't had the time to think through how that should work yet.
(In reply to comment #25) Hmmm, you are not really helping me here David. > You haven't addressed the key comment, which I probably should have made clearer > in comment 20 (although I think I may have in email), which is that this is > fundamentally the wrong design and doesn't extend outside of XForms. It's still not clear to me what you see as the problem. Any element can implement the interface, and elements not implementing it are not influenced. My best guess from your previous comments is in comment 20: > But the ones that apply elsewhere probably can't be implemented as a single > bit in the long term. Could you elaborate on that? I'm not using a single bit, I'm using the tri-state. It is my understanding that any element can either be f.x. :enabled (x)or :disabled, so three states should be enough.
Two problems: (1) we shouldn't parse the selector until we've really implemented it, not just for XForms (2) I think the interface is the wrong API for at least some of the pseudoclasses
OK, in more detail: * the following need to be implemented for HTML form controls: :default * the following need to be implemented for all elements (with special meaning for HTML form controls): :read-only, :read-write and it should work correctly when the document is loaded in the editor (or when contentEditable is used, if we implement it) This should be done without increasing the size of any HTML element objects.
Attachment #176728 - Flags: review?(dbaron) → review-
Attached patch Patch for non-xforms elements too (obsolete) (deleted) — Splinter Review
(In reply to comment #28) > OK, in more detail: > * the following need to be implemented for HTML form controls: > :default > * the following need to be implemented for all elements (with special meaning > for HTML form controls): > :read-only, :read-write This patch should do that, except for the :default submit button (see below). > and it should work correctly when the document is loaded in the editor (or > when contentEditable is used, if we implement it) As we talked about on irc, I'll ignore this for now. > This should be done without increasing the size of any HTML element objects. The patch only touches the parser, but to support :default for the default submit button I suggest that we extract the while loop in: http://lxr.mozilla.org/seamonkey/source/content/html/content/src/nsHTMLInputElement.cpp#930 into fx. GetDefaultSubmitControl(), expose it, and use it in the CSS parser. Or? (Naturally the BEAU_DBG* needs to go away before check in)
Attachment #176728 - Attachment is obsolete: true
Attachment #176729 - Attachment is obsolete: true
Attachment #179940 - Flags: review?(dbaron)
See also bug 84400 regarding :enabled and :disabled.
(In reply to comment #31) > See also bug 84400 regarding :enabled and :disabled. My eyes are wide open :), but there's not really a conclusion is there?
I took a look at the patch and have some comments: * This is lacking clear documentation. * It isn't clear to me how this applies to all elements. * It's unclear to me how this interacts at a JS level. How am I, from script, supposed to mark my <span> or <input> as being :required? * It isn't clear how bad states are handled. What if one of the values is set to an invalid value, like 64? (As opposed to -1, 0, 1). * I don't understand how this interface interacts with the theming interface (which it must). For example, if I set an element to checked, how does the theming interface ('appearance' property implementation) know to change to the relevant checked image? * It doesn't seem very efficient to be using 8 bits (or however much a short is) just to store what fits in 2 (there are at most four states for these pseudo-classes at the moment). This is especially important if these pseudos are relevant for all elements, which they should be. * This doesn't handle all the dynamic UI pseudos (in particular, some from CSS2.1 and Selectors are missing). We should be handling the following states, IMHO. Note that some of them have states that don't match any pseudo-classes yet. We should handle those because it is possible (maybe even likely) that CSS will support those in the future. These states apply to the element in all views at the same time: :default, not default, not applicable :valid, :invalid, not applicable :in-range, :out-of-range, not applicable :required, :optional, not applicable :read-only, :write-only, :read-write, not applicable :enabled, :disabled, not applicable :checked, unchecked, :indeterminate, not applicable selected, unselected, not applicable These states apply to the element differently in each view: :hover, not being hovered :active, non-active, not applicable open, closed, not applicable I'm not saying we need to implement all these right away. I'm just saying that we need to design this so that adding support for them would be mostly trivial.
er, s/:write-only/write-only/.
I was asked to clarify my previous comment. What I think should happen is every element should expose a scriptable interface that says whether the element matches certain states. The states should be mutable, so scripts and other parts of Mozilla should be able to say "you are now the default", "you are now enabled", "the required state no longer applies to you", etc. The pseudo-class code and the theming code would then use this interface to establish element states for selectors and appearance painting. interface UIStates { // for each group of attributes, only one returns true at any one time; // setting any one of a group to true resets the others to false, setting // one to false when it is true sets its opposite to true // :default attribute bool isDefaultApplicable; attribute bool isNotDefault; attribute bool isDefault; // :valid, :invalid attribute bool isValidApplicable; attribute bool isInvalid; attribute bool isValid; // ... } These attributes would be exposing some internal values (probably all kept as a bit mask somewhere -- since this would only be used on very few elements, its data would probably be hidden away in much the same way that DOMSlots is, maybe even in DOMSlots). All the states given above and plenty of room for expansion can be put into a 32 bit structure (2 bits per state). Then, the XForms, HTML forms, etc, code would simply use this interface to say "ok I'm now enabled/valid/out-of-range", and this would trigger the recascade, repainting, etc. Controls defined in XBL would be able to use this interface, since it is scriptable, to set what states their element should be in as well.
Attachment #179940 - Flags: review?(dbaron)
Attached patch Patch w/Hixies (approach) (obsolete) (deleted) — Splinter Review
Here's a go at it. Notes: * I've ignored the view-dependendent ones for now (:hover, etc.). * I also handle :default for HTML now (moved functionality from nsHTMLInputElement to nsIFormControl). But it does not correctly handle dynamics. I haven't looked at it, but something like inputs and buttons need to check if they are :default when added/removed, and inform new/old :default. * There's no support for :enabled/:disabled for HTML elements either. I could do a simple HasAttr("disabled") but that does not handle if parents set it. Add a function to nsIFormControl? What do you say Ian, is this what you meant? And what of the above needs to get in on this bug? (I have a patch for extensions/xforms too, but I cannot get to it from my current location :( )
Attachment #179940 - Attachment is obsolete: true
I can't really tell if this addresses dbaron's concerns or not. Does this data survive a stylesheet change? Can it be modified from script? (Does modifying it update the styles on the fly and so forth?)
(In reply to comment #37) > I can't really tell if this addresses dbaron's concerns or not. Does this data > survive a stylesheet change? Can it be modified from script? (Does modifying it > update the styles on the fly and so forth?) As we talked about on IRC, I've implemented something that is as non-intrusive as possible for existing elements. So (XForms, WebForms, etc) elements that need to support the pseudoclasses will just need to implement the nsICSSUIElement interface. As I understand it, your idea is that the interface is supported (and implemented) by _all (XML) elements in Mozilla_ (I did not understand "every element" in comment 35 as literally), probably through nsGenericElement.cpp. That (IMHO) is a greater task. I'll post the latest patch for my approach, and look at the all-inclusive concept. But is this the concept that you would like David?
Attached patch Approach 1 - core (obsolete) (deleted) — Splinter Review
Attachment #181162 - Attachment is obsolete: true
Attached patch Approach 1 - extensions/xforms (obsolete) (deleted) — Splinter Review
Attachment #179941 - Attachment is obsolete: true
Attached patch Approach 2 - core, patch 1 (obsolete) (deleted) — Splinter Review
Ok, here I go again. Now with something that, hopefully, is closer to what Hixie actually meant :) Implementation notes/questions: * I've temporarily put the interface in nsIContent. This is a problem, as it should be scriptable. But where should the interface be exposed? * There's still special handling of HTML button, input, option, and textarea in nsCSSStyleSheet. I would rather leave existing elements be for now. There should then probably be a flag that determines whether the nsCSSUIElement should be created or not -- or the specific controls should override the GenericElement-implementation. * Shouldn't it be possible to make the states readonly? It does not make much sense for the user to change the states on XForms controls. * Shouldn't it be possible for the content to be advised about state changes, or? F.x. if a user does |element.pseudoStates.isReadOnly| = 1 through script. * I think nsICSSUIElement needs a name-change. nsICSSPseudoClassState? Or?
Attached patch Approach 2 - extensions/xforms, patch 1 (obsolete) (deleted) — Splinter Review
(In reply to comment #42) > Created an attachment (id=181407) [edit] > Approach 2 - extensions/xforms, patch 1 There's a problem with this and the above testcase. My guess is that it's because the visual content of the f.x. xforms:input control is a html:input and that overrules the styling set on the xforms control.
Blocks: 292089
No longer blocks: 292089
Comment on attachment 181406 [details] [diff] [review] Approach 2 - core, patch 1 So, David... comments?
Attachment #181406 - Flags: review?(dbaron)
So I'm trying to understand the setup here... We have a scriptable interface, but the only getter for it is noscript... why is it scriptable? And I assume this is basically leaving mozilla-extension pseudo-classes out to be handled by some other mechanism? I'm sort of working on :-moz-broken and :-moz-blocked pseudo-classes for images, and I'm wondering a little as to how they'd fit into this scheme.
(In reply to comment #45) > So I'm trying to understand the setup here... > > We have a scriptable interface, but the only getter for it is noscript... why is > it scriptable? It's scriptable because Hixie wanted it. But, getting to it is not possible through script now. See comment 41. I need somewhere to expose it, and hoped for some feedback, which I have yet to receive. > And I assume this is basically leaving mozilla-extension pseudo-classes out to > be handled by some other mechanism? I'm sort of working on :-moz-broken and > :-moz-blocked pseudo-classes for images, and I'm wondering a little as to how > they'd fit into this scheme. I've tried to minimize what I'm handling, to ease the process .... it's not working, maybe I should just move to "solve the universe and everything" :) Mozilla-extension pseudo-classes could be included too I guess. Dunno, I do not know too much about them.
Ah, I see. Some comments on the patch, then. Not sure whether these affect the basic design... HasPseudoStates should just return a PRBool. No need for an out param. > aTextControlsFound++; really doesn't look like what you want to be doing. > + document->ContentStatesChanged(mContent, nsnull, NS_EVENT_STATE_UNSPECIFIED); That's wrong. It won't handle dynamic state changes correctly. Not that the code in nsCSSStyleSheet is checking the event state mask, but that's wrong too, for the same reasons. Let me know if this comment doesn't make sense and I'll try to write up an explanation; it's likely to be a little long.... This is why the ESM got mentioned earlier, and why I raised the question I did about how what I'm doing would mesh with this code. I'm not sure why the new pseudos are getting added to IsEventPseudo(). The things in IsEventPseudo are the ones we apply various quirks hacks to. For XForms this is probably a non-issue, but I think that :default for HTML <options> should work even in quirks mode.
yeah, you'd want isBroken and isBlocked flags for that. That would fit here very well, IMHO.
Why would we?
Comment on attachment 181406 [details] [diff] [review] Approach 2 - core, patch 1 This really shouldn't be hard to do without increasing the size of our core element classes. I'm not sure what the use case for scriptability is or why Ian is pushing for it, but what he has done is talk you into ignoring one of my original review comments. review-
Attachment #181406 - Flags: review?(dbaron) → review-
OK, maybe the new entry in nsDOMSlots isn't needed as often as I thought at first glance, but perhaps you should comment (in the code) on what conditions cause it to be created. I'm still not sure what the use case for scriptability is or how much complexity that's adding to the patch or whether this patch even meets that use case.
The use case for the scriptability is being able to make accessible custom widgets. That hasn't changed since the first time it was proposed all those many years ago. Are you saying we shouldn't do this? You don't seen to have commented on it at all, so it is unclear what your position is here. The elements would almost all be at their default values, it's only the few elements that actually end up needing to match these pseudos that would need to get the memory allocated here.
Actually, the patch increases by 4 bytes all elements with DOMSlots. That means anything that has: Had the childNodes getter called on it. Has inline style. Has has node.attributes accessed. Isn't XUL and is in an XBL binding. Is a XUL element with controllers. Granted, the first three of those cases already use a fair amount of memory on their own, which is why adding things to the DOMSlots is generally ok... If we want to avoid doing that, we could possibly use the property storage mechanism and use yet another bit from bits-or-slots to make it fast...
So does what this patch does actually meet that use case? I suspect it doesn't.
I have no idea, I haven't looked at the most recent patch (and my knowledge of internal Gecko things is definitely not enough for me to be able to tell whether something like this would work or not).
(In reply to comment #47) > HasPseudoStates should just return a PRBool. No need for an out param. The reason for that is that it should be scriptable at some time. > > aTextControlsFound++; > > really doesn't look like what you want to be doing. Well, I just expose existing code. > > + document->ContentStatesChanged(mContent, nsnull, NS_EVENT_STATE_UNSPECIFIED); > > That's wrong. It won't handle dynamic state changes correctly. Not that the > code in nsCSSStyleSheet is checking the event state mask, but that's wrong too, > for the same reasons. Let me know if this comment doesn't make sense and I'll > try to write up an explanation; it's likely to be a little long.... Got the explanation. I trashed the specific NS_EVENT_STATE-variables, which was a mistake. I'll include those again.
(In reply to comment #54) > So does what this patch does actually meet that use case? I suspect it doesn't. Well, it's not scriptable yet, so no :) But as I noted in comment 41, where should I expose it?
> The reason for that is that it should be scriptable at some time. Scriptable and moved off nsIContent? Or scriptable via some other interface and calling the nsIContent method internally? In the former case, leaving it this way might be ok (less changes to callers), but in the latter you really do want it to just return PRBool. > Well, I just expose existing code. Existing code counts the text controls by incrementing an integer when a text control is found. Your code increments a pointer when a text control is found and always reports 0 text controls. Not quite the same. Fwiw, regression-testing on the testcases that form code was written to fix is a good idea once this patch gets close enough to landing.
(In reply to comment #58) > > Well, I just expose existing code. > > Existing code counts the text controls by incrementing an integer when a text > control is found. Your code increments a pointer when a text control is found > and always reports 0 text controls. Doh! Stupid me.
Depends on: 296309
Depends on: 297061
Attached patch Patch that uses IntrinsicState() (obsolete) (deleted) — Splinter Review
Here's a patch that implements :enabled/:disabled, :read-only/:read-write, and :default for the standard HTML form controls using IntrinsicState(). :enabled/:disabled just checks the attribute disabled, should I check focusable instead? (bug 84400) The only tricky part is handling :default for submit buttons. I've added mDefaultSubmitElement in nsHTMLFormElement, which is being maintained on add, remove and type changes for buttons and inputs. I've added two functions to nsIForm to get the default submit element and reset it (ie. traverse the form elements and find the default). nsHTMLInputElement::MaybeSubmitForm() is changed too, so that it uses mDefaultSubmitElement.
Attachment #181283 - Attachment is obsolete: true
Attachment #181285 - Attachment is obsolete: true
Attachment #181406 - Attachment is obsolete: true
Attachment #181407 - Attachment is obsolete: true
Attachment #185943 - Flags: review?(bzbarsky)
Attached file Testcase for :default (deleted) —
Attached file Testcase for :read-only/:read-write (deleted) —
It'll take me a few days to get to this, Allan... Also, if I don't manage to do it by the 19th, I won't be able to until July.
ccing content owners in case they have thoughts about some of the review comments coming up.
Comment on attachment 185943 [details] [diff] [review] Patch that uses IntrinsicState() >Index: layout/style/nsCSSStyleSheet.cpp >@@ -3120,16 +3120,49 @@ static PRBool SelectorMatches(RuleProces >+ else if (nsCSSPseudoClasses::defaultPseudo == pseudoClass->mAtom) { It might be a good idea to order the checks here such that the pseudos we expect to see most often are first. > PRBool IsStateSelector(nsCSSSelector& aSelector) Same in this method. I'm pretty sure :hover should come before :optional, say. >Index: content/html/content/src/nsGenericHTMLElement.h >+ virtual PRInt32 IntrinsicState() const; There's state common to all HTML but not other document languages? >+ * Called when an attribute has just been changed This needs a lot more documentation (eg, what does a null aValue mean)? >Index: content/html/content/src/nsGenericHTMLElement.cpp >+nsGenericHTMLElement::IntrinsicState() const >+ // Every HTML element is read only per default Isn't this generally true for non-HTML? And can't having an XBL binding on HTML affect this? Etc, etc. That is, shouldn't this just live in nsGenericElement or even in the default state returned by nsIContent? >+nsGenericHTMLFormElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ PRBool aNotify) >+ // SetAttr() removes and adds the control when @type is set, so we only need What's @type? >+ if (mForm && aName == nsHTMLAtoms::type) { Shouldn't this check that aNameSpaceID == None? >+ mForm->ResetDefaultSubmitElement(); This looks wrong; it'll notify even when aNotify is false. >+nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ const nsAString* aValue, PRBool aNotify) >+{ >+ if (aName == nsHTMLAtoms::disabled) { Check namespace, please. >Index: content/html/content/src/nsHTMLFormElement.cpp >+ /** The default submit element -- WEAK */ >+ nsIFormControl* mDefaultSubmitElement; How do we clear this pointer if mDefaultSubmitElement dies? That is, who's responsible for maintaining this pointer in a sane way? More to the point, is there a reason not to make this a strong pointer? Do form controls hold strong pointers to the form? >@@ -1195,16 +1201,39 @@ nsHTMLFormElement::AddElement(nsIFormCon >+ } else if (CompareFormControlPosition(aChild, mDefaultSubmitElement) < 0) { >+ // New element is positioned before the current default Do we really want to be doing this during parsing? What's preventing that from happening here? > nsHTMLFormElement::RemoveElement(nsIFormControl* aChild) >+ if (aChild == mDefaultSubmitElement) { >+ // We are removing the default submit, find the new default >+ rv = ResetDefaultSubmitElement(); Again, won't this always notify, even if the remove had aNotify false? That looks wrong. >Index: content/html/content/src/nsHTMLInputElement.cpp >+ if (aName == nsHTMLAtoms::readonly) { Namespace id! Also, readonly only applies to text inputs, no? We don't want <input type="checkbox" readonly="readonly"> to match :readonly, I don't think. Which means we need to check the type here and possible notify a content state change when the type attr changes... > nsHTMLInputElement::IntrinsicState() const >+ // default checked element <input type="text" checked="checked"> might not want to match :default... Need a type check here. Also, for multiple radios all in the same group that have a checked attribute, it's not clear what should happen (should they all match :default, or only the ones that actually end up checked by default?). >+ // Nasty hack because we need to call an interface method, and one that >+ // toggles some of our hidden internal state at that! Does GetDefaultChecked really toggle internal state? I don't see where... |mutable| wouldn't help here, therefore. >+ // :read-only/:read-write >+ PRBool roState; >+ // Same nasty hack as above >+ NS_CONST_CAST(nsHTMLInputElement*, this)->GetReadOnly(&roState); Again, this doesn't apply to all inputs, so this code is wrong. >Index: content/html/content/src/nsHTMLOptionElement.cpp >+ // Same nasty hack as above >+ NS_CONST_CAST(nsHTMLOptionElement*, this)->GetDefaultSelected(&selected); GetDefaultSelected doesn't change any internal state.... >Index: content/html/content/src/nsHTMLTextAreaElement.cpp >+ virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ nsIAtom* aPrefix, const nsAString& aValue, >+ PRBool aNotify) >+ { >+ nsresult rv = nsGenericHTMLFormElement::SetAttr(aNameSpaceID, aName, >+ aPrefix, aValue, aNotify); >+ >+ AfterSetAttr(aNameSpaceID, aName, &aValue, aNotify); This will call AfterSetAttr twice (once in nsGenericHTMLFormElement::SetAttr and once here), no? Other subclasses of nsHTMLFormElement have the same problem, I think. We should only be calling that once. Given the changes you're making, I suspect that once should be in the superclass and the subclass AfterSetAttr methods need to call the superclass's method. >+ virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, Same issue here. >+ /** >+ * Called when an attribute has just been changed >+ */ >+ void AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ const nsAString* aValue, PRBool aNotify); That's virtual, right (given that the superclass's is)? >+nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ if (aName == nsHTMLAtoms::readonly) { >+ nsIDocument* document = GetCurrentDoc(); >+ if (document) { >+ mozAutoDocUpdate(document, UPDATE_CONTENT_STATE, PR_TRUE); >+ document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_READONLY | >+ NS_EVENT_STATE_READWRITE); This always notifies. That's not desirable. >+nsHTMLTextAreaElement::IntrinsicState() const >+{ >+ // :checked Huh? >+ // Nasty hack because we need to call an interface method, and one that >+ // toggles some of our hidden internal state at that! Would that we could >+ // use |mutable|. GetReadOnly doesn't change internal state. Perhaps we should have non-COM versions of all these methods for internal use... >Index: content/html/content/public/nsIForm.h >+ * Get the default submit element Can return null, right? >+ NS_IMETHOD GetDefaultSubmitElement(nsIFormControl** aElement) const = 0; Why not just have this return the nsIFormControl*? For that matter, would using nsIContent* here make more sense? You always seem to QI the result to nsIContent... Given the size of the patch and the complexity of getting some of the form controls stuff right, it might be worthwhile to break this up into several patches, but it's your call.
Attachment #185943 - Flags: review?(bzbarsky) → review-
Attached patch With Boris' comments fixed (obsolete) (deleted) — Splinter Review
(In reply to comment #65) > (From update of attachment 185943 [details] [diff] [review] [edit]) > >Index: layout/style/nsCSSStyleSheet.cpp > >@@ -3120,16 +3120,49 @@ static PRBool SelectorMatches(RuleProces > > >+ else if (nsCSSPseudoClasses::defaultPseudo == pseudoClass->mAtom) { > > It might be a good idea to order the checks here such that the pseudos we > expect to see most often are first. Good point, but I might need some help in determining the optimal order. > > PRBool IsStateSelector(nsCSSSelector& aSelector) > > Same in this method. I'm pretty sure :hover should come before :optional, say. Yes. I've put the new ones in the bottom for a start. > >Index: content/html/content/src/nsGenericHTMLElement.h > > >+ virtual PRInt32 IntrinsicState() const; > > There's state common to all HTML but not other document languages? Argh, yeah, I did not re-read all the comments on the bug, thought I could remember what David had written... that was obviously wrong (comment 28). > >+ * Called when an attribute has just been changed > > This needs a lot more documentation (eg, what does a null aValue mean)? Lousy excuse: I just copied it from nsHTMLInputElement.cpp. I'll add dox. > >Index: content/html/content/src/nsGenericHTMLElement.cpp > > >+nsGenericHTMLElement::IntrinsicState() const > > >+ // Every HTML element is read only per default > > Isn't this generally true for non-HTML? And can't having an XBL binding on > HTML affect this? Etc, etc. That is, shouldn't this just live in > nsGenericElement or even in the default state returned by nsIContent? I guess the default state could be READONLY instead of 0. But XUL should probably implement IntrinsicState() too then, but that should really be a separate bug then (at least because I'm no XUL-guru). > >+nsGenericHTMLFormElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, > >+ PRBool aNotify) > > >+ // SetAttr() removes and adds the control when @type is set, so we only need > > What's @type? Attribute |type|, XPath, sorry. > >+ if (mForm && aName == nsHTMLAtoms::type) { > > Shouldn't this check that aNameSpaceID == None? Yes, all the functions should check the namespace. I'll fix that. > >Index: content/html/content/src/nsHTMLFormElement.cpp > > >+ /** The default submit element -- WEAK */ > >+ nsIFormControl* mDefaultSubmitElement; > > How do we clear this pointer if mDefaultSubmitElement dies? That is, who's > responsible for maintaining this pointer in a sane way? The form control is responsible for adding and removing itself from the form, and I check for the removal in RemoveElement(), so it should always be valid. That's why I chose the weak pointer. > More to the point, is there a reason not to make this a strong pointer? Hmmm, probably not, but I'm not exactly "Mr. content/" :-) > Do form controls hold strong pointers to the form? No form controls have a weak pointer to the form. > >@@ -1195,16 +1201,39 @@ nsHTMLFormElement::AddElement(nsIFormCon > > >+ } else if (CompareFormControlPosition(aChild, mDefaultSubmitElement) < 0) { > >+ // New element is positioned before the current default > > Do we really want to be doing this during parsing? What's preventing that from > happening here? I thought about the same, but obviously forgot to handle it :( I guess parsing inserts elements in document order, so I just (re)use the check for whether it's being inserted in the end of the form. > >Index: content/html/content/src/nsHTMLInputElement.cpp > > >+ if (aName == nsHTMLAtoms::readonly) { > > Namespace id! It's checked at the entry to the function, but I missed checking the namespace other places ... I'll add it there. > Also, readonly only applies to text inputs, no? We don't want <input > type="checkbox" readonly="readonly"> to match :readonly, I don't think. Which > means we need to check the type here and possible notify a content state change > when the type attr changes... I agree. I'll add the type checks. The type change should work without changes, as form elements are removed and re-added to the form when they change type. > Also, for multiple radios all in the same group that have a checked attribute, > it's not clear what should happen (should they all match :default, or only the > ones that actually end up checked by default?). Heh, that's a good one. I would say it only match the one that actually ends up getting checked. > >Index: content/html/content/public/nsIForm.h > > >+ * Get the default submit element > > Can return null, right? Yes, add a note about that you mean? > >+ NS_IMETHOD GetDefaultSubmitElement(nsIFormControl** aElement) const = 0; > > Why not just have this return the nsIFormControl*? Well, I could, but all other functions in the interface obey the XPCOM interface rules. > For that matter, would using nsIContent* here make more sense? You always seem > to QI the result to nsIContent... The only place I QI to nsIContent is in nsHTMLInputElement::MaybeSubmitForm(), all other places use nsIFormControl. > Given the size of the patch and the complexity of getting some of the form > controls stuff right, it might be worthwhile to break this up into several > patches, but it's your call. Let's take one more round... then I may split it. Here's a summary of the changes in this patch: * added namespace checks when I look at attributes * ResetDefaultSubmitElement() now takes an aNotify parameter. * added control type checks in nsHTMLInputElement * implemented BeforeSetAttr() and AfterSetAttr() as virtuals in nsGenericHTMLFormElement (funtionality taken from nsHTMLInputElement). * made all elements (nsIContent) match :read-only per default. Open issues: * multiple checked="checked" on radio controls all match :default, I guess only the one "true" default should match? * SetForm() sends notifications all the time now... when should it actually send them? * optimal ordering of if-statements in nsCSSStyleSheet.cpp * make all elements (nsIContent) match :read-only per default.
Attachment #185943 - Attachment is obsolete: true
Attachment #187107 - Flags: review?(bzbarsky)
Allan - is this patch the latest work that needs review, or do you have anything newer in your trees?
(In reply to comment #67) > Allan - is this patch the latest work that needs review, or do you have anything > newer in your trees? Attachment 187107 [details] [diff] is the newest.
Comment on attachment 187107 [details] [diff] [review] With Boris' comments fixed >Index: content/base/public/nsIContent.h > virtual PRInt32 IntrinsicState() const > { >- return 0; >+ // All elements are read only per default >+ return NS_EVENT_STATE_READONLY; So... I've been thinking about this more, and we have a slight problem here. For example, in an editable document, this default should be READWRITE, I would think. And I would think that we'd want XUL text inputs to match readwrite/readonly accordingly; I don't see how this patch manages that. >Index: content/html/content/src/nsGenericHTMLElement.cpp >@@ -3152,17 +3152,18 @@ nsGenericHTMLFormElement::SetForm(nsIDOM >+ // XXX (when) should SetForm() send notifications? >+ mForm->RemoveElement(this, PR_TRUE); Please sort this out (look at the callers of SetForm and figure out what they're doing, etc). Notifying unnecessarily would be a major perf issue (eg would force flushing out the content sink for no reason from the callsite at <http://lxr.mozilla.org/seamonkey/source/content/html/document/src/nsHTMLConten tSink.cpp#842>; that same callsite could also leave to broken behavior on the part of the content sink). It's entirely possible that SetForm() needs an aNotify argument of its own. > nsGenericHTMLFormElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* Fwiw, a -w diff in addition to a normal one would have helped a lot here... :( >+nsGenericHTMLFormElement:: BeforeSetAttr(PRInt32 aNameSpaceID, What's with that extra space? >+{ >+} And why does this method exist? If it's only used by subclasses, then perhaps only they should declare it? >+nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ const nsAString* aValue, >+ mozAutoDocUpdate(document, UPDATE_CONTENT_STATE, aNotify); >+ document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_DISABLED | Why is this notifying when aNotify is false? >Index: content/html/content/src/nsHTMLFormElement.cpp >+ NS_IMETHOD GetDefaultSubmitElement(nsIFormControl** aElement) const; Again, I'd like this to be an NS_IMETHOD_(nsIFormControl*). There's no reason for the refcounting here. I just checked with jst, and he agrees on this. @@ -1195,50 +1203,137 @@ nsHTMLFormElement::AddElement(nsIFormCon >+ mozAutoDocUpdate(document, UPDATE_CONTENT_STATE, PR_TRUE); Ouch. This will notify in the middle of sink notifications. It'll also notify in the middle of attr changes that have aNotify set to false. Please fix this to only notify when it should, ok? Note that notifying in the middle of sink notifications may well be ok here -- we at least want to notify that oldElement is not the default anymore, since it might have a frame. But I really don't think we want to be doing this if aNotify is false on an attr change... >+ NS_ASSERTION(oldElement && newElement, >+ "Form control not implementing nsIContent?!\n"); No need for the \n. >+nsHTMLFormElement::ResetDefaultSubmitElement(PRBool aNotify) >+ if (type == NS_FORM_INPUT_SUBMIT || >+ type == NS_FORM_BUTTON_SUBMIT || >+ type == NS_FORM_INPUT_IMAGE) { Maybe we should have an nsIFormControl function that does this? followup bug, perhaps? >+ // Inform about change Even if aNotify is false? That can't be right... >+ if (oldDefault || mDefaultSubmitElement) { >+ nsIDocument* document = GetCurrentDoc(); >+ if (document) { I really wish we could avoid notifying here for cases when the default control is being removed from the document altogether (since in that case the fact that its state changed really doesn't matter)... But I bet we get into here before oldDefault's document is nulled out in that case, right? >+ nsCOMPtr<nsIContent> newElement(do_QueryInterface(mDefaultSubmitElement)); >+ NS_ASSERTION(oldElement && newElement, >+ "Form control not implementing nsIContent?!\n"); Why can't newElement be null here? I don't think you can make this assertion.... >+nsHTMLFormElement::GetDefaultSubmitElement(nsIFormControl** aElement) const >+{ >+ NS_ENSURE_ARG(aElement); For future reference, don't null-check out params, please. >Index: content/html/content/src/nsHTMLInputElement.cpp > nsHTMLInputElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, > const nsAString* aValue, > PRBool aNotify) > { >+ nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName, > nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, > const nsAString* aValue, > PRBool aNotify) > { >+ nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify); Should we perhaps call the superclass AfterSetAttr after our own? Or does it not matter? Perhaps the function decl in the superclass should document what assumptions are made about call order, if any? >@@ -536,16 +510,29 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 >+ document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_READONLY | >+ NS_EVENT_STATE_READWRITE); Even if aNotify is false? >@@ -2462,20 +2446,69 @@ nsHTMLInputElement::DoneCreatingElement( > nsHTMLInputElement::IntrinsicState() const >+ if (mForm && >+ (mType == NS_FORM_INPUT_SUBMIT || >+ mType == NS_FORM_INPUT_IMAGE)) { This should be in an else, no? If we already hit the first if and it tested true, this one is guaranteed to test false. >+ if (defControl && defControl == this) { No need for defControl null-check here. I'm not seeing any provisions for toggling the :default state for radio/checkbox when the relevant attr changes... >Index: content/html/content/src/nsHTMLOptionElement.cpp I don't see any provisions for toggling the :default state when the "selected" attr changes. This is where those testcases I talked about would come in useful... >Index: content/html/content/src/nsHTMLTextAreaElement.cpp >+nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, >+ document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_READONLY | >+ NS_EVENT_STATE_READWRITE); Event if aNotify is false? I really think this would work best split up into several patches, with some QA involvement to test each patch thoroughly if we're going to take this for 1.8 at this late stage...
Attachment #187107 - Flags: review?(bzbarsky) → review-
Web Forms 2 defines that :default should only match the submit button that will be used when the user presses enter. Web Forms 2 does not define it for other elements and does not intend to. I think we should follow Web Forms 2 here.
Keywords: css3
(In reply to comment #70) > Web Forms 2 defines that :default should only match the submit button that will > be used when the user presses enter. Web Forms 2 does not define it for other > elements and does not intend to. I think we should follow Web Forms 2 here. Well, it certainly makes my life a lot easier.
(In reply to comment #69) > I really think this would work best split up into several patches, with some QA > involvement to test each patch thoroughly if we're going to take this for 1.8 > at this late stage... I'll split the patch.
Depends on: 302186
Depends on: 302188
Comment on attachment 187107 [details] [diff] [review] With Boris' comments fixed Development will continue on seperate bugs now: bug 84400, bug 302186, and bug 302188
Attachment #187107 - Attachment is obsolete: true
> I think we should follow Web Forms 2 here. CSS3 UI pretty clearly defines default to match the default option in a <select>, and default radio in a radio group. Per the Web Forms 2 description of <input type="checkbox">, it also defines it to match a <input type="checkbox" checked="checked">. So luckily, we can follow both Web Forms 2 and CSS3 UI here, since they don't actually conflict!
So regarding valid/invalid and in-range/out-of-range Those don't really work with regular html forms, since there is no way for an html form currently in Mozilla to specify validity. Web Forms does, but we don't support that right now. So should we just have valid/in-range always be true and invalid/out-of-range false for HTML elements? And leave an XXX: for whoever implements Web Forms in the future?
Yes, that's what we should do.
(In reply to comment #75) > So should we just have valid/in-range always be true and invalid/out-of-range > false for HTML elements? And leave an XXX: for whoever implements Web Forms in > the future? I think neither should match HTML form elements unless we implement some notion of validity or being within range.
We do support the MAXLENGTH attribute, but it might not be worth it to support :valid, :invalid just for that.
Depends on: 302462
Depends on: 302608
No longer depends on: 302186
Depends on: 302186
No longer depends on: 302186
Allan, should this bug depend on https://bugzilla.mozilla.org/show_bug.cgi?id=302186 ?
Depends on: 302186
(In reply to comment #80) > Allan, should this bug depend on > https://bugzilla.mozilla.org/show_bug.cgi?id=302186 ? No, so please stop adding it as a dependency... XForms does not use :default for anything.
No longer depends on: 302186
Attached patch Patch for extensions/xforms (deleted) — Splinter Review
Attachment #199833 - Flags: review?(doronr)
Attachment #199833 - Flags: review?(doronr) → review+
Attachment #199833 - Flags: review?(aaronr)
Attachment #199833 - Flags: review?(aaronr) → review+
looks like this patch may have missed the attribute stuff in nsXFormsControlStubBase::ResetBoundNode. Javier is also going to use the "disabled" attribute with his upload control implementation. So if that patch goes in before this patch does, please keep that in mind.
Depends on: 312971
Comment on attachment 199833 [details] [diff] [review] Patch for extensions/xforms Checked in to trunk
Comment on attachment 199833 [details] [diff] [review] Patch for extensions/xforms Requestions a for 1.8rc1, as this is xforms only.
Attachment #199833 - Flags: approval1.8rc1?
Attachment #199833 - Flags: approval1.8rc1? → approval1.8rc1+
Checked in on 1.8 branch. Created bug 313111 for the proper :read-only/:read-write support.
Status: ASSIGNED → RESOLVED
Closed: 19 years ago
No longer depends on: 312971
Keywords: fixed1.8
Resolution: --- → FIXED
Summary: Implement CSS pseudoclasses needed for XForms → Use pseudoclasses instead of attributes
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: