1

The following fiddle allows text to be imported into a <textarea> and dynamically generated into equal paragraphs. Is it possible to break the text in to paragraphs without breaking the text in the middle of a sentence? I want the length of each paragraph to be at or near the ChunkSize or user-adjusted limit, with each paragraph's element on the page being the same height.

If an updated fiddle could please be provided, would be extremely helpful, as I am still new to coding.

Thank You!

Fiddle

$(function() {
    $('select').on('change', function() {
        //Lets target the parent element, instead of P. P will inherit it's font size (css)
        var targets = $('#content'),
            property = this.dataset.property;
        targets.css(property, this.value);
        sameheight('#content p');
    }).prop('selectedIndex', 0);
});
var btn = document.getElementById('go'),
    textarea = document.getElementById('textarea1'),
    content = document.getElementById('content');
chunkSize = 100;
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);
content.addEventListener('paste', handlePaste);

function initialDistribute() {
    custom = parseInt(document.getElementById("custom").value);
    chunkSize = (custom > 0) ? custom : chunkSize;
    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.classList.add("Paragraph_CSS");
        para.setAttribute('contenteditable', true);
        para.textContent = str;
        content.appendChild(para);
    });
    sameheight('#content p');
}

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 handlePaste(e) {
    if (e.target.tagName != 'P') {
        return;
    }
    overflow = e.target.textContent + 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;
}
#text_land {
  border: 1px solid #ccc;
  padding: 25px;
  margin-bottom: 30px;
}

textarea {
  width: 95%;
}

label {
  display: block;
  width: 50%;
  clear: both;
  margin: 0 0 .5em;
}

label select {
  width: 50%;
  float: right;
}

* {
  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: .5em;
}

p {
  /*Here the sliles for OTHER paragraphs*/
}

#content p {
  font-size: inherit;
  /*So it gets the font size set on the #content div*/
  padding: 1.2em .5em;
  margin: 1.4em 0;
  border: 1px dashed #aaa;
  overflow: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <h3>Import Text below, then press the button</h3>
  <textarea id="textarea1" placeholder="Type text here, then press the button below." rows="5">
  </textarea>
  <input style="width:200px;" id="custom" placeholder="Custom Characters per box">

  <br>

  <button style="width:200px;" id="go">Divide Text into Paragraphs</button>
</div>
<div>
  <h3 align="right">Divided Text Will Appear Below:</h3>
  <hr>
  <div id="content"></div>
</div>
Nick Bartlett
  • 4,865
  • 2
  • 24
  • 37
Dave
  • 766
  • 9
  • 26
  • ReferenceError: sameheight is not defined ??? fiddle error – Ranjeet Singh May 19 '16 at 10:07
  • @RanjeetSingh The problem should now be resolved. Thank You. – Dave May 19 '16 at 10:10
  • you may use php str_replace() – Dhaval Chheda May 19 '16 at 10:16
  • kindly refer http://stackoverflow.com/questions/7497608/remove-text-after-last-full-stop – RRR May 19 '16 at 10:19
  • @RRR Hi, Thanks for your input into helping resolve the issue. However, as specified by the ChunkSize element and the input field, there is a limit of how much characters are in each paragraph. Is it possible to stop at the last sentence when the text is close to the ChunkSize limit? Thank you. – Dave May 19 '16 at 10:21
  • you mean last para should not break as per the chunk size and should publish – RRR May 19 '16 at 10:55
  • @RRR Each paragraph should publish however, include the full last sentence of each paragraph. – Dave May 19 '16 at 11:02
  • @Dave Can you include some sample text? I'm confused by what you mean by `paragraph`. The description has at least 2 uses of `paragraph` that don't align with the most common uses of the word, either as a part of English grammar or within an HTML document (`

    ` tag).

    – Michael Gaskill May 23 '16 at 20:07
  • @MichaelGaskill When each paragraph is generated dynamically according to the character count it must stop at the end of a sentence before generating a new paragraph. Therefore each paragraph ends with a sentence and that sentence is not split or overflowed into the next paragraph. Thank You! – Dave May 23 '16 at 20:12
  • @Dave What is a paragraph in this case? How do I know when one paragraph ends and another begins? It is simply the count of characters, +/- the full stop within reasonable distance of the chunk size? – Michael Gaskill May 23 '16 at 20:16
  • @MichaelGaskill Yes, this is correct. – Dave May 23 '16 at 20:17

1 Answers1

2

You can take the approach of splitting the text in to sentences, and then adding sentences to the paragraphs until you reach the desired length (chunkSize in your code).

function splitText (text) {
    var paragraph     = "",
        paragraphs    = [],
        sentenceRegex = /[^\.!\?]+([\.!\?]+|\s*$)/g,
        sentences     = text.match(sentenceRegex);

    sentences.forEach(function createParagraphs (sentence, index) {
        paragraph += sentence;

        if (paragraph.length >= chunkSize || index === sentences.length - 1) {
            paragraphs.push(paragraph);
            paragraph = "";
        }
    });

    return paragraphs.length === 0 ? [text] : paragraphs;
}

https://jsfiddle.net/DirectCtrl/95kuyw4g/4/ (Tried to keep the rest of the code as similar to what it was as possible).

This doesn't deal with margins (meaning you could potentially get much longer paragraphs if you have sentences which end near the boundaries or go well beyond the boundary limit), though those kinds of problems are very likely to appear regardless on edge cases (e.g. with a chunkSize of 100 characters, what do you do when the first sentence is 40 characters and the second is 160 characters?). Tweaking this to use a margin should be pretty trivial, though, if that is a requirement. As the number of characters per paragraph increases, this would become less of an issue.

Nick Bartlett
  • 4,865
  • 2
  • 24
  • 37
  • However, this code repeats the same sentence over and over again. Is it possible for the paragraphs to still remain the same and include the last sentence that will fit into that paragraph before moving onto the next paragraph? Thank You! – Dave May 23 '16 at 21:35
  • Should work now, had an issue with how the paragraphs were being built out. – Nick Bartlett May 23 '16 at 21:49
  • Thank you for your help so far. However, each paragraph needs to be the same height as the previous paragraph. Therefore, can automatic padding be applied when the paragraphs are generated and when the user customizes the character amount? Thank You! – Dave May 23 '16 at 22:33
  • Separate problem, but it's definitely possible - http://stackoverflow.com/a/1056225/1759514. Can update the answer if you want to add the necessary code. I thought that your `sameheight` function which seemed to be excluded from the code in your post might do this. – Nick Bartlett May 23 '16 at 22:40
  • Sure thing. Updated the code with some jQuery to run the resizing on update, and fixed the sentence regex to work when the input text doesn't end in a sentence-end character: https://jsfiddle.net/DirectCtrl/95kuyw4g/4/. Will update the code above. – Nick Bartlett May 23 '16 at 23:28