Dave Dave - 6 months ago 33
jQuery Question

Stop Sentence After Full Stop Dynamically?

The following fiddle allows text to be imported into a

<textarea>
and dynamically generated into equal paragraphs.

Update 2: Is it possible for the paragraph to stop at the last sentence when the text is close to the set ChunkSize limit or user adjusted limit? Thank you.

Is it possible for each equal paragraph to end on the last full stop of that paragraph without breaking the paragraph into two paragraphs?

The element in JQuery on the following fiddle that controls the size per paragraph is the
ChunkSize
attribute.

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>



Answer

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.

Comments