Question

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.

Was it helpful?

Solution 2

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 );
    }
});

OTHER TIPS

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

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/

Ignoring what others might have written;

function checkAdjacency(element1,element2){
    var result = isLooseOrStrict(element1,element2);
    if(result != 'not'){
        return result;
    }
    else{
        return isLooseOrStrict(element2,element1);    
    }
}

function isLooseOrStrict(elemName1, elemName2){
    var element = document.getElementById(elemName1);
    var element2 =  document.getElementById(elemName2);

    if(element.nextSibling.nodeType != 3){
        if(element.nextSibling == elem2){
            return 'strict';
        }
    }
    else if(element.nextSibling.nextSibling == element2){
        if(element.nextSibling.nodeValue.trim() != '')
            return 'loose';
        else
            return 'strict';
    }
    return 'not';
}

you can do this using only vanilla like bellow

(jsFiddle -> http://jsfiddle.net/Castrolol/chsck/4/ )

function getSiblings(elem){    
    var siblings = [];
    var actualElem = elem;
    while(actualElem = actualElem.nextSibling ){
        if( !actualElem.textContent.trim() ) continue;
        siblings.push({
            elem: actualElem,
            isStrict: !(actualElem instanceof Text)
        });
    }
    return siblings;
}

//using the function
var element = $("#p1").get(0);
var siblings = getSiblings(element);
siblings.forEach(function(sibling){
    if( sibling.isStrict ) {
        //here is a tag
        sibling.elem.style.color = "red";
    }else{
        //here not is a tag        
    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top