Cómo detectar hermanos estrictamente adyacentes

Considere el siguiente HTML donde IDs #p1 , #p2 y #p3 son hermanos (ver violín ):

 <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> 

Estas son mis definiciones de hermanos estrictos y flojos:

  • Considero que ID #p1 y #p2 hermanos estrictos (porque no hay text que no esté encapsulado en ningún tipo de elemento html entre ellos).

  • Y ID #p2 y #p3 para ser hermanos sueltos.

Dado cualquier elemento con un próximo hermano, ¿es posible saber si el próximo hermano es estricto o suelto?

Editar: los hermanos pueden ser de otro tipo y actualicé el violín para reflejar eso.

Respondiendo tu pregunta de

Dado cualquier elemento con un próximo hermano, ¿es posible saber si el próximo hermano es estricto o suelto?

en lugar de seguir tu ejemplo del violín, sí, es posible.

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

Esto volverá true cuando el próximo hermano de un elemento sea otro elemento. Sin embargo, tenga cuidado con su ejemplo ya que es incorrecto según su propia definición, los dos tramos tienen un nodo de text entre ellos formado por espacios en blanco, por lo que los numbers 1 y 2 no son "hermanos estrictos".

 <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> 

Estos serían "hermanos estrictos".

 <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> 

editar – solo por diversión. He creado una extensión de jQuery que debe hacer lo que quieras. Puedes verla en tu jsFiddle actualizado, no lo he probado mucho, pero parece funcionar como describes.

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

Es esto lo que querías decir: 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; } }; 

Uso, por ejemplo.

 isStrict("head", "body") => true isStrict("#p1", "#p2") => true isStrict("#p2", "#p3") => false 

Prueba esto.

 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/

Ignorando lo que otros pudieron haber escrito;

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

puedes hacer esto usando solo vainilla como abajo

(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 = "networking"; }else{ //here not is a tag } });