Javascript 在自动换行阿拉伯文本的 textarea 中找到“换行符”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4719777/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
finding "line-breaks" in textarea that is word-wrapping ARABIC text
提问by Irfan jamal
I have a string of text that I display in a textarea (right-to-left orientation). The user can resize the textarea dynamically (I use jquery for this) and the text will wrap as necessary.
我有一个文本字符串显示在文本区域(从右到左方向)中。用户可以动态调整 textarea 的大小(我为此使用 jquery)并且文本将根据需要换行。
When the user hits submit, I will take that text and create an image using PHP, BUT before submitting I would like to know where the "line-breaks" or rather "word-wraps" occur.
当用户点击提交时,我将获取该文本并使用 PHP 创建一个图像,但在提交之前我想知道“换行”或“自动换行”发生的位置。
Everywhere I have looked so far only shows me how to process line-breaks on the php side. I want to make it clear that there ARE NO LINE-BREAKS. What I have is one LONG string that will be word-wrapped in different ways based on the width of the textarea set by the user.
到目前为止,我所看到的所有地方都只向我展示了如何在 php 端处理换行符。我想明确表示没有换行符。我拥有的是一个 LONG 字符串,它将根据用户设置的 textarea 的宽度以不同的方式换行。
I can't use "columns" or any other standard width representation because I have a very complex arabic font that is actually composed of glyphs (characters) of numerous different widths.
我不能使用“列”或任何其他标准宽度表示,因为我有一个非常复杂的阿拉伯字体,它实际上由许多不同宽度的字形(字符)组成。
If anyone knows of a way of accessing where the word wraps occur (either in a textarea or a div if need-be), I'd really like to know.
如果有人知道访问自动换行位置的方法(如果需要,可以在 textarea 或 div 中),我真的很想知道。
My only other solution is to actually store (in my DB) the width of every single character (somewhat tedious since there are over 200 characters in 600 different fonts, for a total of...some huge number).
我唯一的其他解决方案是实际存储(在我的数据库中)每个单个字符的宽度(有点乏味,因为 600 种不同字体中有超过 200 个字符,总共......一些巨大的数字)。
My hopes aren't high, but I thought I would ask.
我的希望并不高,但我想我会问。
Thanks
谢谢
i. jamal
一世。贾马尔
采纳答案by Shadow Wizard is Ear For You
Well, instead of findingthe line breaks (which is virtually impossible) you can forcethem into the textarea, using this function:
好吧,不是找到换行符(这几乎是不可能的),您可以使用以下函数将它们强制放入 textarea:
function ApplyLineBreaks(strTextAreaId) {
var oTextarea = document.getElementById(strTextAreaId);
if (oTextarea.wrap) {
oTextarea.setAttribute("wrap", "off");
}
else {
oTextarea.setAttribute("wrap", "off");
var newArea = oTextarea.cloneNode(true);
newArea.value = oTextarea.value;
oTextarea.parentNode.replaceChild(newArea, oTextarea);
oTextarea = newArea;
}
var strRawValue = oTextarea.value;
oTextarea.value = "";
var nEmptyWidth = oTextarea.scrollWidth;
var nLastWrappingIndex = -1;
for (var i = 0; i < strRawValue.length; i++) {
var curChar = strRawValue.charAt(i);
if (curChar == ' ' || curChar == '-' || curChar == '+')
nLastWrappingIndex = i;
oTextarea.value += curChar;
if (oTextarea.scrollWidth > nEmptyWidth) {
var buffer = "";
if (nLastWrappingIndex >= 0) {
for (var j = nLastWrappingIndex + 1; j < i; j++)
buffer += strRawValue.charAt(j);
nLastWrappingIndex = -1;
}
buffer += curChar;
oTextarea.value = oTextarea.value.substr(0, oTextarea.value.length - buffer.length);
oTextarea.value += "\n" + buffer;
}
}
oTextarea.setAttribute("wrap", "");
}
This function get ID of textarea and whenever there is word wrap, it push new line break into the textarea. Run the function in the form submit and you will get the text with proper line breaks in the server side code.
此函数获取 textarea 的 ID,每当有自动换行时,它将换行符推入 textarea。在表单提交中运行该函数,您将在服务器端代码中获得带有正确换行符的文本。
Tested successfully for IE, Chrome and Firefox feel free to see for yourself here: http://jsfiddle.net/yahavbr/pH79a/1/(The preview will show the new lines)
已针对 IE、Chrome 和 Firefox 测试成功,请在此处自行查看:http: //jsfiddle.net/yahavbr/pH79a/1/(预览将显示新行)
回答by Kevin Borders
Here is a functionally-equivalent implementation of Shadow Wizard's solution that is much faster because it uses binary search instead of linear search to determine the length of each line:
这是 Shadow Wizard 解决方案的功能等效实现,它的速度要快得多,因为它使用二进制搜索而不是线性搜索来确定每行的长度:
function ApplyLineBreaks(strTextAreaId) {
var oTextarea = document.getElementById(strTextAreaId);
if (oTextarea.wrap) {
oTextarea.setAttribute("wrap", "off");
}
else {
oTextarea.setAttribute("wrap", "off");
var newArea = oTextarea.cloneNode(true);
newArea.value = oTextarea.value;
oTextarea.parentNode.replaceChild(newArea, oTextarea);
oTextarea = newArea;
}
var strRawValue = oTextarea.value;
oTextarea.value = "";
var nEmptyWidth = oTextarea.scrollWidth;
function testBreak(strTest) {
oTextarea.value = strTest;
return oTextarea.scrollWidth > nEmptyWidth;
}
function findNextBreakLength(strSource, nLeft, nRight) {
var nCurrent;
if(typeof(nLeft) == 'undefined') {
nLeft = 0;
nRight = -1;
nCurrent = 64;
}
else {
if (nRight == -1)
nCurrent = nLeft * 2;
else if (nRight - nLeft <= 1)
return Math.max(2, nRight);
else
nCurrent = nLeft + (nRight - nLeft) / 2;
}
var strTest = strSource.substr(0, nCurrent);
var bLonger = testBreak(strTest);
if(bLonger)
nRight = nCurrent;
else
{
if(nCurrent >= strSource.length)
return null;
nLeft = nCurrent;
}
return findNextBreakLength(strSource, nLeft, nRight);
}
var i = 0, j;
var strNewValue = "";
while (i < strRawValue.length) {
var breakOffset = findNextBreakLength(strRawValue.substr(i));
if (breakOffset === null) {
strNewValue += strRawValue.substr(i);
break;
}
var nLineLength = breakOffset - 1;
for (j = nLineLength - 1; j >= 0; j--) {
var curChar = strRawValue.charAt(i + j);
if (curChar == ' ' || curChar == '-' || curChar == '+') {
nLineLength = j + 1;
break;
}
}
strNewValue += strRawValue.substr(i, nLineLength) + "\n";
i += nLineLength;
}
oTextarea.value = strNewValue;
oTextarea.setAttribute("wrap", "");
}
回答by Barney
I think the easiest way of doing it would be to set the word wrap of your textarea in the html code to 'hard', like this:
我认为最简单的方法是将 html 代码中 textarea 的自动换行设置为“硬”,如下所示:
<textarea id='yourTextArea' wrap='hard'></textarea>
It means that wherever your textarea breaks the line for you will also insert a \n linebreak charachter in the string when submitting. If you then find this going through your string it will make it easy to determine where was the break originally. Or you can also turn these characters to
html tags with the nl2br() function of PHP.
这意味着无论您的 textarea 在哪里换行,您都会在提交时在字符串中插入一个 \n 换行符。如果您随后发现它穿过您的字符串,则可以轻松确定最初的中断位置。或者您也可以
使用 PHP 的 nl2br() 函数将这些字符转换为html 标签。
回答by xuancong84
Here is my example for computing the actual number of rows (after line wrapping) for every line of text in a textarea. Take note that the text width of a textarea shrinks slightly when the scrollbar starts to appear. This can cause further wrapping of the previous content so that the previously computed row height will not be correct. Therefore, the textarea must have CSS-style overflow-y set to "scroll" to force the display of the scrollbar all the time.
这是我计算 textarea 中每一行文本的实际行数(换行后)的示例。请注意,当滚动条开始出现时,textarea 的文本宽度会略微缩小。这可能会导致对先前内容的进一步环绕,从而使先前计算的行高不正确。因此,textarea必须有CSS样式的overflow-y设置为“scroll”,强制一直显示滚动条。
function get_row_wraps(txtArea){
if(wrap=="off"){
var out=[];
for(var i=txtArea.split_lines.length; i>=0; --i)
out[i]=1;
return out;
}
var its=txtArea.value.split("\n");
var newArea = txtArea.cloneNode(true);
newArea.hidden=true;
newArea.style.visibility = "hidden";
txtArea.parentNode.appendChild(newArea);
// get single row height
newArea.style.height="auto";
newArea.style.overflowY="scroll";
newArea.value="1\n2\n3";
var unit_height=newArea.scrollHeight;
newArea.value="1\n2\n3\n4";
var unit_height=newArea.scrollHeight-unit_height;
newArea.style.height=Math.round(unit_height*1.5)+"px"; // so that the scrollbar does not vanish
newArea.value="";
// obtain row height for every line of text
function comp_Nrow(scroll_height){
return Math.floor(scroll_height/unit_height);
}
function calc_rows(txt){
newArea.value+=txt;
return comp_Nrow(newArea.scrollHeight);
}
var out=[];
for(var i=0; i<its.length; i++)
out.push(calc_rows(i==0?its[i]:("\n"+its[i])));
txtArea.parentNode.removeChild(newArea);
for(var i=out.length-1; i>0; i--)
out[i]-=out[i-1];
// alert(out);
return out;
}
The above function returns the actual number of wrapped rows for each line of text (separated by "\n") in an textarea. The computation is accurate at least for Chrome and Firefox.
上述函数返回 textarea 中每行文本(以“\n”分隔)的实际回绕行数。至少对于 Chrome 和 Firefox,计算是准确的。
回答by Irfan jamal
For some reason, I was never alerted when this post was updated...and last night, I had this BRILLIANT idea on how to determine where the line breaks were... I would rebuild the string, and check the width each time, and it WORKED so I came here to share it...and found I was 1 week behind
出于某种原因,当这篇文章更新时,我从未被提醒过……昨晚,我有一个关于如何确定换行符位置的绝妙想法……我会重建字符串,并每次检查宽度,它有效,所以我来这里分享它......发现我落后了 1 周
Anyway 2 important things
无论如何 2 重要的事情
The code you provided uses the same brilliant idea I had (well done you) BUT when I test it, it breaks the first line correctly then adds a line break after every character (tested on the link jsfiddle.net)
I've added my code which uses jquery and uses the width of a span to determine when to break At first I tried using the width of the div, but div.width() returns the default width, not the width of the content.
您提供的代码使用了与我相同的绝妙想法(您做得好)但是当我测试它时,它正确地打破了第一行,然后在每个字符后添加了一个换行符(在链接 jsfiddle.net 上测试)
我添加了我的代码,它使用 jquery 并使用跨度的宽度来确定何时中断首先我尝试使用 div 的宽度,但 div.width() 返回默认宽度,而不是内容的宽度。
I AM AWARE THIS MAY NOT WORK ON ALL BROWSERSso, I ask kindly that if anyone knows of a way of making this foolproof, or close to it, please share.
我知道这可能不适用于所有浏览器,所以,我恳请如果有人知道使这种方法万无一失或接近它的方法,请分享。
First, the styles are necessary to synchornize fonts (all attributes) between the textarea and div, set the size, and (for IE) remove any scrollbars that automatically appear.
首先,样式对于在 textarea 和 div 之间同步字体(所有属性)、设置大小和(对于 IE)删除任何自动出现的滚动条是必要的。
.inputArea {
width:200px;
height:100px;
font-family:Arial;
font-size:12px;
overflow: auto;
border: 1px solid #cccccc;
padding:0;
margin:0;
}
.divArea {
font-family:Arial;
font-size:12px;
}
Next, I include jquery and my custom functions:
接下来,我包括 jquery 和我的自定义函数:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js
"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#breakUp").click(function () {
showLineBreaks();
addLineBreaks();
});
function showLineBreaks() {
content = $("#textEntered").val();
//replace line breaks in content with "|" to allow for replacement below
content = content.replace("\r\n", "
");
content = content.replace("\r", "
");
content = content.replace("\n", "
");
$("#unedited").html(content);
}
function addLineBreaks() {
content = $("#textEntered").val();
//replace line breaks in content with "|" to allow for replacement below
content = content.replace("\r\n", "|");
content = content.replace("\r", "|");
content = content.replace("\n", "|");
tempContent = "";
$("#edited").html("");
for (var i = 0; i ");
} else {
tempContent = $("#edited").html();
$("#edited").html(tempContent + content.charAt(i));
if ($("#edited").width() > 200) {
$("#edited").html(tempContent + "
" + content.charAt(i));
}
}
}
}
});
<script>
And finally, my html test page
最后,我的 html 测试页面
Enter text into the textarea below (Set to 200 px width, 100 px height)<br>
<textarea id="textEntered" class="inputArea"></textarea>
<br><br>
The div below will display that text WITHOUT wrapping, BUT replacing all existing line breaks with <br><br>
<div id="unedited"></div>
<br>
The following div will display that text with line breaks ADDED to fit the wrapping<br>
<div class="divArea"><span id="edited"></span></div>
<br>
<button id="breakUp">Click Here to Convert</button>
回答by emilio
Code tested at "Crome", "Firefox" and "IE". Get line feeds and carriage returns a component "textArea" (client side with javascript).
在“Crome”、“Firefox”和“IE”上测试的代码。获取换行符并回车一个组件“textArea”(带有 javascript 的客户端)。
WORKS WELL!. I would like to share it with you
效果很好!。我想与你分享
important to include the style
重要的是包括风格
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<%--//definimos un estilo--%>
<STYLE type="text/css">
#CadTemp
{
font-family: "Arial", serif;
font-size: 12pt;
visibility: hidden;
position: absolute;
top: -100;
left: 0px;
}
</STYLE>
<script type="text/javascript">
function mostrar() {
return 'ancho cadena: ' + document.getElementById('myTextarea').value.visualLength() + ' \n' + 'ancho textarea: ' + (document.getElementById('myTextarea').scrollWidth -4);
}
//sustituimos el espacio en blanco por el punto, tienen exactamente el mismo tama?o en 'pixeles'
function reemplazarEspacios(texto) {
var devolver = "";
for (var i = 0; i < texto.length; i++) {
if (texto.charAt(i) == ' ') {
devolver += '.'
} else {
devolver += texto.charAt(i);
}
}
return devolver;
}
// Calcula los pixeles de ancho que ocupa un texto (la cadena debe tener el mismo tama?o y tipo de fuente)
String.prototype.visualLength = function () {
var ruler = document.getElementById("CadTemp");
ruler.innerHTML = reemplazarEspacios(this)
return ruler.offsetWidth;
}
//quitar espacios a la derecha de la cadena
String.prototype.rtrim = function() {return this.replace(/\s+$/,"");}
//devuelve el ultimo espacio de la cadena (que no sea espacio final)
function IndEspacio(cadena) {
//quito los espacios al final
var cadenaTemp = cadena.rtrim();
return cadenaTemp.lastIndexOf(' ');
}
//insertar un salto de linea
function AplicarSaltosLinea(ID_elemento) {
//guardo el elemento web en una variable
var TextArea = document.getElementById(ID_elemento);
var cadenaTexto = "";
var Cadenafinal = "";
var buffer = "";
//recorremos toda la cadena
for (var i = 0; i < TextArea.value.length; i++) {
//guardamos el caracater en la cadena
cadenaTexto += TextArea.value.charAt(i);
//si hay un retorno de carro, antes de llegar al final del textArea
if (TextArea.value.charAt(i) == '\n') {
Cadenafinal += cadenaTexto.substr(0, cadenaTexto.lastIndexOf('\n') + 1) ;
cadenaTexto = "";
}
//si el ancho actual de la cadena es mayor o igual que el ancho del textarea (medida pixeles)
if (cadenaTexto.visualLength() > TextArea.scrollWidth - 4) {
//recuperamos el ultimo espacio en blanco antes de la ultima letra o palabra
var indiceEspacio = IndEspacio(cadenaTexto)
buffer = "";
//ultimo espacio en blanco detectado, metemos el trozo de palabra desde el ultimo espacio
if (indiceEspacio >= 0) {
for (var j = indiceEspacio + 1; j <= i; j++)
buffer += cadenaTexto.charAt(j);
indiceEspacio = -1;
} else {
buffer += TextArea.value.charAt(i);
}
//coloca la cadena
Cadenafinal += cadenaTexto.substr(0, cadenaTexto.length - buffer.length) + "\n";
cadenaTexto = buffer;
}
}
Cadenafinal += cadenaTexto;
document.getElementById("pnlPreview").innerHTML = Cadenafinal.replace(new RegExp("\n", "g"), "<br />");
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<span id="CadTemp">hola</span>
</div>
<br />
<div>
<textarea cols="20" rows="5" id="myTextarea" wrap="hard"
style="font-family: Arial, Helvetica, sans-serif; font-size: 12pt"></textarea>
</div>
<div id="pnlPreview"></div>
<div>
<button type="button" onclick="AplicarSaltosLinea('myTextarea');">Apply Line Breaks</button>
<button type="button" onclick="alert( document.getElementById('myTextarea').value )">mensaje</button>
<button type="button" onclick="alert( mostrar())">calcular Ancho Pixel</button>
<br />
</div>
</form>
</body>
</html>
回答by NoobishPro
I don't mean to dig up old posts, but this is the one where I came out after searching for some time. @Shadow Wizard 's solution didn't work for me because it put a space behind every sentence, so I decided to make some adjustments. Instead of doing it per-character, I do it per-word. This results in way easier checks and is also 10 times faster, checking with full Lorem Ipsum (~600ms vs 6 full seconds on fiddle, 120ms without fiddle).
我不是要挖掘旧帖子,但这是我搜索一段时间后出来的帖子。@Shadow Wizard 的解决方案对我不起作用,因为它在每个句子后面留了一个空格,所以我决定做一些调整。我不是按字符做,而是按字做。这使得检查更容易并且速度也快了 10 倍,使用完整的 Lorem Ipsum 进行检查(大约 600 毫秒 vs 6 整秒的小提琴,120 毫秒没有小提琴)。
I have created a (documented) fiddle.I'm going to see if I can optimise it a bit more, though.
我创建了一个(记录在案的)小提琴。不过,我将看看是否可以进一步优化它。
function applyLineBreaks = function(strTextAreaId) {
// Get txtarea
var oTextarea = document.getElementById(strTextAreaId);
// Disable textarea wrap
oTextarea.setAttribute("wrap", "off");
// Split the characters into an array
var aWords = oTextarea.value.split(' ');
// Empty the textarea
oTextarea.value = "";
// Get textarea scrollwidth
var nEmptyWidth = oTextarea.scrollWidth;
// Start looping over the words
for(var i = 0; i < aWords.length; i++)
{
if(i > 1000)
{
break;
}
var curWord = aWords[i] + ' ';
// Add character to textarea
oTextarea.value += curWord;
// console.log(oTextarea.scrollWidth, nEmptyWidth);
if(oTextarea.scrollWidth > nEmptyWidth)
{
let oldVal = oTextarea.value;
let newVal = oldVal.substring(0, (oldVal.length - (curWord.length + 1))) + "\n" + curWord;
oTextarea.value = newVal;
}
}
oTextarea.setAttribute("wrap", "");
return oTextarea.value;
};