skip to Main Content

I’m trying to insert a random length span into random places within a paragraph tag using jQuery. Think "REDACTED" text within a document.

Here’s what I’ve done so far:

$(document).ready(function() {
  var xx = Math.floor(Math.random() * (14 - 4 + 1) + 4);
  for (var i = 0; i < xx; i++) {
    var $newsp = $('<span class="blackout">&nbsp;&nbsp;</span>');
    $("p").append($newsp);
  }
});
body {
  font: normal normal 400 14pt/1.15em 'Courier New', monospace;
}

.blackout {
  color: #000;
  background-color: #000;
}

.ins {
  width: 100%;
  max-width: 1400px;
  margin: 0 auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="ins">
  <p>To forgive is to set a prisoner free and discover that the prisoner was you. You gain strength, courage and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.</p>
  <p>The unexamined life is not worth living. You gain strength, courage and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.</p>
  <p>Nothing is a waste of time if you use the experience wisely. A man who won't die for something is not fit to live.</p>
</div>

2

Answers


  1. Here’s a solution.

    $(document).ready(function() {
      // Function to generate a random number
      function random(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }
    
      $(".ins p").each(function() {
        var paragraph = $(this).text();
        var words = paragraph.split(" ");
        var newContent = "";
    
        for (var i = 0; i < words.length; i++) {
          // Randomly decide whether to redact this word
          if (Math.random() < 0.3) { // 30% chance to redact
            var blackoutLength = random(3, words[i].length);
            var blackedOutText = "<span class='blackout'>" + "&nbsp;".repeat(blackoutLength) + "</span>";
            newContent += blackedOutText + " ";
          } else {
            newContent += words[i] + " ";
          }
        }
    
        // Set the new content with redacted words
        $(this).html(newContent.trim());
      });
    });
    body {
      font: normal normal 400 14pt/1.15em 'Courier New', monospace;
    }
    
    .blackout {
      color: #000;
      background-color: #000;
    }
    
    .ins {
      width: 100%;
      max-width: 1400px;
      margin: 0 auto;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <div class="ins">
      <p>To forgive is to set a prisoner free and discover that the prisoner was you. You gain strength, courage and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.</p>
      <p>The unexamined life is not worth living. You gain strength, courage and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.</p>
      <p>Nothing is a waste of time if you use the experience wisely. A man who won't die for something is not fit to live.</p>
    </div>

    Thanks to @david for the idea.
    The script starts by splitting each paragraph’s text into an array of words using the split(" ") method.
    A loop iterates through each word, and a random decision is made (with a 30% chance) whether to redact the word. If it’s chosen to be redacted, a <span> element with a random length of spaces is added in place of the word.
    After processing all words, the new content (which includes redacted words) is set as the HTML of the original paragraph using $(this).html(newContent.trim()).

    Login or Signup to reply.
  2. I created a jQuery plugin below that will redact words by looking for non-zero-length text nodes.

    If it encounters one of these, it will:

    1. Extract the words
    2. Remove the node
    3. Append to the parent
      • A word or
      • Redacted span (25% chance)

    I avoided calling innerHTML and $.fn.html, and instead worked with the DOM.

    Note: I kept the text in the span for debugging purposes.

    Here it is in action:

    $(function() {
      $('.ins').redactWords(); // Call the plugin on the entire container
    });
    
    /* jQuery plugin: $.fn.redact */
    (function($) {
      $.fn.redactWords = function() {
        redactRecursive(this);
        return this;
      };
    
      function redactRecursive($el) {
        $el.each(function() {
          $(this).contents().each(function() {
            if (this.nodeType === Node.TEXT_NODE && this.textContent.trim()) {
              const parent = $(this).parent();  // Get the parent element
              const words = this.textContent.trim().split(/s+/);
              $(this).remove();  // Remove the original text node
              
              words.forEach((word, index) => {
                const chance = Math.random();
                if (chance < 0.25) {
                  $('<span>')
                    .addClass('redacted')
                    .css({ width: `${word.length}ch` })
                    .text(word) /* Keep for DEBUG */
                    .appendTo(parent);
                } else {
                  parent.append(document.createTextNode(word)); // Append text node to parent
                }
    
                // Append a space after the word unless it's the last one
                if (index < words.length - 1) {
                  parent.append(document.createTextNode(' '));
                }
              });
            } else if (this.nodeType === Node.ELEMENT_NODE) {
              redactRecursive($(this));
            }
          });
        });
      }
    })(jQuery);
    body {
      font: normal normal 400 14pt/1.15em 'Courier New', monospace;
    }
    
    .redacted {
      display: inline-block;
      height: 1rem;
      color: #000;
      background-color: #000;
      vertical-align: middle;
      color: yellow; /* Keep for DEBUG */
    }
    
    .ins {
      width: 100%;
      max-width: 1400px;
      margin: 0 auto;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <div class="ins">
      <p>To forgive is to set a prisoner free and discover that the prisoner was you. You gain strength, courage and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.</p>
      <p>The unexamined life is not worth living. You gain strength, courage and confidence by every experience in which you really stop to look fear in the face. You must do the thing which you think you cannot do.</p>
      <p>Nothing is a waste of time if you use the experience wisely. A man who won't die for something is not fit to live.</p>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search