Prev: FYI: Douglas Crockford: Loopage
Next: Getting there....
From: Richard Cornford on 11 Aug 2010 08:39 On Aug 11, 4:30 am, Denis McMahon wrote: > On 10/08/10 21:57, Evertjan. wrote: > >> Denis McMahon wrote on 10 aug 2010 in comp.lang.javascript: > >>> At the moment I use named elements, and group the elements by giving >>> them a common name, but this feels "wrong". For example: > >>> function vis(name, state) >>> { >>> var els = document.getElementsByName(name); >>> for (var el in els) els[el].style.visible = state; >>> } > >>> Has anyone got a "better" way to do this sort of thing? >> class > > Yes, nice answer, but how do you refer to a class to change it's > style rule? > > If I have to trawl through > document.styleSheets[*].cssRules|rules[*].selectorText looking for > any / every rule that matches my class to set the style element, > that's not really "better". You don't necessarily have to do that. Remember that when rules have equal specificity the last rule overrides all previous ones. So just adding a rule for a class at the end of the last (appropriate media (i.e. probably not 'print' style sheets, etc.)) style sheet overrides all previous equivalent rules for that class in that and all preceding style sheets. Richard.
From: Gregor Kofler on 11 Aug 2010 08:40 Am 2010-08-11 12:49, williamc meinte: >> (untested) >> function gEBCN(cN) { >> var els = document.getElementsByTagName("*"); >> var result = []; >> var l = els.length; >> >> while(l--) { >> if(els[l].className == cN) { >> results.push(els[l]); >> } >> } >> return result; >> } >> >> The main difference: the "native" gEBCN() will return a live collection, >> the custom version a snapshot. >> >>> If I have to trawl through >>> document.styleSheets[*].cssRules|rules[*].selectorText looking for any / >>> every rule that matches my class to set the style element, that's not >>> really "better". >> >> Obviously not. >> >> Gregor > > I was going to post this question myself (i.e. what's the best getEBCN > function?)... > > Good point about the difference between the native implementation > returning a (live) node list vs. just a snapshot. > > Any solution must work with multiple values, though, e.g. class="foo > bar" and I don't see how the function above will do that. As below: Either with a RegExp or you could split() the className and use Array.indexOf() (again not supported in some browsers) on the resulting array. > Crockford suggested this (calling his recursive walkTheDom function)... > > function getElemsByClassName2(className) { > if (document.getElementsByClassName) { > return(elem.getElementsByClassName(className)); > } else { > var results = []; > walkTheDOM(document.body, function (node) { > var a, c = node.className, i; > if (c) { > a = c.split(' '); > for (i = 0; i< a.length; i += 1) { > if (a[i] === className) { > results.push(node); > break; > } > } > } > }); > return results; > } > } Well, one could benchmark that, but since it is a fallback, I don't care too much about speed (though the fallback will be used by the slowest browsers, Internet Explorer 6 to 8). > I saw a very long "ultimate" version somewhere (Robert Nyman?). I'd be > interested to see what people use in their own work. element.gEBCN() (transfered into a "static" array), document.evaluate(), filtered element.gEBTN(). Gregor -- http://vxjs.gregorkofler.com
From: Denis McMahon on 11 Aug 2010 10:14 On 11/08/10 10:54, Gregor Kofler wrote: > Am 2010-08-11 05:30, schrieb Denis McMahon: >> On 10/08/10 21:57, Evertjan. wrote: >>> Denis McMahon wrote on 10 aug 2010 in comp.lang.javascript: >>> >>>> At the moment I use named elements, and group the elements by giving >>>> them a common name, but this feels "wrong". For example: >>>> >>>> function vis(name, state) >>>> { >>>> var els = document.getElementsByName(name); >>>> for (var el in els) els[el].style.visible = state; >>>> } > > This rather works by coincidence, since el will become any property of > your els collection - and quite a few of these properties won't have a > style property. (And most DOM elements don't have a name property.) > > A working approach: > > var l = els.length; > while(l--) { > els[l].style.visibility = state; > } Good catch, I usually use: for (var i = 0; i < els.length; i++) els[i].style.visible = state; Don't know why I wrote it with a for / in really. > element.getElementsByClassName(cName) in recent enough browsers will > give you all elements with the according class. Rest of the solution > looks exactly like the one above. > If getElementsByClassName() is not available, a simple function will do > the job: > > (untested) > function gEBCN(cN) { > var els = document.getElementsByTagName("*"); > var result = []; > var l = els.length; > > while(l--) { > if(els[l].className == cN) { > results.push(els[l]); > } > } > return result; > } > > The main difference: the "native" gEBCN() will return a live collection, > the custom version a snapshot. That's really the same as my current solution, but using class as n identifier instead of name, which is marginally better, but I was hoping for a means of setting the class style, rather than the element style of each element in the class. >> If I have to trawl through >> document.styleSheets[*].cssRules|rules[*].selectorText looking for any / >> every rule that matches my class to set the style element, that's not >> really "better". > > Obviously not. Indeed, but (unfortunately) I'm not convinced that any solution that has me trawling through any collection of elements is really significantly better (more efficient, more elegant) than the current solution. I came up with this, which will work on (a) style rule(s) based on the class in the selector. The method of finding the style rule(s) to change doesn't strike me as great, but I can't see an obviously better one: function changeClassStyles(theClass, theProp, theVal) { if (theClass.charAt(0) != ".") theClass = "." + theClass; var ss = document.styleSheets; for (var ssnm = 0; ssnm < ss.length; ssnm ++) { if (ss[ssnm].cssRules) // non ie { var rls = ss[ssnm].cssRules; } else if (ss[ssnm].rules) // ie { var rls = ss[ssnm].rules; } if (rls) { for (var rlnm = 0; rlnm < rls.length; rlnm ++) { var rl = rls[rlnm]; var select = rl.selectorText; /* // for complex eg. 'ele.class:pseudo' selectors and // simple ie. '.class' selectors var classre = /\.[a-z0-9]/gi; var clss = select.match(classre); for (var clsnm = 0; clsnm < clss.length; clsnm ++) { if (theClass == clss[clsnm]) { eval("rl.style." + theProp + " = theVal"); } } */ ///* // for simple ie. '.class' selectors if (theClass == select) { eval("rl.style." + theProp + " = theVal"); } //*/ } } } } What I'd really like is: document.classes[classname].style.property = value but I can see that classes aren't a valid collection of themselves, rather they represent a one-or-many to one-or-many link between elements and styles. I think any dom representation of an html class attribute or css class selector would need a collection of rules and a collection of elements, to maintain the mapping. A class would be added to document.classes either (a) when a style rule selector first referenced it or (b) when an element class attribute first referenced it, with the style rule or element being added to it's appropriate member collection. Subsequent style rules or elements that featured the class would also be added to the collection. Maybe: var l = document.classes[classname].rules.length; while (l--) { eval ("document.classes[classname].rules[l]." + theProp + " = theVal"); } or even better, using a construct like: document.classes[classname].rules[l].properties[theProp] = theVal; (Yes, I know style rules don't have a properties collection either, I just think it would be nice if they did.) Rgds Denis
From: Denis McMahon on 11 Aug 2010 10:18 On 11/08/10 13:39, Richard Cornford wrote: > You don't necessarily have to do that. Remember that when rules have > equal specificity the last rule overrides all previous ones. So just > adding a rule for a class at the end of the last (appropriate media > (i.e. probably not 'print' style sheets, etc.)) style sheet overrides > all previous equivalent rules for that class in that and all preceding > style sheets. Ooh, nice, hadn't thought of that approach. Rgds Denis McMahon
From: Thomas 'PointedEars' Lahn on 11 Aug 2010 18:24 Denis McMahon wrote: > function changeClassStyles(theClass, theProp, theVal) > { > if (theClass.charAt(0) != ".") theClass = "." + theClass; > var ss = document.styleSheets; > for (var ssnm = 0; ssnm < ss.length; ssnm ++) for (var ssnm = 0, len = ss.length; ssnm < len; ++ssnm) is more efficient. You might even want to consider for (var ssnm = ss.length; ssnm--;) or, as Gregor suggested, var ssnm = ss.length; while (ssnm--) instead. > { > if (ss[ssnm].cssRules) // non ie > { > var rls = ss[ssnm].cssRules; > } > else if (ss[ssnm].rules) // ie You should use multi-line pre-comments instead of single-line post-comments, and the comments should contain at least "W3C DOM" and "MSHTML DOM". IE or not IE ─ that is _not_ the question. > { > var rls = ss[ssnm].rules; > } Since the /IfStatement/ type-converts its condition to boolean, it is easier to maintain and not more error-prone to write var o = ss[ssnm], rls = o.cssRules || o.rules; instead. > if (rls) > { > for (var rlnm = 0; rlnm < rls.length; rlnm ++) See above for the optimization. And it makes no sense to me to insert whitespace between a *unary* operator and its operand, even if the grammar allows it. > { > var rl = rls[rlnm]; > var select = rl.selectorText; > /* > // for complex eg. 'ele.class:pseudo' selectors and > // simple ie. '.class' selectors > var classre = /\.[a-z0-9]/gi; That is hardly sufficient. Check the CSS (2.1) grammar. > var clss = select.match(classre); > for (var clsnm = 0; clsnm < clss.length; clsnm ++) > { > if (theClass == clss[clsnm]) > { > eval("rl.style." + theProp + " = theVal"); Ouch. Please read the FAQ about eval(), and from then on use only this syntax: rl.style[theProp] = theVal; Note that the `style' property is not required to be implemented per W3C DOM Level 2 Style CSS here. Use .getPropertyValue() as fallback. > [...] > What I'd really like is: > > document.classes[classname].style.property = value No, you won't. Do not augment host objects, such as the one that `document' refers to. (Doing otherwise is an clear indicator of the cluelessness of a library author.) > but I can see that classes aren't a valid collection of themselves, > rather they represent a one-or-many to one-or-many link between elements > and styles. ISTM rather easy to read all stylesheet selectors into a mapping object on load. I have started writing an object type to that effect, but the query method (findSimpleSelector) is not ready yet: <http://pointedears.de/websvn/filedetails.php?repname=JSX&path=%2Ftrunk%2Fcss- commented.js> > [...] > eval ("document.classes[classname].rules[l]." + theProp + " = theVal"); > [...] You are not ready for this yet. PointedEars -- realism: HTML 4.01 Strict evangelism: XHTML 1.0 Strict madness: XHTML 1.1 as application/xhtml+xml -- Bjoern Hoehrmann
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 5 Prev: FYI: Douglas Crockford: Loopage Next: Getting there.... |