Element.adjacent(selector) doesn't return expected elements

19 views
Skip to first unread message

jip...@gmail.com

unread,
Sep 4, 2008, 10:39:32 AM9/4/08
to Prototype & script.aculo.us

Hi!

It's my first time here, I never felt the need to write here because
Prototype is almost perfect to me :D

Bu I have an issue with Element.adjacent() method. I would like to use
it to find all the dd sibling element in a definition list menu. Here
is a sample of my html code for the menu :
<dl id="menu">
<dt>title 1</dt>
<dd id="dd1">
<dl>
<dt>sub-title 1</dt>
<dd id="dd11">
<dl>
<dt>sub-sub-title 1</dt>
</dl>
</dd>
<dt>sub-title 2</dt>
<dd id="dd12">
<dl>
<dt>sub-sub-title 2</dt>
<dl>
<dt>sub-sub-sub-title 1</dt>
<dd id="dd121">
<dl>
<dt>sub-sub-sub-sub-title 1</dt>
</dl>
</dd>
<dt>sub-sub-sub-title 2</dt>
<dd id="dd122">
<dl>
<dt>sub-sub-sub-sub-title 2</dt>
</dl>
</dd>
</dl>
</dl>
</dd>
</dl>
</dd>
<dt>title 2</dt>
<dd id="dd2">
<dl>
<dt>sub-title 1</dt>
<dd>
<dl>
<dt>sub-sub-title 1</dt>
</dl>
</dd>
<dt>sub-title 2</dt>
</dl>
</dd>
</dl>

<div id="result" style="border:solid 1px red;"></div>

And the js :

<script type="text/javascript" src="libJS/prototype.js"></script>
<script type="text/javascript">
var s = "dds adjacent to dd1: " + $
("dd1").adjacent("dd").pluck("id").toString();
s += "<br />dds adjacent to dd11: " + $
("dd11").adjacent("dd").pluck("id").toString();

$("result").update(s);
</script>


here are the alert:

dds adjacent to dd1: dd11,dd12,dd121,dd122,dd2
dds adjacent to dd11: dd12,dd121,dd122

But for me, siblings are supposed to be on the same level. All sibling
should have the same parant, not the same ancestor. So the list of dds
should be :
dds adjacent to dd1: dd2
dds adjacent to dd11: dd12

Am I wrong here ?

Thanks for your help,
Jean-Philippe

Matt Foster

unread,
Sep 4, 2008, 1:19:28 PM9/4/08
to Prototype & script.aculo.us
Hey Jean,

My first thought was bad markup but everything you had was well-
formed. So I took a look into the prototype source code and with
regret I found that your apprehension was confirmed. The adjacent
method looks for all children of the node's parent that matches the
selector, so you get siblings and nephews.

adjacent: function() {
var args = $A(arguments), element = $(args.shift());
return Selector.findChildElements(element.parentNode,
args).without(element);
},

I agree with you completely, it should only collect direct sibling
nodes.

jip...@gmail.com

unread,
Sep 4, 2008, 3:10:04 PM9/4/08
to Prototype & script.aculo.us
Do you think a patch could be release soon or I should do it myself ?

Thanks,
Jp

kangax

unread,
Sep 4, 2008, 4:37:11 PM9/4/08
to Prototype & script.aculo.us
On Sep 4, 3:10 pm, "jip...@gmail.com" <jip...@gmail.com> wrote:
> Do you think a patch could be release soon or I should do it myself ?

As a temporary workaround, try:

$('dd1').siblings().grep(new Selector('dd'));

-- kangax

jip...@gmail.com

unread,
Sep 5, 2008, 2:57:23 PM9/5/08
to Prototype & script.aculo.us
It's working, thanks you. My version was way more complicated:

$('dd1').up('dl').childElements().select(function(elt) { return
elt.tagName == 'DD';}).without($('dd1'))

But it worked too.

I will update my code with your version. Should I report the bug
somewhere to be sure that the core developer team is aware of it ?

And finally, how can we learn about the Selector class ? I didn't know
it and I couldn't find it in the API doc...

Thanks again,
JP

kangax

unread,
Sep 5, 2008, 3:39:26 PM9/5/08
to Prototype & script.aculo.us
On Sep 5, 2:57 pm, "jip...@gmail.com" <jip...@gmail.com> wrote:
> It's working, thanks you. My version was way more complicated:
>
> $('dd1').up('dl').childElements().select(function(elt) { return
> elt.tagName == 'DD';}).without($('dd1'))
>
> But it worked too.
>
> I will update my code with your version. Should I report the bug
> somewhere to be sure that the core developer team is aware of it ?

Please file a bug at http://prototype.lighthouseapp.com/projects/
We'll look into it.

>
> And finally, how can we learn about the Selector class ? I didn't know
> it and I couldn't find it in the API doc...

Some parts of the documentation are outdated and some are not
complete. `grep` just happens to delegate its filtering to `match`
method of an iterable object (if such method exists). This delegation
is what makes passing a Selector instance useful (as it provides a
"public" `match` method).

--
kangax

jip...@gmail.com

unread,
Sep 8, 2008, 12:48:34 PM9/8/08
to Prototype & script.aculo.us
Hi kangax,

Thanks for your response. I went to the bug tracker and find the bug
here with a patch to fix it !

http://prototype.lighthouseapp.com/projects/8886/tickets/244-element-adjacent-can-select-siblings-childnodes-and-shouldn-t

Everything is under control :)
JP

On Sep 5, 3:39 pm, kangax <kan...@gmail.com> wrote:
> On Sep 5, 2:57 pm, "jip...@gmail.com" <jip...@gmail.com> wrote:
>
> > It's working, thanks you. My version was way more complicated:
>
> > $('dd1').up('dl').childElements().select(function(elt) { return
> > elt.tagName == 'DD';}).without($('dd1'))
>
> > But it worked too.
>
> > I will update my code with your version. Should I report the bug
> > somewhere to be sure that the core developer team is aware of it ?
>
> Please file a bug athttp://prototype.lighthouseapp.com/projects/

jdalton

unread,
Sep 8, 2008, 2:45:12 PM9/8/08
to Prototype & script.aculo.us
@Kangax awesome use of the .match method check in grep !!!

jip...@gmail.com

unread,
Sep 8, 2008, 3:13:55 PM9/8/08
to Prototype & script.aculo.us
I place a comment on the bug trtacker to point Kangax solution. It is
indeed simple and effective.

http://prototype.lighthouseapp.com/projects/8886-prototype/tickets/244-element-adjacent-can-select-siblings-childnodes-and-shouldn-t#ticket-244-4

kangax

unread,
Sep 8, 2008, 4:31:25 PM9/8/08
to Prototype & script.aculo.us
On Sep 8, 3:13 pm, "jip...@gmail.com" <jip...@gmail.com> wrote:
> I place a comment on the bug trtacker to point Kangax solution. It is
> indeed simple and effective.
>
> http://prototype.lighthouseapp.com/projects/8886-prototype/tickets/24...

While it's simple and effective, the problem is inability of
`Selector` class to work with complex or multiple selectors.
`adjacent` supports passing any number of selectors to match elements
against. `new Selector` can't handle more than one and that one can
only be a simple one : )

There's a way to use grep but its O(n^2) complexity makes it ugly : /

adjacent2: function(element) {
element = $(element), expressions = $A(arguments).slice(1);
return Element.siblings(element).grep({
match: function(element) {
return expressions.any(function(expr) {
return element.match(expr);
});
}
});
}

This would obviously work nicely if Selector constructor was able to
accept complex selectors.
Any other ideas?

--
kangax
Reply all
Reply to author
Forward
0 new messages