I am trying to get part of the text from an input element, depending on where the user clicked, but if I click in between the 1 and 0, the result is wrong "שלום 1", it should be "שלום 0". I tried adding CSS "unicode-bidi: plaintext;" to the input element. It did not help fix the problem.

var myInput = document.getElementById("myInput")
myInput.value = "שלום 10 hello";

alert("Needs to be: 'שלום 0' \n Result '"+myInput.value.substring( 0, 6 )+"'")

function mouseUp(){
 alert("Result '"+myInput.value.substring( 0, myInput.selectionStart )+"'")
}
myInput.addEventListener("mouseup", mouseUp);
<input id="myInput" style="direction: rtl;unicode-bidi: plaintext;">

推荐答案

I found a solution thanks to Bergi's comment:

console.log("שלום 10 hello".split("").map(c => '${c}': \\u${c.charCodeAt(0).toString(16).padStart(4,'0')}).join("\n")); might be helpful to see how the string is actually composed, without weird bidi rendering, which is what slice works on. I suspect you need to add some ltr/rtl marks.

After reading the page linked in the comment, I realized that the Unicode formatting offers two types of keycodes (LRM and RLM marks) that have zero width upon rendering and their purpose is to override the default direction flow.

So when the first non-space neighboring character, before a number is an RTL character, the explicit RTL characters interfere with the numbers' default LTR behavior. So when I added an LRM bidi control character before the number, it ignored the RTL direction flow override that caused the problem.

One thing to consider: I also learned that an RLM control character might be required right after the number if an LTR char immediately follows after the number (ignoring white spaces due to their neutrality) because of the fact that, if you start a sentence with an RTL word followed by a (space, LRM, number, space, LTR word), the LRM flow override merges the number and the following LTR word into a single LTR block which flips the display of the number and the LTR section since the number is found before the LTR block. So the string described above would be rendered like that: number, space, LTR word, space, RTL word in contrast to the expected way it should be rendered. I added a code example to demonstrate it:

var myInput = document.getElementById("myInput"),
    Normal = document.getElementById("Normal"),
    Fixed = document.getElementById("Fixed");
    
myInput.value = "שלום 10 hello";

Normal.innerHTML = myInput.value.substring( 0, 6 );
Normal.innerHTML += '<div style="display: inline-block;"></div>';
Normal.innerHTML += myInput.value.substring( 6, 14 );

Fixed.innerHTML = 
myInput.value.replace("10",String.fromCodePoint("0x200E")+"10").substring( 0, 7 );
Fixed.innerHTML += '<div style="display: inline-block;"></div>';
Fixed.innerHTML += myInput.value.replace("10",String.fromCodePoint("0x200E")+"10"+String.fromCodePoint("0x200F")).substring( 7, 16 );
<input id="myInput" style="direction: rtl;width: 79px;">
<h3>Before the fix</h3>
<div id="Normal" style="background: #ffa0a0;width: fit-content;direction: rtl;display: inline-block;"> </div>

<h3>After the fix</h3>
<div id="Fixed" style="background: #a2ffa0;width: fit-content;direction: rtl;display: inline-block;"> </div>

Javascript相关问答推荐

Firestore - 获取文档中的字段数量

为什么console.log中的内容在react native return语句中无限打印

使用 MUI 悬停时的三倍图像效果

如果数据介于 0 和 1 之间,如何使用对数采样使用 D3 创建图例

Chart.js 工具提示未在折线图中的特定点显示 x 轴数据集的所有值,模式问题:'index'

Typescript :类型是属性名称未知的对象

Time Limit Exceeded:如何在 Javascript 中优化我的代码?

根据线性渐变中的 colored颜色 更改 SVG 圆形进度条笔划

如何从 html 中提取特定元素

使用 jQuery 将页面滚动到某个点时,如何更改文本?

将另一个入口文件添加到 webpack 而不注入 HTML 文件

状态中的计数值没有增加

第二个数据集的工具提示不会显示 chart.js

函数中未定义的 jQuery DataTable 参数

无法在js中声明top

我可以在服务器上生成交易并将其发送给客户端进行付款吗

即使使用 e.preventDefault() 也无法停止刷新,e.stopPropagation 并且我也try 使用 document.getElementById 来做到这一点

如何在Node JS中编写这个Java加密函数的类似功能

数字输入最小属性不适用于浮点数