[Proto-Scripty] Re: How would I get a closer set of siblings?
This would be an ideal use case for XPath. On Mar 5, 10:35 am, Walter Lee Davis wa...@wdstudio.com 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 wa...@wdstudio.com 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 wa...@wdstudio.com 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 kimba...@gmail.com 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 alexmlwall...@gmail.comwrote: 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 kimba...@gmail.com 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++) {
Re: [Proto-Scripty] Re: How would I get a closer set of siblings?
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 wa...@wdstudio.com 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 wa...@wdstudio.com 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 kimba...@gmail.com 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 alexmlwall...@gmail.comwrote: 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 kimba...@gmail.com 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
Re: [Proto-Scripty] Re: How would I get a closer set of siblings?
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 wa...@wdstudio.comwrote: 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 kimba...@gmail.com 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 alexmlwall...@gmail.com 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 kimba...@gmail.com 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 / titleDemo/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 h3first header/h3 p id=foofirst paragraph/p psecond paragraph/p h3second header/h3 pthird paragraph/p pfourth paragraph/p pfifth paragraph/p h3third header/h3 psixth paragraph/p pseventh paragraph/p /div /body /html On Mon, Feb 22, 2010 at 8:22 AM, Walter Lee Davis wa...@wdstudio.com wrote: Thanks very much. I was looking in the wrong place for the functionality I need. You've given
Re: [Proto-Scripty] Re: How would I get a closer set of siblings?
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 wa...@wdstudio.com 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 kimba...@gmail.com 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 alexmlwall...@gmail.comwrote: 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 kimba...@gmail.com 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 / titleDemo/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
Re: [Proto-Scripty] Re: How would I get a closer set of siblings?
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 kimba...@gmail.com 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 alexmlwall...@gmail.comwrote: 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 kimba...@gmail.com 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 / titleDemo/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 h3first header/h3 p id=foofirst paragraph/p psecond paragraph/p h3second header/h3 pthird paragraph/p pfourth paragraph/p pfifth paragraph/p h3third header/h3 psixth paragraph/p pseventh paragraph/p /div /body /html On Mon, Feb 22, 2010 at 8:22 AM, Walter Lee Davis wa...@wdstudio.comwrote: 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 wa...@wdstudio.com wrote: Hmmm. That's not a documented function. I had a look at the