jQuery перенос текста и элементов между тегами <hr> - PullRequest
5 голосов
/ 18 июля 2010

Мне нужно обернуть все, включая свободный текст, который находится между двумя <hr> элементами.

По данным этого источника:

<hr class=begin>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  <a href=mauris.html>Mauris</a> id diam turpis, et faucibus nunc.
  <div><img src=foo.png /></div>
<hr class=end>

Мне нужно обернуть все между тегами hr.begin и hr.end, например:

<hr class=begin>
  <div class=content>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    <a href=mauris.html>Mauris</a> id diam turpis, et faucibus nunc.
    <div><img src=foo.png /></div>
  </div>
<hr class=end>

Я не могу использовать метод, подобный .nextUntil('hr.end'), потому что он не выделит текст без тегов.

Ответы [ 6 ]

5 голосов
/ 18 июля 2010

Обновлено

Мне нравится эта версия лучше, чем моя предыдущая: http://jsfiddle.net/LbmCg/3/

(Отчасти вдохновленный ответом J-P дал.)

$('hr.begin').each(function(){
    var $set = $();
    var nxt = this.nextSibling;
    while(nxt) {
        if(!$(nxt).is('hr.end')) {
            $set.push(nxt);
            nxt = nxt.nextSibling;
        } else break;
    } 
   $set.wrapAll('<div class="content" />');
});

Оригинальный ответ

Попробуйте это: http://jsfiddle.net/LbmCg/

Если имеется более одного набора для намотки, потребуется некоторая настройка.

var foundBegin = false;
var foundEnd = false;

$('hr.begin').parent()
    .contents()
    .filter(function() {
        if($(this).is('hr.begin')) {
            foundBegin = true;
        }
        if($(this).is('hr.end')) {
            foundEnd = true;
        }
        return foundBegin && !foundEnd;
    })

    .wrapAll('<div class="content"/>');​

jQuery's .contents() возвращает все узлы, включая текстовые узлы. Итак, здесь мы переходим к .parent() из hr.begin, получаем все его узлы, используя .contents(), затем фильтруем их, отслеживая, когда мы нашли начало и конец, и возвращая только элементы между ними.

Затем мы используем .wrapAll(), чтобы обернуть их div.content.


РЕДАКТИРОВАТЬ: Если есть несколько наборов для переноса, попробуйте это: http://jsfiddle.net/LbmCg/1/

РЕДАКТИРОВАТЬ: Немного почищены в обоих примерах.

2 голосов
/ 18 июля 2010
​$('hr.begin ~ hr.end').each(function(){

    var contents = [], node, begin = $(this).prevAll('hr.begin')[0];

    if (node = this.previousSibling) do {
        if (node === begin) break;
        contents.unshift(node);
    } while (node = node.previousSibling);

    $(contents).wrapAll('<div class="content">');

});​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

Может обрабатывать несколько наборов последовательности begin - contents - end.Он будет искать все элементы hr.end, которым предшествуют элементы hr.begin, и для каждого hr.end найдет предшествующие узлы между ним и hr.begin, а затем обернет их все в <div class=content>.

1 голос
/ 31 августа 2010

Была похожая проблема, но я использовал CMS на основе FCKEditor, которая не работала так сильно из-за вставки новых строк TextNodes из-за использования свойства nextSibling.Я вообще не люблю смешивать jQuery с нативным JavaScript, если я тоже могу помочь.Я придумал этот фрагмент, который обновляет решение Patrick DW, которое, вероятно, будет более дружественным для использования jQuery.Также не требует классов для определения следующего блока.

$('hr').each(function(){
    var $set = $([]);
    var $nxt = $(this).next();
    while($nxt.length) {
        if(!$($nxt).is('hr')) {
            $set = $set.add($nxt);
            $nxt=$nxt.next();
        } else break;
    } 
    $set.wrapAll('<div class="content" />');
});
1 голос
/ 18 июля 2010

theElement.contents() распознает текстовые узлы .Поскольку jQuery.nextUntil() на самом деле является оберткой вокруг jQuery.dir, что делает

dir: function( elem, dir, until ) {

    var matched = [], cur = elem[dir];
    while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
        if ( cur.nodeType === 1 ) {
            matched.push( cur );
        }
        cur = cur[dir];
    }
    return matched;
},

, где отфильтрованные текстовые узлы имеют nodeType из 3, здесь может помочь пользовательский jQuery.dir.

-

Я попробовал это решение с тестовыми данными Патрика, и оно работает:

jQuery.dirIncludingTextNodes = function( elem, dir, until ) {
    var matched = [], cur = elem[dir];
    while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
        if ( cur.nodeType === 1 ||cur.nodeType === 3 ) {
            matched.push( cur );
        }
        cur = cur[dir];
    }
    return matched;
};

jQuery.nextUntilIncludingTextNodes = function( elem, i, until ) {

    return jQuery.dirIncludingTextNodes( elem, "nextSibling", until );

};

$('hr.begin').nextUntilIncludingTextNodes("hr").wrap($("<div>").addClass("content"));​​​​​​​​​​​​​​​​​
0 голосов
/ 23 июня 2014

Расширенная версия кода пользователя 191688.Это не только поиск «до» у братьев и сестер, но и вверх и вниз по дереву.

(function($){

    $.fn.extend({
        nextUntilExtended: function(until) {
            var $set = $();
            var nxt = this.get(0).nextSibling;
            while(nxt) {
                if(!$(nxt).is(until)) {
                    if(nxt.nodeType != 3 && $(nxt).has(until)){
                        nxt = nxt.firstChild;
                    }else{
                        $set.push(nxt);
                        if(nxt.nextSibling){
                            nxt = nxt.nextSibling;
                        }else{
                            nxt = nxt.parentNode.nextSibling;
                        }
                    }
                } else break;
            }
            return($set);
        }
    });

})(jQuery);
0 голосов
/ 18 июля 2010

Если ваш HR и другие теги находятся внутри div, например,

<div id="mydiv">
  <hr class=begin>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  <a href=mauris.html>Mauris</a> id diam turpis, et faucibus nunc.
  <div><img src=foo.png /></div>
  <hr class=end>
</div>

Вы можете использовать jQuery.contents () например

 $("#mydiv").contents().each(function(i,el){
  console.log(i,el)
  })

выходы:

0, [object Text]
1, [object HTMLHRElement]
2, [object Text]
3, http://jsbin.com/mauris.html
4, [object Text]
5, [object HTMLDivElement]
6, [object Text]
7, [object HTMLHRElement]
8, [object Text]

Так что вы можете легко разбивать их на группы по мере необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...