36

The following fiddle allows text to be pasted into a <textarea> and generated into equal paragraphs dynamically <p> consisting of the same amount of characters.


The problem occurring is; text from previous dynamically generated paragraphs <p> overflows within each tag and does not continue to the next dynamic paragraph properly. Therefore, is it possible for the user to press enter and move that content down into the next existing paragraph, while still keeping the existing formatting dynamically and automatically?

If a new Fiddle could be provided, it would be very much appreciated, as I am still new to coding. Once again, the Fiddle can be found here.

Update: Is it possible for once the paragraphs are generated, for the user to press enter and if possible move their content down into the below paragraph seamlessly? And also for the same to apply when the backspace button is pressed, for the content to move up into the above paragraph? The problem occurring is, the text, when pressing enter, seems to hide the text due to the overflow property in css.


$(function() {
    $("#Go").on('click', function() {
        var theText = $('textarea').val();
        var numberOfCharacters = 300;
        while (theText.length) {
            while (theText.length > numberOfCharacters &&
                theText.charAt(numberOfCharacters) !== ' ') {
                numberOfCharacters++;
            }
            $("#text_land").append("<br><\/br><p>" + theText.substring(
                    0, numberOfCharacters) +
                "<\/p><br><\/br>");
            theText = theText.substring(numberOfCharacters);
            numberOfCharacters = 300;
            $('p').attr('contenteditable', 'true');
            $("p").addClass("text");
        }
    })
})
$('select').on('change', function() {
    var targets = $('#text_land p'),
        property = this.dataset.property;
    targets.css(property, this.value);
}).prop('selectedIndex', 0);
(end);
@media print {
    p {
        page-break-inside: avoid;
    }
}

p {
    position: relative;
}

@media print {
    .no-print,.no-print * {
        display: none !important;
    }
}

p {
    border-style: solid;
    color: #000;
    display: block;
    text-align: justify;
    border-width: 5px;
    font-size: 19px;
    overflow: hidden;
    height: 300px;
    width: 460px;
    word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


 <div align="center">
        <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4><br>
        <br>
        <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10">
</textarea><br>
        <br>
        <button id="Go">Divide Text into Paragraphs!</button>
    </div>
    <hr>
    <h2 align="center">Divided Text Will Appear Below:</h2>
    <div>
        <div align="center" id="text_land" style="font-family: monospace">
        </div>
    </div>
Cœur
  • 37,241
  • 25
  • 195
  • 267
Dave
  • 766
  • 9
  • 26
  • Do you actually need new paragraph tags wrapping each chunk of text, or do you need the appearance of space where there was previous space between paragraphs in the text? – Joshua Dec 17 '15 at 12:25
  • Did you actually try something by yourself ? – enguerranws Dec 17 '15 at 12:29
  • @Joshua - Each paragraph is created dynamically for each block of text. However, when the block of text is filled, the user may need to edit the text and may want to move the text from the previous paragraph to the new paragraph, to continue the text to flow into the next paragraph. – Dave Dec 17 '15 at 12:29
  • @enguerranws - Yes I have tried to solve this problem, however I am having difficulty solving this problem of flowing the text if the user needs to edit the generated paragraphs. – Dave Dec 17 '15 at 12:32
  • So, can you paste what you've tried so far ? – enguerranws Dec 17 '15 at 12:35
  • For example, if you fill the textarea with text and click the button, the text will continue into the second paragraph. However, when trying to edit the text and move it into the next paragraph such as pressing "enter", it will not flow into the paragraph and will disappear. – Dave Dec 17 '15 at 12:39
  • you might want to add some code to move some text when the content of your paragraphs change like this? http://stackoverflow.com/a/6263537/1328536 – fuchs777 Dec 17 '15 at 13:20
  • @Dave, do you want to edit the textarea or dynamically created paragraphs? I have checked your fiddle and sees that, the paragraphs allow user to create new line but with nested `
    ` only. Do you want to split the paragraph into two when user press enter from the paragraph?
    – Abhilash Augustine Dec 28 '15 at 04:27
  • Yes, the text needs to be split while still compensating for the existing text to flow into the boxes below or create a new paragraph tag. – Dave Dec 28 '15 at 07:06
  • Can you explain what you are trying to achieve and why you need to split the user text from a text box to paragraphs? It is an "exercise" or are you trying to create something for one of your project? If it is the latter, can you add some context? – Chris Cinelli Dec 29 '15 at 12:45

9 Answers9

6

possible for the user to press enter and move that content down into the next existing paragraph, while still keeping the existing formatting dynamically and automatically

If I understand you correctly, what you want is that once the text is divided into paragraphs, and then the user adds some text into one of them and presses Enter, then the remaining text should flow into the next paragraphs distributing the overflowing text equally as done earlier.

Similarly, when the user presses BackSpace at the start of the paragraph, then the text goes back into the previous paragraph again with the overflowing text distributed into the other paragraphs equally as done earlier.

As an algorithm, what you need is something like this:

  1. Divide initial text into equal chunks and distribute into paragraphs creating those ps dynamically as required.
  2. Listen to keyup event on those p elements
  3. If key pressed is Enter,
    • 3.1 Extract remaining text from where Enter was pressed
    • 3.2 Extract text from next all paragraphs, prepend with the overflowing text extracted above
    • 3.3 Remove next all paragraphs and distribute the combined text just like we did in step 1
  4. If key pressed is BackSpace,
    • 4.1 Check if it is in the beginning of the paragraph and if there is a preceding paragraph
    • 4.2 Extract the text of the paragraph and append to the text from next all paragraphs
    • 4.3 Remove next all paragraphs including the current one and append the extracted text to the preceding paragraph.
    • 4.4 Distribute combined text just like we did in step 1

With that rough algorithm, you can start coding which could look something like this:

Note 1: This is all JavaScript, no jQuery.
Note 2: This is overly simplified, you will need to further optimize and work out all the edge cases.

Cache required elements and bind event handlers:

var btn = document.getElementById('go'), 
    textarea = document.getElementById('textarea1'), 
    content = document.getElementById('content');

btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);

Distribute the initial text from the textarea removing existing paragraphs if any:

function initialDistribute() {
    var text = textarea.value;
    while (content.hasChildNodes()) { content.removeChild(content.lastChild); }
    rearrange(text);
}

Logic for re-aranging / distributing text by creating required number of paragraphs dynamically:

function rearrange(text) {
    var chunks = text.match(/.{1,100}/g) || [];
    chunks.forEach(function(str, idx) {
        para = document.createElement('P');
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
}

Note 3: I've used 100 characters to split text for this example. Also, this does not take care of spaces and will split the words in between. You will need to do that in your code. (# see edit below)

Event handler for trapping Enter (keycode 13) and BackSpace (keycode 8) keys. Also, see if the element is a p element :

function handleKey(e) {
    var para = e.target, position, 
        key, fragment, overflow, remainingText;
    key = e.which || e.keyCode || 0;
    if (para.tagName != 'P') { return; }
    if (key != 13 && key != 8) { return; }
    ...

Get the cursor position to determine whether BackSpace was pressed at the beginning of the paragraph or not:

position = window.getSelection().getRangeAt(0).startOffset;    

If Enter was pressed, extract text after the last child of the current paragraph (contenteditable will produce a div when Enteris pressed), remove that node, prepend the remaining text of all paragraphs which come after this, and remove the remaining paragraphs.

if (key == 13) {
    fragment = para.lastChild; overflow = fragment.textContent;
    fragment.parentNode.removeChild(fragment); 
    remainingText = overflow + removeSiblings(para, false);
    rearrange(remainingText);
}

If BackSpace was pressed, check if there is a preceding paragraph and that the cursor was at the beginning. If yes, extract remaining text from all succeeding paragraphs (including the current one) while removing them:

if (key == 8 && para.previousElementSibling && position == 0) {
    fragment = para.previousElementSibling;
    remainingText = removeSiblings(fragment, true);
    rearrange(remainingText);
}

Logic to extract text from succeeding paragraphs and removing those:

function removeSiblings(elem, includeCurrent) {
    var text = '', next;
    if (includeCurrent && !elem.previousElementSibling) { 
        parent = elem.parentNode; text = parent.textContent;
        while (parent.hasChildNodes()) { parent.removeChild(parent.lastChild); }
    } else {
        elem = includeCurrent ? elem.previousElementSibling : elem;
        while (next = elem.nextSibling) { 
            text += next.textContent; elem.parentNode.removeChild(next);
        }
    }
    return text;
}

Putting that all together, here is a working snippet:

Snippet:

var btn = document.getElementById('go'), 
 textarea = document.getElementById('textarea1'), 
 content = document.getElementById('content'), 
    chunkSize = 100;
    
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);

function initialDistribute() {
    var text = textarea.value;
    while (content.hasChildNodes()) {
        content.removeChild(content.lastChild);
    }
    rearrange(text);
}

function rearrange(text) {
    var chunks = splitText(text, false);
    chunks.forEach(function(str, idx) {
        para = document.createElement('P');
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
}

function handleKey(e) {
    var para = e.target, position, 
        key, fragment, overflow, remainingText;
    key = e.which || e.keyCode || 0;
    if (para.tagName != 'P') { return; }
    if (key != 13 && key != 8) { return; }
  position = window.getSelection().getRangeAt(0).startOffset;    
    if (key == 13) {
        fragment = para.lastChild;
        overflow = fragment.textContent;
        fragment.parentNode.removeChild(fragment); 
        remainingText = overflow + removeSiblings(para, false);
        rearrange(remainingText);
    }
    if (key == 8 && para.previousElementSibling && position == 0) {
        fragment = para.previousElementSibling;
        remainingText = removeSiblings(fragment, true);
        rearrange(remainingText);
    }
}

function removeSiblings(elem, includeCurrent) {
    var text = '', next;
    if (includeCurrent && !elem.previousElementSibling) { 
        parent = elem.parentNode; 
  text = parent.textContent;
        while (parent.hasChildNodes()) {
            parent.removeChild(parent.lastChild);
        }
    } else {
        elem = includeCurrent ? elem.previousElementSibling : elem;
        while (next = elem.nextSibling) { 
            text += next.textContent;
            elem.parentNode.removeChild(next);
        }
    }
    return text;
}

function splitText(text, useRegex) {
 var chunks = [], i, textSize, boundary = 0;
    if (useRegex) { 
        var regex = new RegExp('.{1,' + chunkSize + '}\\b', 'g');
        chunks = text.match(regex) || [];
    } else {
  for (i = 0, textSize = text.length; i < textSize; i = boundary) {
   boundary = i + chunkSize;
   if (boundary <= textSize && text.charAt(boundary) == ' ') {
    chunks.push(text.substring(i, boundary));
   } else {
    while (boundary <= textSize && text.charAt(boundary) != ' ') { boundary++; }
    chunks.push(text.substring(i, boundary));
   }
  }
 }
 return chunks;
}
* { box-sizing: border-box; padding: 0; margin: 0; }
body { font-family: monospace; font-size: 1em; }
h3 { margin: 1.2em 0; }
div { margin: 1.2em; }
textarea { width: 100%; }
button { padding: 0.5em; }
p { padding: 1.2em 0.5em; margin: 1.4em 0; border: 1px dashed #aaa; }
<div>
  <h3>Paste text in the field below to divide text into
        paragraphs..</h3>
  <textarea placeholder="Type text here, then press the button below." id="textarea1" rows="5" ></textarea><br/><br/>
  <button id="go">Divide Text into Paragraphs</button>
</div>
<hr>
<div>
  <h3>Divided Text Will Appear Below:</h3>
  <div id="content"></div>
</div>

And a Fiddle for you to play with:

Fiddle: https://jsfiddle.net/abhitalks/jwnnn5oy/


Edit 1:

Fixed the regex for breaking at word boundaries. Also added the non-regex procedural code for the same (on the lines of Op's original code), to demonstrate the Op on how to factor-in and integrate his other code segments into it.

Note 4: Regarding Op's comment of using jQuery, it has got nothing to do with the problem at hand. jQuery is nothing but JavaScript and should be trivial for them to incorporate pieces of snippet into the larger code base.

Change Set: Added function splitText.


Edit 2:

As per your comment, if you want the re-distribution to happen automatically as the user types... then you will need to calculate the length of the text in that paragraph and see if exceeds your chunk-size. If it does, then do the re-distribution from that paragraph onwards. Do the reverse for backspace.

I initially posted the solution for your requirement of doing that when user presses enter between any text to break and distribute that to succeeding paragraphs. I do not recommend doing that automatically as user types because the changes will be too jarring for the user.

Snippet 2:

var btn = document.getElementById('go'), 
 textarea = document.getElementById('textarea1'), 
 content = document.getElementById('content'), 
    chunkSize = 100;
    
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);

function initialDistribute() {
    var text = textarea.value;
    while (content.hasChildNodes()) {
        content.removeChild(content.lastChild);
    }
    rearrange(text);
}

function rearrange(text) {
    var chunks = splitText(text, false);
    chunks.forEach(function(str, idx) {
        para = document.createElement('P');
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
}

function handleKey(e) {
    var para = e.target, position, 
        key, fragment, overflow, remainingText;
    key = e.which || e.keyCode || 0;
    if (para.tagName != 'P') { return; }
    if (key != 13 && key != 8) { redistributeAuto(para); return; }
  position = window.getSelection().getRangeAt(0).startOffset;    
    if (key == 13) {
        fragment = para.lastChild;
        overflow = fragment.textContent;
        fragment.parentNode.removeChild(fragment); 
        remainingText = overflow + removeSiblings(para, false);
        rearrange(remainingText);
    }
    if (key == 8 && para.previousElementSibling && position == 0) {
        fragment = para.previousElementSibling;
        remainingText = removeSiblings(fragment, true);
        rearrange(remainingText);
    }
}

function redistributeAuto(para) {
 var text = para.textContent, fullText;
 if (text.length > chunkSize) {
  fullText = removeSiblings(para, true);
 }
 rearrange(fullText);
}

function removeSiblings(elem, includeCurrent) {
    var text = '', next;
    if (includeCurrent && !elem.previousElementSibling) { 
        parent = elem.parentNode; 
  text = parent.textContent;
        while (parent.hasChildNodes()) {
            parent.removeChild(parent.lastChild);
        }
    } else {
        elem = includeCurrent ? elem.previousElementSibling : elem;
        while (next = elem.nextSibling) { 
            text += next.textContent;
            elem.parentNode.removeChild(next);
        }
    }
    return text;
}

function splitText(text, useRegex) {
 var chunks = [], i, textSize, boundary = 0;
    if (useRegex) { 
        var regex = new RegExp('.{1,' + chunkSize + '}\\b', 'g');
        chunks = text.match(regex) || [];
    } else {
  for (i = 0, textSize = text.length; i < textSize; i = boundary) {
   boundary = i + chunkSize;
   if (boundary <= textSize && text.charAt(boundary) == ' ') {
    chunks.push(text.substring(i, boundary));
   } else {
    while (boundary <= textSize && text.charAt(boundary) != ' ') { boundary++; }
    chunks.push(text.substring(i, boundary));
   }
  }
 }
 return chunks;
}
* { box-sizing: border-box; padding: 0; margin: 0; }
body { font-family: monospace; font-size: 1em; }
h3 { margin: 1.2em 0; }
div { margin: 1.2em; }
textarea { width: 100%; }
button { padding: 0.5em; }
p { padding: 1.2em 0.5em; margin: 1.4em 0; border: 1px dashed #aaa; }
<div>
  <h3>Paste text in the field below to divide text into
        paragraphs..</h3>
  <textarea placeholder="Type text here, then press the button below." id="textarea1" rows="5" ></textarea><br/><br/>
  <button id="go">Divide Text into Paragraphs</button>
</div>
<hr>
<div>
  <h3>Divided Text Will Appear Below:</h3>
  <div id="content"></div>
</div>

Fiddle 2: https://jsfiddle.net/abhitalks/hvhr4ds8/

Note 5: In the fiddle first hit enter to break some text in between so that you are able to see how re-distribution happens as you type. Also, note that because of the logic of not breaking a word, it will take a few more characters before it re-distributes.

Change Set: Added function redistributeAuto.

Abhitalks
  • 27,721
  • 5
  • 58
  • 81
  • I have managed to add a space between each paragraph using the margin settings in css for the

    tag and have also read thoroughly through the information above. However, I have had difficulty in resolving the problem with the characters from the words missing. Also, I have tried combining the JQuery from the original code and have been unable to solve this issue. Is it possible to resolve this issue as I have been unsuccessful in trying to implement a solution and am still new to coding? Thank You. https://jsfiddle.net/InnovativeDave/jwnnn5oy/4/

    – Dave Dec 29 '15 at 15:53
  • @Dave: That's great. Appreciate your effort. Regarding incorporating word breaks, I shall be able look at it after around 12 hours or so (it's nearly midnight in this part of the world). And jQuery shouldn't be a problem as it is JavaScript. – Abhitalks Dec 29 '15 at 16:03
  • @Dave: There. I've edited the answer to resolve word-breaks. – Abhitalks Dec 30 '15 at 07:38
  • However, there is still one problem that needs to be resolved. As the text is filled in each paragraph, when a user adds more text through contenteditable="true", it overflows and does not flow into the next paragraph and hides under each divided section. Is it possible to resolve this issue using the maxlength attribute or similar element? – Dave Dec 30 '15 at 10:49
  • @Dave: `maxlength` won't work as it will restrict number of characters, but you do not want words to break. Also, distribution of text will then produce unexpected results. I've added another edit to the answer. Basically, you can call the redistribute code on every keypress if the length of text exceeds chunksize. – Abhitalks Dec 30 '15 at 11:18
  • Thanks for the update. However, when pasting text into a generated

    paragraph, text still remains and overflows. Is it possible to remove the overflow attribute for the text to flow better into each paragraph rather than disappearing underneath each paragraph?

    – Dave Dec 31 '15 at 08:11
  • @Dave: Look again at the code. When is the text being redistributed? When the user types, presses enter or presses backspace. Right? How? By handling the keyup event. So, now ask yourself.. what event you also need to handle in order to do the same when paste occurs? – Abhitalks Dec 31 '15 at 09:24
  • I have tried using the following in order to ensure the paste event does not allow the text to overflow underneath the existing paragraph. if (key != 86 && ctrlKey) However this does not seem to be working. Please see https://jsfiddle.net/hvhr4ds8/4/ for a better understanding of this problem. Is it possible to resolve this issue as I have attempted using "key != 87 && ctrlKey" and this does not seem to be working successfully? – Dave Dec 31 '15 at 14:46
  • Why would you look for keycode and ctrl for this when you can handle the `paste` event directly??? Check my updated fiddle again - https://jsfiddle.net/abhitalks/hvhr4ds8/ @Dave: It is becoming increasingly clear that you do not have enough skills with JavaScript. I would suggest that you first learn and acquire basic skills using JavaScript before attempting a project of this level. – Abhitalks Dec 31 '15 at 15:49
1

Very simple, if I understand you correctly.

$(function() {
    $("#Go").on('click', function() {
        var theText = $('textarea').val();
        var paragraphs = theText.split('\n\n');
        $("#text_land").html('');
        paragraphs.forEach(function(paragraph) {
          var lines = paragraph.split('\n');
          $('<p class="text" contenteditable />').html(lines.join('<br>')).appendTo("#text_land");
        });
    })
})
$('select').on('change', function() {
    var targets = $('#text_land p'),
        property = this.dataset.property;
    targets.css(property, this.value);
}).prop('selectedIndex', 0);
(end);
@media print {
    p {
        page-break-inside: avoid;
    }
}

p {
    position: relative;
}

@media print {
    .no-print,.no-print * {
        display: none !important;
    }
}

p {
    border-style: solid;
    color: #000;
    display: block;
    text-align: justify;
    border-width: 5px;
    font-size: 19px;
    overflow: hidden;
    height: 300px;
    width: 460px;
    word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


 <div align="center">
        <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4><br>
        <br>
        <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10">
</textarea><br>
        <br>
        <button id="Go">Divide Text into Paragraphs!</button>
    </div>
    <hr>
    <h2 align="center">Divided Text Will Appear Below:</h2>
    <div>
        <div align="center" id="text_land" style="font-family: monospace">
        </div>
    </div>
Louay Alakkad
  • 7,132
  • 2
  • 22
  • 45
1

D3 is actually quite well suited to this. If I understand you correctly, the addition and removal of <p> elements should appear and disappear naturally while editing.

It's a bit rough, but in the example below a new paragraph is 'detected' after the insertion of two new lines. The <textarea> value is .split() against that criteria and applied to the <div> on the right as it's data() array. So for each element in the data, we just enter/exit/update <p> elements. We get nice and easy additions and removals as we edit the text without a lot of DOM thrashing.

With some reworking, you could probably merge the <textarea> and the <p> into a 'wysiwyg' editor of sorts...

var text = '';
var break_char = '\n\n';
var editor = d3.select('.editor');
var output = d3.select('.output');

function input_handler () {

  text = editor.node().value;

  var paragraphs = output.selectAll('.paragraph')
    .data(text.split(break_char));

  paragraphs.enter()
    .append('p')
    .attr('class', 'paragraph')
    .style('opacity', 0);

  paragraphs.exit().remove();

  paragraphs
    .text(function (d) { return d })
    .transition()
    .duration(300)
    .style('opacity', 1);
}

editor.on('input', input_handler);
body {
  vertical-align: top;
  height: 100%;
  background-color: #eee;
}
body * {
  box-sizing: border-box;
  font-family: arial;
  font-size: 0.8rem;
  margin: 0.5rem;
  padding: 0.5rem;
}
.input,
.output {
  display: inline-block;
  position: absolute;
  top: 0;
  height: auto;
}
.input {
  left: 0;
  right: 50%;
}
.output {
  left: 50%;
  right: 0;
}
.editor {
  display: inline-block;
  border: 0;
  width: 100%;
  min-height: 10rem;
  height: 100%;
}
.paragraph {
  background-color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div>
  <div class='input'>
    <textarea class='editor' placeholder='write away...'></textarea>
  </div>
  <div class='output'></div>
</div>
Will
  • 453
  • 4
  • 8
  • Thanks for the updated code using D3. However, this version does not split the paragraphs after the 300 character limit and also when typing text in the textarea, text will eventually go out of the white paragraph space and does not continue underneath in each paragraph. Is it possible for these issues to be fixed? – Dave Dec 24 '15 at 00:37
  • Before I go any further, I'd like your test data or whatever you're typing in so that I can generate exactly the results you're seeing. Could you please also provide some context so I can more fully understand the problem space? I'm not clear on exactly what or why the new paragraph criteria are or when exactly they are expected to occur. – Will Dec 24 '15 at 06:14
  • Please see the updated fiddle, https://jsfiddle.net/InnovativeDave/j56c03ub/, using your code with the test data text. What I would like to occur is the text pasted is divided into a 300 character limit per paragraph

    and the reason why it needs to include the enter and backspace functionality is in case the user requires more room in one of the paragraphs where they may want to add more text. Also when they press enter, I would like it for the text from the previous paragraph to flow into the paragraph below, still consisting of 300 character, where it may need to create a new paragraph.

    – Dave Dec 24 '15 at 11:01
1

Please, check the fiddle. I added some code to listen to <p> elements key press and do the required text manipulation.

$(function() {
  $("#Go").on('click', function() {
    var $p, a = [];
    var theText = $('textarea').val();
    var numberOfCharacters = 300;
    while (theText.length) {
      while (theText.length > numberOfCharacters &&
        theText.charAt(numberOfCharacters) !== ' ') {
        numberOfCharacters++;
      }

      $p = $("<p contenteditable class='text'>" + theText.substring(0, numberOfCharacters) + "<\/p>")
        .on('keydown', function(e) {
          var p = this;
          setTimeout(function() {
            if (e.which === 13) {
              var i;
              var k = $(p).html().split('<br>');
              if ((i = a.indexOf(p)) > -1 && a[i + 1])
                $(a[i + 1]).html(k.pop() + ' ' + $(a[i + 1]).html());

              $(p).html(k.join('<br>'));
            }
          });
        });

      a.push($p.get(0));

      $("#text_land").append("<br><\/br>", $p, "<br><\/br>");

      theText = theText.substring(numberOfCharacters);
      numberOfCharacters = 300;
    }
  })
})
$('select').on('change', function() {
  var targets = $('#text_land p'),
    property = this.dataset.property;
  targets.css(property, this.value);
}).prop('selectedIndex', 0);
//(end);
@media print {
  p {
    page-break-inside: avoid;
  }
}
p {
  position: relative;
}
@media print {
  .no-print,
  .no-print * {
    display: none !important;
  }
}
p {
  border-style: solid;
}
p {
  color: #000;
}
p {
  display: block;
  text-align: justify;
  border-width: 5px;
  font-size: 19px;
}
p {
  overflow: hidden;
  height: 300px;
  width: 460px;
  word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div align="center">
  <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4>
  <br>
  <br>
  <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10">
  </textarea>
  <br>
  <br>
  <button id="Go">Divide Text into Paragraphs!</button>
</div>
<hr>
<h2 align="center">Divided Text Will Appear Below:</h2>
<div>
  <div align="center" id="text_land" style="font-family: monospace">
  </div>
</div>
Eugene Tiurin
  • 4,019
  • 4
  • 33
  • 32
  • What I would like to occur is the text pasted is divided into a 300 character limit per paragraph

    and needs to include the enter and backspace functionality is in case the user requires more room in one of the paragraphs where they may want to add more text. However, this code does not flow content into the next paragraph on edit and hides the text below each dynamic

    tag. Is it possible to fix these issues?

    – Dave Dec 25 '15 at 12:22
1

can you check this Fiddle. Well I'm not sure if this is what you wanted. I just add event on the editable paragraph to control the desired output.

$(function() {
  $("#Go").on('click', function() {
    var theText = $('textarea').val();
    var numberOfCharacters = 300;
    while (theText.length) {
      while (theText.length > numberOfCharacters &&
        theText.charAt(numberOfCharacters) !== ' ') {
        numberOfCharacters++;
      }
      $("#text_land").append("<br><\/br><p>" + theText.substring(
          0, numberOfCharacters) +
        "<\/p><br><\/br>");
      theText = theText.substring(numberOfCharacters);
      numberOfCharacters = 300;
      $('p').attr('contenteditable', 'true');
      $("p").addClass("text");
    }
  })
});
$(document).on('keyup', 'p.text', function(e) {
  if (e.keyCode == 13) {
    var extend = $(this).find("div").html();
    $(this).next().next().next().next().next().prepend(extend).focus();
    $(this).find("div").remove();
  }
});
$('select').on('blur keyup paste', function() {
  var targets = $('#text_land p'),
    property = this.dataset.property;
  targets.css(property, this.value);
}).prop('selectedIndex', 0);
(end);
@media print {
  p {
    page-break-inside: avoid;
  }
}
p {
  position: relative;
}
@media print {
  .no-print,
  .no-print * {
    display: none !important;
  }
}
p {
  border-style: solid;
}
p {
  color: #000;
}
p {
  display: block;
  text-align: justify;
  border-width: 5px;
  font-size: 19px;
}
p {
  overflow: hidden;
  height: 300px;
  width: 460px;
  word-wrap: break-word;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<div align="center">
  <h4 align="center"><u>Paste text in the field below to divide text into
        paragraphs.</u></h4>
  <br>
  <br>
  <textarea placeholder="Type text here, then press the button below." cols="50" id="textarea1" rows="10"></textarea>
  <br>
  <br>
  <button id="Go">Divide Text into Paragraphs!</button>
</div>
<hr>
<h2 align="center">Divided Text Will Appear Below:</h2>
<div>
  <div align="center" id="text_land" style="font-family: monospace">
  </div>
</div>
Markipe
  • 616
  • 6
  • 16
  • However, when one of the dynamic paragraphs is filled the text needs to overflow to the next paragraph tag and the user may want to add a space between the paragraph text within one of the boxes. Therefore, while this code does move text to the next box, overflown text is still not visible and moves an entire section of text to the next box, rather than compensating the existing text to ensure it fits into each box equally. – Dave Dec 28 '15 at 07:04
1

Bind this event to your each paragraph,

$('.text').bind("DOMSubtreeModified", function () {
                        var text = $(this).html();
                        var newLineIndex = text.indexOf('&nbsp;');
                        if (newLineIndex != -1) {
                            var currentP = text.substring(0, newLineIndex);
                            var newP = text.substring(newLineIndex + 11, text.length - 6);
                            $(this).html(currentP);
                            var nextElement = $(this).next();
                            if (nextElement != null) {
                                // append rest of line to next paragraph
                                nextPara = newP + nextElement.html();
                                nextElement.html(nextPara);
                            }
                            else {
                                // Else, create new paragraph
                                $(this).after('<br><\/br> <p contenteditable="true" class="text">' + newP + '</p>');
                            }
                        }
                    });

So, your whole code should be look like this,

$(function () {
            $("#Go").on('click', function () {
                var theText = $('textarea').val();
                var numberOfCharacters = 300;
                while (theText.length) {
                    while (theText.length > numberOfCharacters &&
                        theText.charAt(numberOfCharacters) !== ' ') {
                        numberOfCharacters++;
                    }
                    $("#text_land").append("<br><\/br><p>" + theText.substring(
                            0, numberOfCharacters) +
                        "<\/p><br><\/br>");
                    theText = theText.substring(numberOfCharacters);
                    numberOfCharacters = 300;
                    $('p').attr('contenteditable', 'true');
                    $("p").addClass("text");

                    $('.text').bind("DOMSubtreeModified", function () {
                        var text = $(this).html();
                        var newLineIndex = text.indexOf('&nbsp;');
                        if (newLineIndex != -1) {
                            var currentP = text.substring(0, newLineIndex);
                            var newP = text.substring(newLineIndex + 11, text.length - 6);
                            $(this).html(currentP);
                            var nextElement = $(this).next();
                            if (nextElement != null) {
                                // append rest of line to next paragraph
                                nextPara = newP + nextElement.html();
                                nextElement.html(nextPara);
                            }
                            else {
                                // Else, create new paragraph
                                $(this).after('<br><\/br> <p contenteditable="true" class="text">' + newP + '</p>');
                            }
                        }
                    })
                }
            })
        })
        $('select').on('change', function () {
            var targets = $('#text_land p'),
                property = this.dataset.property;
            targets.css(property, this.value);
        }).prop('selectedIndex', 0);

Please feel free to ask any doubt on this.

Abhilash Augustine
  • 4,128
  • 1
  • 24
  • 24
  • However, this code does not seem to be working correctly. Is it possible for once the paragraphs are generated, for the user to press enter and if possible move their content down into the below paragraph seamlessly? And also for the same to apply when the backspace button is pressed, for the content to move up into the above paragraph? The problem occurring is, the text, when pressing enter, seems to hide the text due to the overflow property in css. – Dave Dec 29 '15 at 12:26
0

I think the CSS property: white-space: pre-wrap might be what you're looking for:

https://jsfiddle.net/dbz3mwsb/1

Joshua
  • 6,320
  • 6
  • 45
  • 62
0

In case I understand your question correctly, you could add something like this:

$('#text_land').keyup(function(e) {
  if(e.keyCode == '13') {
    $(this).append("<br><br><p contenteditable='true' class='text'></p>");
    $('p.text:last-child').focus();
  }
});

Then when you are typing, it will generate new boxes on the fly whenever the user hits enter. Here's the full example: https://jsfiddle.net/2hcfbp2h/6/

zpr
  • 2,886
  • 1
  • 18
  • 21
  • However, the goal is if the text from the previous boxes overflows, the user can hit enter to move that content down into a new box. This also applies if the user presses the backspace button to revert their changes. – Dave Dec 21 '15 at 08:10
0

The npm package paragraph-builder splits continued text into paragraphs evenly distributed and all approximately with the same size in number of words. You can define the number of words for the paragraphs.

This paragraph builder node script generates paragraphs from continuous text. It outputs a text wherein the size of each paragraph is approximately the same, providing an even distribution of paragraphs within the text. It doesn't split the text on numbers such as "1.2".

There is an option to define the break character between paragraphs or you can fetch the paragraphs into an array of strings from which you can apply the html tag <p>. Check its documentation for further clarification.

João Pimentel Ferreira
  • 14,289
  • 10
  • 80
  • 109