获取选择所在的行 javascript
get line where selection is in javascript
我有一个 div contentEditable=true,其中输入了多行文本。每当用户按下回车键时,我想检查用户所在的行以查看该行(最好是所有行)的上下文。
是否可以有类似 window.getSelection().lineContent
的东西?
我可以使用window.getSelection().anchorNode.textContent
,但它只适用于当前节点(不是该行)。我假设用户将按 enter 键转到下一行,我想知道下一行是否应该缩进(我的主要目标是知道行首是否有“制表符”,到目前为止)。
编辑:当前代码:
document.getElementById('sampleeditor').addEventListener("keydown", fSubsTab );
function fSubsTab () {
e = window.event
if ( false ) {
} else if ( e.keyCode == 13 ) {
e.preventDefault();
if (!window.getSelection) return;
sel = window.getSelection();
node_offset = sel.anchorOffset
node_text = sel.anchorNode.textContent
// The problem is how would I get the content of the
// current line between last line break and next one,
// or until the end
}
}
编辑 2:已解决。请参阅下面的答案。
如果我正确理解了您的问题,您可以通过组合获得所需的行为:
document.activeElement
获取活动文本元素
document.activeElement.selectionStart
获取光标位置
document.activeElement.value.split("\n")[line]
to convert cursor to the active line
document.addEventListener('keyup', (e) => {
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
if (document.activeElement.type === 'textarea') {
let start = $(document.activeElement).prop("selectionStart");
let line = document.activeElement.value.substr(0, document.activeElement.selectionStart).split("\n").length - 2;
console.log(`Pressed enter on line ${line + 1}:`);
console.log(document.activeElement.value.split("\n")[line]);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea rows='5'>
foo
bar
foobar
barfoo
</textarea>
根据原始问题中列出的所有 parameters/rules,它的工作方式存在一些潜在问题。
最大的问题是使用 contentEditable 属性作为编辑 HTML 的方法。其他 solutions/examples 让你使用像 activeElement 和 selectionStart 这样的东西。这很好,但您指出可以有 mixed 内容,例如 HTML 在某些情况下会改变活动元素。最初我想使用 innerText 或 innerHTML 值,但这以更明显的方式提出了主要问题。
document.getElementById('sampleeditor').addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
console.log(this.innerHTML.split("<div>")[this.innerHTML.split("<div>").length-1]);
console.log(this.innerText.split("\n")[this.innerText.split("\n").length-1]);
}
});
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
<div id="sampleeditor" contentEditable=true>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of <b><i>classical Latin literature</i></b> from 45 BC, making it over <span>2000 years old</span>.</div>
<p>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested.</p>
<p>"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."</p>
在这个例子中,使用 innerText 可以让我们轻松地分隔每一行,但无法获取嵌入在主元素中的任何 HTML 代码。使用 innerHTML 也允许我们获得 HTML 代码,但是由于 contentEditable 的工作方式,这些行被一个简单的 标签分开,它也可以包含在元素内部并可能导致冲突。
替代方法
我不确定您可以使用现有代码执行的操作是否有任何限制因素,但我的建议是放弃 contentEditable 并加载 元素中该元素的内容以供编辑。将此与 中的方法相结合,你似乎得到了你想要的结果。
下面的示例在单击某个元素时获取该元素的内容,并将其放置在 中,替换该元素的内容。在 中按下 enter/return 键后,此 returns 行号和上一行的文本。在 之外单击时,脚本会获取新代码并将其放回父元素内。
document.querySelector("#sampleeditor").addEventListener("click", function() {
_EditEl(this);
this.removeEventListener('click', arguments.callee);
});
function _EditEl(pEl) {
let curContent = pEl.innerHTML;
pEl.innerHTML = `<textarea id="tmpEdit" style="width: 100%; height: 4em;">${curContent}</textarea>`;
document.querySelector("#tmpEdit").focus();//
document.querySelector("#tmpEdit").addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
let start = document.activeElement.selectionStart;
let line = document.activeElement.value.substr(0, document.activeElement.selectionStart).split("\n").length - 2;
console.log(`Pressed enter on line ${line + 1}:`);
console.log(document.activeElement.value.split("\n")[line]);
}
});
document.querySelector("#tmpEdit").addEventListener("blur", function(e) {
let parentEl = this.parentElement;
parentEl.innerHTML = this.value;
parentEl.addEventListener("click", function() {
_EditEl(this);
this.removeEventListener('click', arguments.callee);
});
});
}
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
<div id="sampleeditor">Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of <b><i>classical Latin literature</i></b> from 45 BC, making it over <span>2000 years old</span>.</div>
<p>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested.</p>
<p>"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."</p>
我已经解决了这个问题,方法是使用自定义函数生成一个 uuid,将其添加到文本中,然后再将其删除。由于使用了很多函数,代码有点乱,但它是这样的
// function for replacing characters without case sensitivity
String.prototype.replaces = function(str, replace, incaseSensitive) {
if(!incaseSensitive){
return this.split(str).join(replace);
} else {
// Replace this part with regex for more performance
var strLower = this.toLowerCase();
var findLower = String(str).toLowerCase();
var strTemp = this.toString();
var pos = strLower.length;
while((pos = strLower.lastIndexOf(findLower, pos)) != -1){
tcounter++
strTemp = strTemp.substr(0, pos) + replace + strTemp.substr(pos + findLower.length);
pos--;
if (pos<0) {
break
}
}
return strTemp;
}
};
// function for generating uuid to be used after
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// function for dealing with linebreaks from innerhtml and returning as text with line breaks
function innerHTMLtoText ( inner ) {
text = inner
prelb = uuidv4() + uuidv4() + uuidv4() + uuidv4()
prelb_list = [];
lb = prelb + "ddd" + prelb; prelb_list.push(lb);
tag_ = "<div>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "</div>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<div "; text = text.replaces ( tag_, lb + tag_, true );
lb = prelb + "ppp" + prelb; prelb_list.push(lb);
tag_ = "<p>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "</p>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<p "; text = text.replaces ( tag_, lb + tag_, true );
lb = prelb + "bbb" + prelb; prelb_list.push(lb);
tag_ = "<br>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<br "; text = text.replaces ( tag_, lb + tag_, true );
// tag_ = "<br />"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<br/>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "</br>"; text = text.replaces ( tag_, lb + tag_, true );
var temporalDivElement = document.createElement("div");
temporalDivElement.innerHTML = text;
text = temporalDivElement.textContent
list_ = prelb_list
for ( let i = 0 ; i<list_.length ; i++ ) {
this_ = list_[i]
text = text.replaces ( this_, "\n", true );
}
return text
}
// main function, that generates a uuid, inserts at caret position, checks text of line, and removes the uuid
document.getElementById('sampleeditor').addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
texteditor = document.getElementById('sampleeditor')
e.preventDefault();
if (!window.getSelection) return;
sel = window.getSelection();
if (!sel.rangeCount) return;
range = sel.getRangeAt(0);
range.collapse(true);
span = document.createElement('span');
span.appendChild(document.createTextNode(' '));
theSpanId = "span_" + uuidv4() + uuidv4() + uuidv4() + uuidv4()
span.id = theSpanId
outerInclude = span.outerHTML
changeText = document.createElement('span');
idToRemove = uuidv4() + uuidv4() + uuidv4() + uuidv4()
changeText.innerHTML = idToRemove
outerRemove = changeText.outerHTML
range.insertNode(changeText);
theinner = texteditor.innerHTML
plainText = innerHTMLtoText ( theinner )
posLineBreak = plainText.indexOf (idToRemove)
textBefore = plainText.substring(0, posLineBreak)
textBefore = textBefore.split ("\n")
linePart1 = textBefore[textBefore.length-1]
textAfter = plainText.substring(posLineBreak)
textAfter = textAfter.split ("\n")
linePart2 = textAfter[0]
fullLine = linePart1 + linePart2
fullLine = fullLine.split ( idToRemove ).join ("")
texteditor.innerHTML = texteditor.innerHTML.split(outerRemove).join("<br>" + outerInclude)
range = sel.getRangeAt(0);
range.collapse(true);
span = document.getElementById(theSpanId)
range.setStartAfter(span);
range.collapse(true);
var startNode = span.firstChild;
var endNode = span.firstChild;
var range = document.createRange();
range.setStart(startNode, 0);
range.setEnd(endNode, 0+1);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
});
我有一个 div contentEditable=true,其中输入了多行文本。每当用户按下回车键时,我想检查用户所在的行以查看该行(最好是所有行)的上下文。
是否可以有类似 window.getSelection().lineContent
的东西?
我可以使用window.getSelection().anchorNode.textContent
,但它只适用于当前节点(不是该行)。我假设用户将按 enter 键转到下一行,我想知道下一行是否应该缩进(我的主要目标是知道行首是否有“制表符”,到目前为止)。
编辑:当前代码:
document.getElementById('sampleeditor').addEventListener("keydown", fSubsTab );
function fSubsTab () {
e = window.event
if ( false ) {
} else if ( e.keyCode == 13 ) {
e.preventDefault();
if (!window.getSelection) return;
sel = window.getSelection();
node_offset = sel.anchorOffset
node_text = sel.anchorNode.textContent
// The problem is how would I get the content of the
// current line between last line break and next one,
// or until the end
}
}
编辑 2:已解决。请参阅下面的答案。
如果我正确理解了您的问题,您可以通过组合获得所需的行为:
document.activeElement
获取活动文本元素document.activeElement.selectionStart
获取光标位置document.activeElement.value.split("\n")[line]
to convert cursor to the active line
document.addEventListener('keyup', (e) => {
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
if (document.activeElement.type === 'textarea') {
let start = $(document.activeElement).prop("selectionStart");
let line = document.activeElement.value.substr(0, document.activeElement.selectionStart).split("\n").length - 2;
console.log(`Pressed enter on line ${line + 1}:`);
console.log(document.activeElement.value.split("\n")[line]);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea rows='5'>
foo
bar
foobar
barfoo
</textarea>
根据原始问题中列出的所有 parameters/rules,它的工作方式存在一些潜在问题。
最大的问题是使用 contentEditable 属性作为编辑 HTML 的方法。其他 solutions/examples 让你使用像 activeElement 和 selectionStart 这样的东西。这很好,但您指出可以有 mixed 内容,例如 HTML 在某些情况下会改变活动元素。最初我想使用 innerText 或 innerHTML 值,但这以更明显的方式提出了主要问题。
document.getElementById('sampleeditor').addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
console.log(this.innerHTML.split("<div>")[this.innerHTML.split("<div>").length-1]);
console.log(this.innerText.split("\n")[this.innerText.split("\n").length-1]);
}
});
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
<div id="sampleeditor" contentEditable=true>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of <b><i>classical Latin literature</i></b> from 45 BC, making it over <span>2000 years old</span>.</div>
<p>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested.</p>
<p>"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."</p>
在这个例子中,使用 innerText 可以让我们轻松地分隔每一行,但无法获取嵌入在主元素中的任何 HTML 代码。使用 innerHTML 也允许我们获得 HTML 代码,但是由于 contentEditable 的工作方式,这些行被一个简单的 我不确定您可以使用现有代码执行的操作是否有任何限制因素,但我的建议是放弃 contentEditable 并加载 元素中该元素的内容以供编辑。将此与 下面的示例在单击某个元素时获取该元素的内容,并将其放置在 中,替换该元素的内容。在 中按下 enter/return 键后,此 returns 行号和上一行的文本。在 之外单击时,脚本会获取新代码并将其放回父元素内。 我已经解决了这个问题,方法是使用自定义函数生成一个 uuid,将其添加到文本中,然后再将其删除。由于使用了很多函数,代码有点乱,但它是这样的
替代方法
document.querySelector("#sampleeditor").addEventListener("click", function() {
_EditEl(this);
this.removeEventListener('click', arguments.callee);
});
function _EditEl(pEl) {
let curContent = pEl.innerHTML;
pEl.innerHTML = `<textarea id="tmpEdit" style="width: 100%; height: 4em;">${curContent}</textarea>`;
document.querySelector("#tmpEdit").focus();//
document.querySelector("#tmpEdit").addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
let start = document.activeElement.selectionStart;
let line = document.activeElement.value.substr(0, document.activeElement.selectionStart).split("\n").length - 2;
console.log(`Pressed enter on line ${line + 1}:`);
console.log(document.activeElement.value.split("\n")[line]);
}
});
document.querySelector("#tmpEdit").addEventListener("blur", function(e) {
let parentEl = this.parentElement;
parentEl.innerHTML = this.value;
parentEl.addEventListener("click", function() {
_EditEl(this);
this.removeEventListener('click', arguments.callee);
});
});
}
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.</p>
<div id="sampleeditor">Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of <b><i>classical Latin literature</i></b> from 45 BC, making it over <span>2000 years old</span>.</div>
<p>The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested.</p>
<p>"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."</p>
// function for replacing characters without case sensitivity
String.prototype.replaces = function(str, replace, incaseSensitive) {
if(!incaseSensitive){
return this.split(str).join(replace);
} else {
// Replace this part with regex for more performance
var strLower = this.toLowerCase();
var findLower = String(str).toLowerCase();
var strTemp = this.toString();
var pos = strLower.length;
while((pos = strLower.lastIndexOf(findLower, pos)) != -1){
tcounter++
strTemp = strTemp.substr(0, pos) + replace + strTemp.substr(pos + findLower.length);
pos--;
if (pos<0) {
break
}
}
return strTemp;
}
};
// function for generating uuid to be used after
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// function for dealing with linebreaks from innerhtml and returning as text with line breaks
function innerHTMLtoText ( inner ) {
text = inner
prelb = uuidv4() + uuidv4() + uuidv4() + uuidv4()
prelb_list = [];
lb = prelb + "ddd" + prelb; prelb_list.push(lb);
tag_ = "<div>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "</div>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<div "; text = text.replaces ( tag_, lb + tag_, true );
lb = prelb + "ppp" + prelb; prelb_list.push(lb);
tag_ = "<p>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "</p>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<p "; text = text.replaces ( tag_, lb + tag_, true );
lb = prelb + "bbb" + prelb; prelb_list.push(lb);
tag_ = "<br>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<br "; text = text.replaces ( tag_, lb + tag_, true );
// tag_ = "<br />"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "<br/>"; text = text.replaces ( tag_, lb + tag_, true );
tag_ = "</br>"; text = text.replaces ( tag_, lb + tag_, true );
var temporalDivElement = document.createElement("div");
temporalDivElement.innerHTML = text;
text = temporalDivElement.textContent
list_ = prelb_list
for ( let i = 0 ; i<list_.length ; i++ ) {
this_ = list_[i]
text = text.replaces ( this_, "\n", true );
}
return text
}
// main function, that generates a uuid, inserts at caret position, checks text of line, and removes the uuid
document.getElementById('sampleeditor').addEventListener("keyup", function(e) {
if(e.keyCode == 13) {
texteditor = document.getElementById('sampleeditor')
e.preventDefault();
if (!window.getSelection) return;
sel = window.getSelection();
if (!sel.rangeCount) return;
range = sel.getRangeAt(0);
range.collapse(true);
span = document.createElement('span');
span.appendChild(document.createTextNode(' '));
theSpanId = "span_" + uuidv4() + uuidv4() + uuidv4() + uuidv4()
span.id = theSpanId
outerInclude = span.outerHTML
changeText = document.createElement('span');
idToRemove = uuidv4() + uuidv4() + uuidv4() + uuidv4()
changeText.innerHTML = idToRemove
outerRemove = changeText.outerHTML
range.insertNode(changeText);
theinner = texteditor.innerHTML
plainText = innerHTMLtoText ( theinner )
posLineBreak = plainText.indexOf (idToRemove)
textBefore = plainText.substring(0, posLineBreak)
textBefore = textBefore.split ("\n")
linePart1 = textBefore[textBefore.length-1]
textAfter = plainText.substring(posLineBreak)
textAfter = textAfter.split ("\n")
linePart2 = textAfter[0]
fullLine = linePart1 + linePart2
fullLine = fullLine.split ( idToRemove ).join ("")
texteditor.innerHTML = texteditor.innerHTML.split(outerRemove).join("<br>" + outerInclude)
range = sel.getRangeAt(0);
range.collapse(true);
span = document.getElementById(theSpanId)
range.setStartAfter(span);
range.collapse(true);
var startNode = span.firstChild;
var endNode = span.firstChild;
var range = document.createRange();
range.setStart(startNode, 0);
range.setEnd(endNode, 0+1);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
});