JQuery inserts html after x number of words inside a div without using split

It was 4 days, I tried many different methods, now I almost refuse, it seems that something is impossible to do ...

I am trying to create a script where it will generate html text and put it in a blog post after it counts x number of words, let it say after it counts 10 words. I was able to achieve this with regex (split), but regex robs my post of HTML. In theory, this is something really simple, but I don’t know why it is so difficult in practice. I can not use paragraphs or any elements as links, it should not insert html only after the text, but not inside the code tags, for example, I have <script> some code </script> My blog text --- The text that needs to be inserted -- , it cannot calculate what is inside the script tags, it should only read plain text and insert a new html after it and be displayed. Say the same logic for entering text and inserting images using the WYSIWG editor. This is very difficult to explain.

Basically, I need something that just get a banner and insert it after x number of words in the text, just that.

Here is what I last tried, without any success (the code does not work):

 <div style="width:1000px; margin-left:auto; margin-right:auto" class="newsitem_text"> <div style="width:980px; margin-left:auto; margin-right:auto"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec pellentesque urna eu pulvinar maximus. Sed elit nunc, vestibulum ut eros vitae, pellentesque rhoncus ipsum. In et metus non diam porttitor maximus iaculis nec lectus. Quisque sodales scelerisque auctor. Nam rutrum venenatis eros, eu condimentum erat placerat ut. Pellentesque sed tempus sem, eu viverra ipsum. Vestibulum nec turpis convallis, dapibus massa vitae, posuere mauris. Suspendisse mattis tincidunt lorem. Aliquam erat volutpat. Nullam at tincidunt erat, maximus laoreet ipsum. </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <script> jQuery(function ($) { var wordList = $(".newsitem_text").html(); var newHtml = ' '; $.each(wordList, function(index, word) { newHtml += ' ' + word; if (index == 2) { newHtml += '<img src="https://www.google.com.br/logos/doodles/2015/adolphe-saxs-201st-birthday-6443879796572160.2-res.png" />' } }); $(newHtml).html('').insertAfter(".newsitem_text"); }); </script> 

UPDATE is when I started to open threads in stackoverflow about this topic, I will give links for reference:

+5
source share
4 answers

One approach to this is as follows, although it is, unfortunately, somewhat naive, and I cannot help suspecting it is too complicated. But:

 // a simple utility function to get only the actual words // from the supplied textNode (though this should work for // elements also): function getActualWords(node) { // gets the textContent of the node, // splits that string on one-or-more ('+') // white-space characters ('\s'); // filters the array returned by split(): return node.textContent.split(/\s+/).filter(function (word) { // word is the current array-element // (a 'word') in the array over // which we're iterating using // Array.prototype.filter(); // here if the word, with leading // and trailing white-space removed // (using String.prototype.trim()) // has a length greater than 0 // (a falsey value) the word is kept // in the array returned by filter: return word.trim().length; // note that negative numbers are // also truthy, but no string can // have a negative length; so the // comparison is effectively, if // not explicitly 'greater than zero' // rather than simply 'not-zero' }); } // named function to insert the specified // element after the nth word: function insertElemAfterNthWord(opts) { // defining the defaults for the function // (which can be overridden via the opts // Object): var defaults = { // the word after-which to insert the // the new element: 'nth': 5, // the text of the new element: 'elemText': 'new element', // the type of element (note no '<' or '>'): 'elemTag': 'div' }; // iterating over the supplied opts Object to update // the defaults with the user-supplied options using // for...in loop: for (var prop in opts) { // if the opts Object has a property and // that property is not inherited from the // prototype chain: if (opts.hasOwnProperty(prop)) { // we set the defaults property // to the property-value held // in the opts Object: defaults[prop] = opts[prop]; } } // aliasing the defaults object (simply to save // typing; this is not essential): var d = defaults, // ensuring that the supplied string, // specifying the element-type has no // '<' or '>' characters (to ensure validty // this should be extended further to // ensure only alphabetical characters are kept): tag = d.elemTag.replace(/<|>/g, ''), // creating the new element: elem = document.createElement(tag); // setting the textContent of the new element: elem.textContent = d.elemText; // ensuring that the d.nth variable is // a number, not a string, in base-10: d.nth = parseInt(d.nth, 10); // if a node was specified: if (d.node) { // setting the 'n' variable to hold // to the firstChild of the d.node: var n = d.node.firstChild, // using the utility function (above) // to get an Array of only the actual // words held in the node: words = getActualWords(n), // getting the number of words held // in the Array of words: wordCount = words.length; // while (n.nodeType is not a textNode OR // d.nth is a greater number than the number // of words in the node) AND the node has // a following sibling node: while ((n.nodeType !== 3 || d.nth > wordCount) && n.nextSibling) { // we update n to the next-sibling: n = n.nextSibling; // we get an array of words from // newly-assigned node: words = getActualWords(n); // we update the wordCount, in // order to progress through: wordCount = words.length; } // if the number of words is less than // the nth word after which we want to // insert the element, we return from // the function (doing nothing): if (getActualWords(n).length < d.nth) { return; // otherwise: } else { // again we get an Array of actual words, // we slice that Array and then get the // last array-element from that array, // using Array.prototype.pop(): var w = getActualWords(n).slice(0, d.nth).pop(), // here we get the index of that word // (note that this is naive, and relies // upon the word being unique as a // proof-of-concept; I plan to update later): i = n.textContent.indexOf(w); // we split the n textNode into // two separate textNodes, at // supplied index ('i + w.length'); // n remains the shortened 'first' // textNode: n.splitText(i + w.length); // navigating to the parentNode, and // using insertBefore() to insert the // new element ('elem') before the // next-siblin of the n textNode: n.parentNode.insertBefore(elem, n.nextSibling); // doing exactly the same, but adding a // newly-created textNode (of a space character) // between the 'n' textNode (which by definition // ends without a space) and newly-inserted // element: n.parentNode.insertBefore(document.createTextNode(' '), n.nextSibling); // joining adjacent, but unconnected, // textNodes (n and the newly-inserted // space character) together, to become // a single node: n.parentNode.normalize(); // returning the newly-created element // so that it can be modified if required // or simply cached: return elem; } } } // calling the function, specifying the // user-defined properties: insertElemAfterNthWord({ // after the tenth word: 'nth': 10, // the element-type (a span): 'elemTag': 'span', // setting the text of that new element: 'elemText': 'this is the newly-added text inside the newly-added element!', // specifying the node into which the element // should inserted: 'node': document.querySelector('div > div') // chaining the function, to use the Element.classList // API to add the 'newlyAdded' class to the // newly-created element: }).classList.add('newlyAdded'); 

 function getActualWords(node) { return node.textContent.split(/\s+/).filter(function(word) { return word.trim().length; }); } function insertElemAfterNthWord(opts) { var defaults = { 'nth': 5, 'elemText': 'new element', 'elemTag': 'div' }; for (var prop in opts) { if (opts.hasOwnProperty(prop)) { defaults[prop] = opts[prop]; } } var d = defaults, tag = d.elemTag.replace(/<|>/g, ''), elem = document.createElement(tag); elem.textContent = d.elemText; d.nth = parseInt(d.nth, 10); if (d.node) { var n = d.node.firstChild, words = getActualWords(n), wordCount = words.length; while ((n.nodeType !== 3 || d.nth > wordCount) && n.nextSibling) { n = n.nextSibling; words = getActualWords(n); wordCount = words.length; } if (getActualWords(n).length < d.nth) { return; } else { var w = getActualWords(n).slice(0, d.nth).pop(), i = n.textContent.indexOf(w); n.splitText(i + w.length); n.parentNode.insertBefore(elem, n.nextSibling); n.parentNode.insertBefore(document.createTextNode(' '), n.nextSibling); n.parentNode.normalize(); return elem; } } } insertElemAfterNthWord({ 'nth': 10, 'elemTag': 'span', 'elemText': 'this is the newly-added text inside the newly-added element!', 'node': document.querySelector('div > div') }).classList.add('newlyAdded'); 
 span { color: #f90; } div { margin-left: auto; margin-right: auto; } .newlyAdded { background-color: #ffa; } 
 <div class="newsitem_text"> <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec pellentesque urna eu pulvinar maximus. Sed elit nunc, vestibulum ut eros vitae, pellentesque rhoncus ipsum. In et metus non diam porttitor maximus iaculis nec lectus. Quisque sodales scelerisque auctor. Nam rutrum venenatis eros, eu condimentum erat placerat ut. Pellentesque sed tempus sem, eu viverra ipsum. Vestibulum nec turpis convallis, dapibus massa vitae, posuere mauris. Suspendisse mattis tincidunt lorem. Aliquam erat volutpat. Nullam at tincidunt erat, maximus laoreet ipsum.</div> 

JS Fiddle demo .

Caveats about the above approach:

  • It is required that all words be contained in the same text node; he does not even try to count words that can begin in one element and end inside a sibling element.
  • This does not allow - in its current implementation - any way to insert a non-text into the created element (although this could be resolved using elem.innerHTML instead of elem.textContent ), but it returns the created element to the calling context so that it can be cached or chained , which allows in a sense to manipulate the created element.
  • Some checks, if not most, are naively naive; and benefit from an extension to accommodate your own specific regional affairs.

Literature:

+1
source

You can use regular expression to add text after n words:

 $("div").html($("div").text().replace(/([a-zA-Z]+[.,]? ){25}/, function(x) { return x + "<p>This paragraph added after 25 words.</p>"; })); 

(You can change the number of words 25 to n ).

See this working example .

+1
source

Try using .html() , String.prototype.replace() with RegExp /\w+/ to match aplhanumeric characters followed by alphanumeric characters, creating a variable to increase until 10 reaches

 var x = 10; $(".newsitem_text div").html(function(_, html) { var index = -1; return html.replace(/\w+/g, function(match) { ++index; return index === x ? ' <img src="https://www.google.com.br/logos/doodles/2015/adolphe-saxs-201st-birthday-6443879796572160.2-res.png" /> ' : match }) }) 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div style="width:1000px; margin-left:auto; margin-right:auto" class="newsitem_text"> <div style="width:980px; margin-left:auto; margin-right:auto"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec pellentesque urna eu pulvinar maximus. Sed elit nunc, vestibulum ut eros vitae, pellentesque rhoncus ipsum. In et metus non diam porttitor maximus iaculis nec lectus. Quisque sodales scelerisque auctor. Nam rutrum venenatis eros, eu condimentum erat placerat ut. Pellentesque sed tempus sem, eu viverra ipsum. Vestibulum nec turpis convallis, dapibus massa vitae, posuere mauris. Suspendisse mattis tincidunt lorem. Aliquam erat volutpat. Nullam at tincidunt erat, maximus laoreet ipsum. </div> </div> 
+1
source

It seems impossible or just to do. Regex just removes the HTML tags, and other solutions do not help.

0
source

Source: https://habr.com/ru/post/1235433/


All Articles