Продолжать текст в отдельные параграфы <p>динамически?
Следующий Fiddle позволяет вставить текст в <textarea>
и сгенерирован в равные абзацы динамически <p>
состоящий из того же количества символов.
Возникает проблема; текст из предыдущих динамически сгенерированных абзацев <p>
переполняется в каждом теге и не переходит к следующему динамическому абзацу. Таким образом, можно ли пользователю нажать ввод и переместить этот контент вниз в следующий существующий абзац, сохраняя при этом существующее форматирование динамически и автоматически?
Если бы был предоставлен новый Fiddle, это было бы очень признательно, поскольку я все еще новичок в кодировании. Еще раз, Fiddle можно найти здесь.
Обновление: Возможно ли, как только будут созданы абзацы, чтобы пользователь нажал кнопку ввода и, если возможно, легко переместил свой контент в нижний абзац? А также для того, чтобы применить, когда нажата кнопка backspace, чтобы содержимое переместилось вверх в вышеприведенный абзац? Возникающая проблема заключается в том, что текст при нажатии enter, кажется, скрывает текст из-за свойства переполнения в 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>
Ответы
Ответ 1
чтобы пользователь мог нажать Enter и переместить этот контент вниз следующий существующий пункт, сохраняя при этом существующие форматирование динамически и автоматически
Если я правильно вас понимаю, то, что вы хотите, состоит в том, что после того, как текст будет разделен на абзацы, а затем пользователь добавит текст в один из них и нажимает Enter, тогда оставшийся текст должен перетекать в следующие абзацы, распространяющие переполняющий текст поровну, как было сделано ранее.
Аналогично, когда пользователь нажимает BackSpace в начале абзаца, текст снова возвращается к предыдущему абзацу с переполняющим текстом, распределенным по другим пунктам, равно как и ранее.
Как алгоритм, вам нужно что-то вроде этого:
- Разделить исходный текст на равные куски и распределить по абзацам, создавая эти
p
динамически, как требуется.
- Слушайте событие
keyup
для этих p
элементов
- Если нажата клавиша Enter,
- 3.1 Извлечь оставшийся текст, где был нажат Enter
- 3.2 Извлечь текст из следующих всех абзацев, добавить с переполненным текстом, извлеченным выше
- 3.3 Удалите следующие пункты и распределите комбинированный текст так же, как мы сделали на шаге 1
- Если нажата клавиша BackSpace,
- 4.1. Проверьте, находится ли он в начале абзаца и есть ли предыдущий абзац
- 4.2 Извлеките текст абзаца и добавьте текст из следующих всех абзацев
- 4.3 Удалите следующие все абзацы, включая текущий, и добавьте извлеченный текст в предыдущий параграф.
- 4.4 Распределите комбинированный текст так же, как мы сделали на шаге 1
С помощью этого грубого алгоритма вы можете начать кодирование, которое может выглядеть примерно так:
Примечание 1. Это все JavaScript, а не jQuery.
Примечание 2. Это слишком упрощено, вам нужно будет еще больше оптимизировать и выработать все краевые случаи.
Кэшировать требуемые элементы и связывать обработчики событий:
var btn = document.getElementById('go'),
textarea = document.getElementById('textarea1'),
content = document.getElementById('content');
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);
Распределите исходный текст из textarea
, удалив существующие абзацы, если таковые имеются:
function initialDistribute() {
var text = textarea.value;
while (content.hasChildNodes()) { content.removeChild(content.lastChild); }
rearrange(text);
}
Логика для реорганизации/распределения текста путем динамического создания требуемого количества абзацев:
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);
});
}
Примечание 3. Я использовал 100 символов для разделения текста для этого примера. Кроме того, это не позаботится о пространствах и разделит слова между ними. Вам нужно будет сделать это в своем коде. (# см. ниже)
Обработчик событий для захвата ключей Enter (keycode 13) и BackSpace (keycode 8). Также посмотрите, является ли элемент элементом 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) { return; }
...
Получить позицию курсора, чтобы определить, было ли нажато BackSpace в начале абзаца или нет:
position = window.getSelection().getRangeAt(0).startOffset;
Если было нажато Enter, извлеките текст после последнего дочернего элемента текущего абзаца (contenteditable будет выдавать div
при нажатии Enter), удалите этот node, добавьте оставшийся текст всех абзацев, которые после этого и удалите оставшиеся абзацы.
if (key == 13) {
fragment = para.lastChild; overflow = fragment.textContent;
fragment.parentNode.removeChild(fragment);
remainingText = overflow + removeSiblings(para, false);
rearrange(remainingText);
}
Если нажата кнопка BackSpace, проверьте, есть ли предыдущий абзац и что курсор был в начале. Если да, извлеките оставшийся текст из всех последующих абзацев (включая текущий), удалив их:
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;
}
Объединяя это вместе, вот рабочий фрагмент:
Отрывок:
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>
Ответ 2
Очень просто, если я правильно вас понимаю.
$(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>
Ответ 3
D3 на самом деле вполне подходит для этого. Если вы правильно поняли, добавление и удаление элементов <p>
должны появляться и исчезать естественным образом при редактировании.
Это немного грубо, но в приведенном ниже примере новый абзац "обнаружен" после вставки двух новых строк. Значение <textarea>
соответствует .split()
по этим критериям и применяется к <div>
справа как массив data()
. Поэтому для каждого элемента данных мы просто вводим/выходим/обновляем элементы <p>
. Мы получаем приятные и легкие дополнения и удаления, когда мы редактируем текст без большого количества промахов DOM.
С некоторой переработкой вы могли бы, вероятно, объединить <textarea>
и <p>
в редактор wysiwyg...
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>
Ответ 4
Пожалуйста, проверьте fiddle. Я добавил код для прослушивания клавиши <p>
, нажав клавишу и выполнил требуемую текстовую манипуляцию.
$(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>
Ответ 5
можете проверить это Fiddle. Ну, я не уверен, что это то, что ты хотел. Я просто добавляю событие в редактируемый абзац для управления желаемым выходом.
$(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>
Ответ 6
Привяжите это событие к каждому абзацу,
$('.text').bind("DOMSubtreeModified", function () {
var text = $(this).html();
var newLineIndex = text.indexOf(' ');
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>');
}
}
});
Итак, весь ваш код должен выглядеть так:
$(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(' ');
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);
Пожалуйста, не стесняйтесь задавать любые сомнения по этому поводу.
Ответ 7
Я думаю, что свойство CSS: white-space: pre-wrap
может быть тем, что вы ищете:
https://jsfiddle.net/dbz3mwsb/1
Ответ 8
Если я правильно понял ваш вопрос, вы можете добавить что-то вроде этого:
$('#text_land').keyup(function(e) {
if(e.keyCode == '13') {
$(this).append("<br><br><p contenteditable='true' class='text'></p>");
$('p.text:last-child').focus();
}
});
Затем, когда вы печатаете, он будет генерировать новые поля "на лету" всякий раз, когда пользователь нажимает "Enter". Вот полный пример: https://jsfiddle.net/2hcfbp2h/6/
Ответ 9
Построитель абзацев пакета npm разбивает непрерывный текст на равномерно распределенные абзацы с одинаковым количеством слов. Вы можете определить количество слов для абзацев.
Этот скрипт узла построителя абзацев генерирует абзацы из непрерывного текста. Он выводит текст, в котором размер каждого абзаца примерно одинаков, обеспечивая равномерное распределение абзацев в тексте. Он не разбивает текст на числа, такие как "1.2".
Существует возможность определить символ разрыва между абзацами, или вы можете извлечь абзацы в массив строк, из которого вы можете применить html-тег <p>
. Проверьте его документацию для дальнейшего уточнения.