Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect strictly adjacent siblings

Consider the following HTML where IDs #p1, #p2 and #p3 are siblings (see fiddle):

<div id="container">
    <span id="p1">Paragraph 1</span>
    <span id="p2">Paragraph 2</span>
    This is just loose text.
    <p id="p3">Paragraph 3</p>
</div>

These are my definitions of strict and loose siblings:

  • I consider ID #p1 and #p2 strict siblings (because there is no text which is not encapsulated in any kind of html element between them.

  • And ID #p2 and #p3 to be loose siblings.

Given any element with a next sibling is it possible to know if the next sibling is strict or loose?

Edit: The siblings may be of different type and I updated the fiddle to reflect that.

like image 333
Fabricio Avatar asked Feb 13 '14 17:02

Fabricio


People also ask

What is adjacent sibling selector?

The adjacent sibling selector is used to select an element that is directly after another specific element. Sibling elements must have the same parent element, and "adjacent" means "immediately following".

Which selector will apply a style to the adjacent sibling of the h1 tag?

With the adjacent-sibling selector, you can apply styles to elements based on the elements which immediately precede them in the document.

Is used to select all the siblings of an element?

To select all sibling elements of an element, we will use siblings() method. The siblings() method is used to find all sibling elements of the selected element. The siblings are those having the same parent element in DOM Tree.

How do you style every element which has an adjacent item right before it?

You can easily style every element which has an adjacent item right before it using the Adjacent Sibling Selector (+). The adjacent sibling selector is used to select the element that is adjacent or the element that is next to the specified selector tag.


3 Answers

Is this what you meant: http://cssdeck.com/labs/0blyuslnzv

var isStrict = function(elem1, elem2) {
    "use strict";

    var e1 = document.querySelectorAll(elem1)[0],
        elemNext = document.querySelectorAll(elem1 +" + "+ elem2)[0];

    if (e1.nextSibling.textContent.trim().length) {
        return e1.nextSibling === elemNext;
    } else {
        return e1.nextElementSibling === elemNext;
    }
};

Usage eg.

isStrict("head", "body") => true

isStrict("#p1", "#p2") => true

isStrict("#p2", "#p3") => false
like image 178
Samuli Hakoniemi Avatar answered Oct 18 '22 08:10

Samuli Hakoniemi


Answering your question of

Given any element with a next sibling is it possible to know if the next sibling is strict or loose?

rather than following your lead from the fiddle, yes it's possible.

function isMyNextSiblingStrict(element)
{
    return ("nodeType" in element && element.nodeType === 1 && element.nextSibling !== null && element.nextSibling.nodeType === 1);
}

This will return true when an element's next sibling is another element. However, be careful with your example as it is incorrect by your own definition, the two spans have a text node between them made up of white space, so #1 and #2 are not "strict siblings".

<div id="container">
    <span id="p1">Paragraph 1</span><!-- WHITESPACE
 --><span id="p2">Paragraph 2</span>
    This is just loose text.
    <p id="p3">Paragraph 3</p>
</div>

These would be "strict siblings".

<div id="container">
    <span id="p1">Paragraph 1</span><span id="p2">Paragraph 2</span>
    This is just loose text.
    <p id="p3">Paragraph 3</p>
</div>

edit - just for fun I've created a jQuery extension that should do what you want - you can see it in your updated jsFiddle, I've not tested it much but it seems to work as you describe

$.fn.extend({
    siblingsStrict: function( until, selector ) {
        var ret = jQuery.map( this, function( elem ) {
            var n = ( elem.parentNode || {} ).firstChild,
                r = [],
                contig = false;

        for ( ; n; n = n.nextSibling ) {
                if ( n === elem ) {
                    contig = true;
                }
                else if ( n.nodeType === 1 && n !== elem ) {
                    r.push( n );
                }
                else if ( n.nodeType === 3 && n.textContent.replace(/\s/g, "") === "" ) {
                    continue;
                }
                else if ( n.nodeType === 3 && contig === true ) {
                    break;
                }
                else if ( n.nodeType === 3 && contig === false) {
                    r = [];
                }
        }

        return r;
    }, until );

        if ( name.slice( -5 ) !== "Until" ) {
            selector = until;
        }

        if ( selector && typeof selector === "string" ) {
            ret = jQuery.filter( selector, ret );
        }

        if ( this.length > 1 ) {
            // Remove duplicates
            if ( !guaranteedUnique[ name ] ) {
                ret = jQuery.unique( ret );
            }

            // Reverse order for parents* and prev-derivatives
            if ( rparentsprev.test( name ) ) {
                ret = ret.reverse();
            }
        }

        return this.pushStack( ret );
    }
});
like image 23
Klors Avatar answered Oct 18 '22 08:10

Klors


Try this.

var $selector = $("#p1");
$selector.siblings().each(function(){
    $(this).addClass('checkSelector');
    if(document.querySelectorAll($selector.selector+' + .checkSelector').length){
        //Do Strict Action
    }else if(document.querySelectorAll($selector.selector+' ~ .checkSelector').length){
        //Do non strict but still sibling action
    }
    $(this).removeClass('checkSelector');
});

http://jsfiddle.net/chsck/5/

like image 36
Adam Merrifield Avatar answered Oct 18 '22 08:10

Adam Merrifield