possible pour l'utilisateur d'appuyer sur la touche Entrée et le prochain paragraphe existant, tout en le formatage existant de manière dynamique et automatique
Si je comprends bien, ce que vous voulez, c'est qu'une fois que le texte est divisé en paragraphes, l'utilisateur ajoute du texte dans l'un d'eux et appuie sur Enter Le reste du texte doit alors s'écouler dans les paragraphes suivants en répartissant le texte qui déborde de manière égale, comme cela a été fait précédemment.
De même, lorsque l'utilisateur appuie sur BackSpace au début du paragraphe, puis le texte retourne à nouveau dans le paragraphe précédent, le texte débordant étant réparti dans les autres paragraphes de la même manière que précédemment.
En tant qu'algorithme, ce dont vous avez besoin est quelque chose comme ceci :
- Divisez le texte initial en morceaux égaux et répartissez-les dans des paragraphes en créant ceux qui sont les plus appropriés.
p
de manière dynamique, selon les besoins.
- Ecoutez
keyup
sur ces p
éléments
- Si la touche pressée est Enter ,
- 3.1 Extraire le texte restant de l'endroit où Enter a été pressé
- 3.2 Extraire le texte de tous les paragraphes suivants, le faire précéder du texte débordant extrait ci-dessus.
- 3.3 Supprimez ensuite tous les paragraphes et distribuez le texte combiné comme nous l'avons fait à l'étape 1.
- Si la touche pressée est BackSpace ,
- 4.1 Vérifier si elle se trouve au début du paragraphe et s'il y a un paragraphe précédent.
- 4.2 Extraire le texte du paragraphe et l'ajouter au texte de tous les paragraphes suivants
- 4.3 Supprimer ensuite tous les paragraphes, y compris le paragraphe actuel, et ajouter le texte extrait au paragraphe précédent.
- 4.4 Distribuez le texte combiné comme nous l'avons fait à l'étape 1.
Avec cet algorithme approximatif, vous pouvez commencer à coder, ce qui pourrait ressembler à quelque chose comme ceci :
Note 1 : C'est tout JavaScript, pas de jQuery.
Note 2 : C'est trop simplifié, vous devrez optimiser davantage et résoudre tous les cas limites.
Mettez en cache les éléments requis et liez les gestionnaires d'événements :
var btn = document.getElementById('go'),
textarea = document.getElementById('textarea1'),
content = document.getElementById('content');
btn.addEventListener('click', initialDistribute);
content.addEventListener('keyup', handleKey);
Distribuez le texte initial de la textarea
supprimer les paragraphes existants, le cas échéant :
function initialDistribute() {
var text = textarea.value;
while (content.hasChildNodes()) { content.removeChild(content.lastChild); }
rearrange(text);
}
Logique pour réorganiser / distribuer le texte en créant dynamiquement le nombre requis de paragraphes :
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 : J'ai utilisé 100 caractères pour diviser le texte pour cet exemple. De plus, cette méthode ne tient pas compte des espaces et divisera les mots entre eux. Vous devrez le faire dans votre code. (# voir modification ci-dessous)
Gestionnaire d'événements pour piéger Enter ( code clé 13 ) et BackSpace ( code clé 8 ). Vérifiez également si l'élément est un p
élément :
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; }
...
Obtenir la position du curseur pour déterminer si BackSpace a été appuyé au début du paragraphe ou non :
position = window.getSelection().getRangeAt(0).startOffset;
Si Enter a été pressé, extraire le texte après le dernier enfant du paragraphe actuel ( contenteditable produira un div
quand Enter est pressé ), supprimez ce noeud, ajoutez le texte restant de tous les paragraphes qui viennent après celui-ci, et supprimez les paragraphes restants.
if (key == 13) {
fragment = para.lastChild; overflow = fragment.textContent;
fragment.parentNode.removeChild(fragment);
remainingText = overflow + removeSiblings(para, false);
rearrange(remainingText);
}
Si BackSpace a été appuyé, vérifiez s'il existe un paragraphe précédent et si le curseur se trouvait au début. Si oui, extraire le texte restant de tous les paragraphes suivants (y compris le paragraphe actuel) tout en les supprimant :
if (key == 8 && para.previousElementSibling && position == 0) {
fragment = para.previousElementSibling;
remainingText = removeSiblings(fragment, true);
rearrange(remainingText);
}
Logique d'extraire le texte des paragraphes successifs et de les supprimer :
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;
}
En mettant tout cela ensemble, voici un extrait de travail :
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>
Et un violon pour que vous puissiez jouer avec :
Violon : https://jsfiddle.net/abhitalks/jwnnn5oy/
Edit 1 :
Correction de la regex pour la rupture aux limites des mots. J'ai également ajouté le code procédural non-regex pour la même chose ( sur les lignes du code original d'Op ), pour démontrer à l'Op comment factoriser et intégrer ses autres segments de code dans celui-ci.
Note 4 : En ce qui concerne le commentaire d'Op sur l'utilisation de jQuery, cela n'a rien à voir avec le problème en question. jQuery n'est rien d'autre que du JavaScript et il devrait être trivial pour eux d'incorporer des morceaux de snippet dans la base de code plus large.
Changez le jeu : Fonction ajoutée splitText
.
Edit 2 :
Selon votre commentaire, si vous voulez que la redistribution se fasse automatiquement lorsque l'utilisateur tape... alors vous devrez calculer la longueur du texte dans ce paragraphe et voir si elle dépasse la taille de vos morceaux. Si c'est le cas, effectuez la redistribution à partir de ce paragraphe. Faites l'inverse pour le retour arrière.
J'ai initialement posté la solution pour votre exigence de faire cela lorsque l'utilisateur appuie sur la touche Entrée entre n'importe quel texte pour le rompre et le distribuer aux paragraphes suivants. Je ne recommande pas de le faire automatiquement au fur et à mesure que l'utilisateur tape, car les changements seraient trop brutaux pour l'utilisateur.
Extrait 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>
Violon 2 : https://jsfiddle.net/abhitalks/hvhr4ds8/
Note 5 : Dans le violon, appuyez d'abord sur la touche Entrée pour interrompre le texte afin que vous puissiez voir comment la redistribution se produit lorsque vous tapez. Notez également qu'en raison de la logique de ne pas casser un mot, il faudra quelques caractères supplémentaires avant que la redistribution ne s'effectue.
Changez le jeu : Fonction ajoutée redistributeAuto
.
0 votes
Avez-vous réellement besoin de nouvelles balises de paragraphe pour envelopper chaque morceau de texte, ou avez-vous besoin de l'apparence d'un espace là où il y avait auparavant un espace entre les paragraphes dans le texte ?
0 votes
Avez-vous vraiment essayé quelque chose par vous-même ?
0 votes
@Joshua - Chaque paragraphe est créé dynamiquement pour chaque bloc de texte. Cependant, lorsque le bloc de texte est rempli, l'utilisateur peut avoir besoin de modifier le texte et peut vouloir déplacer le texte du paragraphe précédent vers le nouveau paragraphe, pour que le texte continue de couler dans le paragraphe suivant.
0 votes
@enguerranws - Oui j'ai essayé de résoudre ce problème, cependant j'ai du mal à résoudre ce problème de fluidité du texte si l'utilisateur a besoin de modifier les paragraphes générés.
0 votes
Alors, pouvez-vous coller ce que vous avez essayé jusqu'à présent ?
0 votes
Par exemple, si vous remplissez la zone de texte avec du texte et cliquez sur le bouton, le texte se poursuivra dans le deuxième paragraphe. Toutefois, si vous essayez de modifier le texte et de le déplacer dans le paragraphe suivant, par exemple en appuyant sur la touche "Entrée", il ne s'insère pas dans le paragraphe et disparaît.
0 votes
Vous pourriez ajouter un code pour déplacer du texte lorsque le contenu de vos paragraphes change comme ceci ? stackoverflow.com/a/6263537/1328536
0 votes
@Dave, voulez-vous modifier le textarea ou les paragraphes créés dynamiquement ? J'ai vérifié votre truc et je vois que les paragraphes permettent à l'utilisateur de créer une nouvelle ligne, mais avec des éléments imbriqués.
<div>
seulement. Voulez-vous diviser le paragraphe en deux lorsque l'utilisateur appuie sur la touche Entrée du paragraphe ?0 votes
Oui, le texte doit être divisé tout en compensant le texte existant pour qu'il s'écoule dans les cases en dessous ou créer une nouvelle balise de paragraphe.
0 votes
Pouvez-vous expliquer ce que vous essayez d'obtenir et pourquoi vous devez diviser le texte de l'utilisateur d'une zone de texte en paragraphes ? S'agit-il d'un "exercice" ou essayez-vous de créer quelque chose pour l'un de vos projets ? Si c'est le dernier, pouvez-vous ajouter un peu de contexte ?