This would be an ideal use case for XPath.
On Mar 5, 10:35 am, Walter Lee Davis <[email protected]> wrote: > Thanks, yes that might work. But I am trying to write something which > is structure-agnostic, since it goes in a plug-in for a Web design > application, and I have no idea how people will want to use it. Alex's > suggestion allows me to do the very least (and therefore resist the > urge to screw up) while still offering an unsurprising result in a > wide range of layout situations. > > Walter > > On Mar 5, 2010, at 8:08 AM, Eric wrote: > > > > > Hi, > > > All the proposed solutions are very nice example of coding, but > > however you may ask yourself this question: > > "If there is no easy way to do the processing I want with my data > > structure, am I sure I am using the right data structure?" > > > In other words, instead of coding heavy processing functions couldn't > > you just change your DOM structure to optimize whatever processing you > > need to do with them. > > > In your case, adding a DIV around each "H3-P-P-P..." sequence would do > > the trick. > > > Alex: Very nice implementation! > > > Eric > > > On Feb 23, 6:20 pm, Walter Lee Davis <[email protected]> wrote: > >> Wow, thanks very much Alex! > > >> Walter > > >> On Feb 23, 2010, at 11:28 AM, Alex Wallace wrote: > > >>> Here's a slightly better version, as it crawls the tree itself > >>> instead of grabbing and filtering all of the element's > >>> nextSiblings(). Since it avoids the call to recursivelyCollect() > >>> it's a bit faster (with 10 siblings after the requested node, it's > >>> about 20% faster - when I upped it to about 40 elements after the > >>> node, it ran well over 250% faster). If you have a lot of nodes to > >>> filter for the accordion, I'd definitely use this version. > > >>> function fasterSameTagSiblings(element) { > >>> element = $(element); > >>> var results = [], node = element.nextSibling, tag; > >>> while (node = node.nextSibling) { > >>> if (node.nodeType === 1) { > >>> tag = tag || node.tagName.toLowerCase(); > >>> if (node.tagName.toLowerCase() === tag) > >>> results.push(node) > >>> else > >>> break; > >>> } > >>> } > >>> return results; > >>> } > > >>> Cheers, > >>> Alex > > >>> Micro-optimization for sure, but it was bugging me. :) > > >>> function fasterSameTagSiblings(element) { > >>> element = $(element); > >>> var results = [], node = element.nextSibling, tag; > >>> while (node = node.nextSibling) { > >>> if (node.nodeType === 1) { > >>> tag = tag || node.tagName.toLowerCase(); > >>> if (node.tagName.toLowerCase() === tag) > >>> results.push(node) > >>> else > >>> break; > >>> } > >>> } > >>> return results; > >>> } > > >>> On Mon, Feb 22, 2010 at 8:24 PM, Walter Lee Davis > >>> <[email protected]> wrote: > >>> The heads and the paragraphs are all at the same level, and I don't > >>> want all the paragraphs, just the ones between "this" head and the > >>> next head. (It's for an accordion effect.) So while > >>> up('div').select('p') would do exactly what you say, it would leave > >>> me where I started. > > >>> Thanks, > > >>> Walter > > >>> On Feb 22, 2010, at 5:46 PM, Matt Foster wrote: > > >>> This is probably too obvious to be right but if you're simply > >>> looking > >>> for all of the paragraph tags at that level could you simply go up > >>> to > >>> the parent and select down from there? > > >>> On Feb 22, 12:57 pm, Paul Kim <[email protected]> wrote: > >>> Hi Alex, thanks for the tip. I've modified the function based on > >>> your tip > >>> and your example function: > > >>> function consecutiveSameTagSiblings(element) { > >>> var element = $(element); > >>> var nextSiblings = element.nextSiblings(); > >>> var similarElements = []; > >>> similarElements.push(element); > >>> for (var i=0; i< nextSiblings.length; i++) { > >>> if (element.tagName == nextSiblings[i].tagName) { > >>> similarElements.push(nextSiblings[i]); > >>> } > >>> else { > >>> break; > >>> } > >>> } > >>> return similarElements; > >>> } > > >>> On Mon, Feb 22, 2010 at 9:50 AM, Alex Wallace > >>> <[email protected]>wrote: > > >>> Paul, one recommendation: store the results of > >>> element.nextSiblings() in a > >>> local variable outside of the loop. DOM traversals are pretty slow. > > >>> Best, > >>> Alex > > >>> On Mon, Feb 22, 2010 at 12:28 PM, Paul Kim <[email protected]> > >>> wrote: > > >>> Hi Walter, if you want to get all similar elements up to but not > >>> including > >>> the next head, I would use Prototype's Element.nextSiblings() to > >>> loop > >>> through all elements with the same tagName and break when the > >>> tagName is > >>> different. Here is a function I created just now that would > >>> hopefully do > >>> what you want: > > >>> function getSimilarElements(element) { > >>> var element = $(element); > >>> var similarElements = new Array(); > >>> for (var i=0; i< element.nextSiblings().length; i++) { > >>> if (element.tagName == element.nextSiblings()[i].tagName) { > >>> similarElements[i] = element.nextSiblings()[i]; > >>> } > >>> else { > >>> break; > >>> } > >>> } > >>> return similarElements; > >>> } > > >>> Here is the entire example as well: > > >>> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" > >>> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> > >>> <html xmlns="http://www.w3.org/1999/xhtml"> > >>> <head> > >>> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> > >>> <title>Demo</title> > >>> <script type="text/javascript" src=" > >>>http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js > >>> "></script> > >>> <script type="text/javascript" src=" > >>>http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/ > >>> scriptaculou... > >>> "></script> > >>> <script type="text/javascript"> > >>> document.observe("dom:loaded", function() { > >>> function getSimilarElements(element) { > >>> var element = $(element); > >>> var similarElements = new Array(); > >>> for (var i=0; i< element.nextSiblings().length; i++) { > >>> if (element.tagName == element.nextSiblings() > >>> [i].tagName) { > >>> similarElements[i] = element.nextSiblings()[i]; > >>> } > >>> else { > >>> break; > >>> } > >>> } > >>> return similarElements; > >>> } > > >>> console.log(getSimilarElements('foo')); > >>> }); > >>> </script> > >>> <style type="text/css"> > >>> body {margin:0; padding:0;} > >>> </style> > >>> </head> > >>> <body> > >>> <div> > >>> <h3>first header</h3> > >>> <p id="foo">first paragraph</p> > >>> <p>second paragraph</p> > >>> <h3>second header</h3> > >>> <p>third paragraph</p> > >>> <p>fourth paragraph</p> > >>> <p>fifth paragraph</p> > >>> <h3>third header</h3> > >>> <p>sixth paragraph</p> > >>> <p>seventh paragraph</p> > >>> </div> > >>> </body> > >>> </html> > > >>> On Mon, Feb 22, 2010 at 8:22 AM, Walter Lee Davis > >>> <[email protected]>wrote: > > >>> Thanks very much. I was looking in the wrong place for the > >>> functionality > >>> I need. You've given me the bones I need to build on. > > >>> Walter > > >>> On Feb 22, 2010, at 11:07 AM, Alex Wallace wrote: > > >>> I whipped up something that should handle the task, although I'm > >>> sure > >>> this could be optimized using the nextElementSibling. This version > >>> grabs > >>> nextSiblings() and then filters them, but the faster way would be to > >>> iterate > >>> over the `element.nextSibling` and break when it encounters a > >>> different tag > >>> name (instead of finding them all, which is bound to be slower). > > >>> But here goes: > > >>> function consecutiveSameTagSiblings(element) { > >>> element = $(element); > >>> var siblings = element.nextSiblings(), results = []; > >>> if (!siblings[0]) return results; > >>> var tagName = siblings[0].tagName.toLowerCase(); > >>> for (var i = 0, sibling; sibling = siblings[i]; ++i) { > >>> if (sibling.tagName.toLowerCase() === tagName) > >>> results.push(sibling); > >>> else > >>> break; > >>> } > >>> return results; > >>> } > > >>> Best, > >>> Alex > > >>> On Mon, Feb 22, 2010 at 10:38 AM, Walter Lee Davis > >>> <[email protected]> > >>> wrote: > >>> Hmmm. That's not a documented function. I had a look at the source, > >>> and > >>> I can't see how it works. It accepts a node as its only argument, > >>> and it > >>> doesn't seem to perform any comparison as it executes. How then > >>> would I get > >>> it to stick to just the one type of sibling, and how would I get it > >>> to stop > >>> when it ran out of similar siblings? > > >>> Thanks as always for any pointers. > > >>> Walter > > >>> On Feb 22, 2010, at 10:29 AM, Alex Wallace wrote: > > >>> You'll want to leverage Prototype's nextElementSibling function. > >>> That > >>> function grabs element.nextSibling and traverses until it finds an > >>> an actual > >>> element (by checking nodeType). > > >>> You could wrap a function around that which stores the tagName of > >>> the > >>> first element it matches, and then continues to find > >>> nextElementSibling > >>> until it either returns null, or break when the tagName doesn't > >>> match the > >>> original tagName. > > >>> Take a look at the innards of Element.adjacent and > >>> Element.nextElementSibling for an idea of what I mean. > > >>> Best, > >>> Alex > > >>> On Mon, Feb 22, 2010 at 12:00 AM, Walter Lee Davis > >>> <[email protected]> > >>> wrote: > >>> I have a structure like this inside a parent DIV: > > >>> H3 > >>> P > >>> P > >>> H3 > >>> P > >>> P > >>> P > >>> H3 > >>> P > >>> P > > >>> And I'd like to be able to get the paragraphs between two heads, or > >>> between the last head and the end of the parent DIV. > >>> Element.adjacent('p') > >>> doesn't do what I need -- > > ... > > read more » -- You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en.
