简体   繁体   中英

Inserting tags in between html content

I have the sample below content in mydiv

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner text </i> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

Now I want to append highlighting div in between the mydiv content. sample is given below.

<div class="highlight">highlight text</div>

I want to insert this div in every 200 words, but the problem is it should not goes inside any of the children tags. for example in case 200th word is inner it should not append like

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner<div class="highlight">highlight text</div> text </i> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

it should append after the inner tags

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner text </i> <div class="highlight">highlight text</div> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

I tried with substring but it goes inside the child tags. Is there any way to achieve this? We can use any js libraries.

The easiest way of doing this is to loop through the content of your div and insert the highlight in the right spot. Here is the code :

$(document).ready(function () {
    // count of characters (modulo the period) and selected period
    var count = 0, period = 200;

    // iterator and highlight
    var words = '', highlight = '<div class="highlight">highlight text</div>';

    // loop through the contents
    $('#mydiv').contents().each(function () {
        // we only care about text contents
        if (this.nodeType === 3) {
            // get the individual words
            words = $(this).text().split(' ');
            // loop through them
            for (var j = 0; j < words.length; j++) {
                // increase count except if the word is empty (mutiple spaces)
                if (words[j] && words[j] !== '\n') { count++; }
                // if the period is exceeded, add the highlight and reset the count
                if (count === period) {
                    words.splice(1 + j++, 0, highlight);
                    count = 0;
                }
            }
            // replace the text
            $(this).replaceWith(words.join(' '));
        }
    });
});

You can use JQuery after or insertAfter to insert element after the target.

append method inserts the specified content as the last child of each element in the jQuery collection

 $(function(){ // your logic to find position goes here... // append text after an element $("#mydiv i:first-child").after("<div class='highlight'>highlight text</div>"); }); 
 .highlight{ color: red; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="mydiv"> sample1 text1 sample1 text1 sample1 text1sample1 tex1 sample1 text1 sample text1 sample2 text2 sample2 text sample2 textsample2 text2 sample2 text2 sample2 text2 sample3 text3 sample3 text3 sample3 textsample3 text3 sample3 text3 sample3 text3 sample 3 text 3sample 3text sample3 textsample3 text4 sample 4text sample4 text <i>1inner text 1 </i> <i>sample text 1</i> <i>2inner text 2</i> <i>sample text2 </i> <i>3inner text 3</i> <i>sample text 3</i> <i>4inner text 4</i> <i>sample text4 </i> <i>5inner text 5</i> <i>sample text5 </i> <i>6inner text 6</i> <i>sample text6 </i> <i>7inner text 7</i> <i>sample text 7</i> <b>8sample text 8</b> <i>sample text 8</i> <b>9sample text 9</b> <i>sample text 9</i> <b>10sample text 10</b> <i>sample text10 </i> <b>11sample text 11</b> <i>sample text 11</i> <b>12sample text 12</b> <i>sample text 12</i> </div> 

UPDATED The div that I will be adding after every 2nd word.

var some_div = '<div style="display:inline-block;color:red;">some_text</div>';

var text = $('#mydiv').text().match(/\w+/g);

Secondly, traverse through all the words and prefixed these words in the html of the div with a unique identifier text.

Here, I am add a string <index>$$ where <index> increments on each traversal.

var i = 1;
var count = 1;
var html = $('#mydiv').html();

text.forEach(function(word, index) {

  var offset = html.indexOf(word);
  while (html[offset - 1] == '$' && html[offset - 2] == '$') {
    offset = html.indexOf(word, offset + 1);
  }

  if ((count % up_index) == 0) {
    html = html.slice(0, offset) + (i++) + '$$' + html.slice(offset)
    $('#mydiv').html(html);
  }

  count++;
});

Finally, loop through all the unique tokens and replace them with your html.

to find tokens use $('#mydiv').find(':contains(' + j + '$$)'); of jquery.

for (var j = 1; j < i; j++) {
  var elm = $('#mydiv').find(':contains(' + j + '$$)');
  if (elm.length == 0) {
    console.log('inroot>>' + ':contains(' + j + '$$)');
    var offset = $(':contains(' + j + '$$)').last().html().indexOf(j + '$$');
    var t_html = $(':contains(' + j + '$$)').last().html().slice(0, (offset + (("" + j + '$$').length))).replace(/[0-9]\$\$/ig, '');
    t_html += some_div;
    t_html += $(':contains(' + j + '$$)').last().html().slice(offset + (("" + j + '$$').length));
    $('#mydiv').html(t_html);

  } else {
    console.log('not inroot>>' + ':contains(' + j + '$$)');
    $(some_div).insertAfter(elm.last());
  }
}

Here is an Example where I have added div after every 2nd word

Firstly, I am fetching all the words inside the interested container as follows,

 var some_div = '<div style="display:inline-block;color:red;">some text</div>'; var up_index = 2; // Word index that will be updated every 2nd word. var text = $('#mydiv').text().match(/\\w+/g); var i = 1; var count = 1; var html = $('#mydiv').html(); text.forEach(function(word, index) { var offset = html.indexOf(word); while (html[offset - 1] == '$' && html[offset - 2] == '$') { offset = html.indexOf(word, offset + 1); } if ((count % up_index) == 0) { html = html.slice(0, offset) + (i++) + '$$' + html.slice(offset) $('#mydiv').html(html); } count++; }); for (var j = 1; j < i; j++) { var elm = $('#mydiv').find(':contains(' + j + '$$)'); if (elm.length == 0) { console.log('inroot>>' + ':contains(' + j + '$$)'); var offset = $(':contains(' + j + '$$)').last().html().indexOf(j + '$$'); var t_html = $(':contains(' + j + '$$)').last().html().slice(0, (offset + (("" + j + '$$').length))).replace(/[0-9]\\$\\$/ig, ''); t_html += some_div; t_html += $(':contains(' + j + '$$)').last().html().slice(offset + (("" + j + '$$').length)); $('#mydiv').html(t_html); } else { console.log('not inroot>>' + ':contains(' + j + '$$)'); $(some_div).insertAfter(elm.last()); } } $('#mydiv').html($('#mydiv').html().replace(/[0-9]\\$\\$/ig, '')); 
 .highlight { color: red; display: inline-block; } b { background-color: blue; } i { background-color: yellow; } i, b { border: 1px solid green; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="mydiv"> sample text <b><a>sample text</a></b> <i>sample text </i> ...... <i>inner text </i> <i>sample text </i> ...... <b>sample text </b> <i>sample text </i> </div> 

You haven't given specifics on how you arrive at the text within the DOM (and I assume you're using the DOM). But given the text node containing the word of interest, something like this should do. I am using a minimal amount jQuery for convenience, it is hardly necessary.

// use jQuery to find the text node "inner text" from your example
let textNode = $("#mydiv i")
    .first()
    .contents()
    .filter(function () {
        return this.nodeType == 3; /* text node */
    }).get(0);

// find the parent element of the text node
let el = textNode;
while (el.parentNode) {
    if (el.nodeType == 1) break; /* element */
    el = el.parentNode;
}
// append the html after the parent of the text node.
 $(el).after(`<div class="highlight">highlight text</div>`);

You can see this in action at this plnkr .

Basically the code gets the text node of the Nth word of interest, finds it's parent element, then inserts the desired html as the first right sibling of the parent element.

In any way, I hope this helps.

NOTE: HTML used is given sample content .
Try splitting your div content and work from that. See comments for explanations:

        //1.Get mydiv content
        //2. Split spaces and newlines
        //3. Remove empty array values
        var div =     $("#mydiv").html().toString().split(/[\s+\n]/).filter(String);

        var allowAdd = true, appendNow;
        for(var a=0; a < div.length ; a++){
            if(div[a].match(/^</) && div[a].match(/>$/)){ //search for end tags ie. </i>, </b>
                if(div[a].match(/<\//)){ //if end tag, 
                    allowAdd = true;    //allow append
                }
            }else if (div[a].match(/</)){ //if start stag,
                allowAdd = false;   //disallow append (inside block)

            }

            if((a+1)%200 == 0){
                //every 200 words
                appendNow = true;
            }

            //append if 200th word and end tag is passed
            if(appendNow && allowAdd){
                div[a] += ' <div class="highlight">highlight text </div> ';
                appendNow = false;
            }
        }

        //join array values and assign value to mydiv content
        $("#mydiv").html(div.join(" ")); 

Here's a code that will give you your desired result. The advantage of this code is that it doesn't check every element whether it's a tag or not by checking if it contains < or </ , which in my opinion is good, as our code is not as complicated as it would be, and we don't need to check through all values, whether or not they contain < or </ . (Less calculation, should in theory run faster.)

var elements = $("#mydiv").contents(); //Get all contents of #mydiv
$("#mydiv").html(null); //Delete all elements from #mydiv

var count = 0; //This will be counting our elements

for(var i = 0; i < elements.length; i++){ //Go through all elements of #mydiv
    if(elements[i].nodeName == "#text"){ //If the element is a text block, then:

        var textElements = $(elements[i]).text().split(/\s+/g); //Split the text by all the spaces

        for(var j = 0; j < textElements.length; j++){ //Go through all elements inside the text block

            if(textElements[j] == "") continue; //The splitting of the text-block elements is not perfect, so we have to skip some elements manually

            count++; //Add to our count

            $("#mydiv").append(textElements[j] + " "); //Add this element to our cleared #mydiv

            if(count != 0 && count % 200 == 0){ //Every 200 elements, do this:
                $("#mydiv").append(" <span class='highlight'>highlight</span> "); //Add our highlight
            }
        }
    }else{ //If the element is not a text block, then:

        $("#mydiv").append(elements[i]); //Add the non-text element

        count++; //Add to our counter

        if(count != 0 && count % 200 == 0){ //Every 200 elements, do this:
            $("#mydiv").append(" <span class='highlight'>highlight</span> "); //Add our highlight

        }
    }
}

Provided that you are ok with manipulating the HTML of #mydiv as a string, one solution is to use string.replace with a regular expression and a replacement function, such as:

function insertInHTMLEveryNWords(n, htmlString, insertString) {
  var wordCounter = 0,
      tagDepth = 0;
  return htmlString.replace(
    /<(\/?)([^>]+)>|[^<\s]+/g,
    function(match, forwardSlash, tagContent) {
      if (tagContent) { //matched a tag
        tagDepth += forwardSlash ? -1 : 1;
      } else { //matched a word
        wordCounter++;
      }
      if (!tagDepth && wordCounter >= n) {
        //if not inside tag and words are at least n,
        wordCounter = 0;
        return match + insertString;
      } else {
        return match;
      }
    });
}

The following snippet contains a working demo of the approach, simplified to insertion after every 2 words (if not in any tag, or directly after the next possible closing tag, as stated by the OP):

 var htmlOriginal = document.getElementById('mydiv').innerHTML; var htmlWithInsertions = insertInHTMLEveryNWords( 2, htmlOriginal, '<div>[Inserted DIV after every 2 words or when not in any tag]</div>' ); //inspect result in console console.log(htmlWithInsertions); //replace html in #mydiv document.getElementById('mydiv').innerHTML = htmlWithInsertions; function insertInHTMLEveryNWords(n, htmlString, insertString) { var wordCounter = 0, tagDepth = 0; return htmlString.replace( /<(\\/?)([^>]+)>|[^<\\s]+/g, function(match, forwardSlash, tagContent) { if (tagContent) { //matched a tag tagDepth += forwardSlash ? -1 : 1; } else { //matched a word wordCounter++; } if (!tagDepth && wordCounter >= n) { //if not inside tag and words are at least n, wordCounter = 0; return match + insertString; } else { return match; } }); } 
 <div id="mydiv"> Some text, word3, <em>emphasized and <strong>strong</strong></em> text. </div> 

A potential limitation is that manipulating the HTML replaces the existing DOM elements in #mydiv and breaks any previous references to them. If that does not pose any problem, this is a straightforward working solution.

The i tag is an inline element and it isn't possible to insert a block element, as div , inside it. And "highlight" is not a valid attribute for div .

To achieve the insertion, use a span instead of a div . And check which attribute are needed for your goals. The result will be (with id as attribute):

<div id="mydiv">
   sample text sample text sample text...
   ......
   <i>inner<span id="highlight">highlight text</span> text </i> <i>sample text </i>
   ......
   <b>sample text </b> <i>sample text </i>
</div>

I assume you are already finding the word 200 and appending your div after it, something like this maybe?

varUntilSpace200 + '<div "highlight">highlight text</div>' + restOfInnerHTML;

Then all you need to do is check in restOfInnerHTML if after space 200 there is a

"</"

if so, just append everything from that position to the first

">"

var indof1 = restOfInnerHTML.indexOf("</");
var indof2 = restOfInnerHTML.indexOf("<");
var indof3 = restOfInnerHTML.indexOf(">");

if (indof1 < indof2) {
  varUntilSpace200 += restOfInnerHTML.substring(indof1,indof3);
  restOfInnerHTML = restOfInnerHTML.substring(indof3+1,restOfInnerHTML.length);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM