मुझे contenteditable
Gmail नोट्स विजेट पर नोड के अंत में कैरेट को स्थानांतरित करने की आवश्यकता है ।
मैं स्टैकऑवरफ़्लो पर थ्रेड्स पढ़ता हूं, लेकिन वे समाधान इनपुट्स का उपयोग करने पर आधारित हैं और वे contenteditable
तत्वों के साथ काम नहीं करते हैं।
जवाबों:
एक और समस्या भी है।
अगर एनको बर्न्स का समाधान काम करता है, अगर contenteditable
div में अन्य बहुस्तरीय तत्व नहीं हैं।
उदाहरण के लिए, यदि एक div में अन्य div हैं, और इन अन्य div में अन्य सामान हैं, तो कुछ समस्याएं हो सकती हैं।
उन्हें हल करने के लिए, मैंने निम्नलिखित समाधान की व्यवस्था की है, जो कि नीको के एक का सुधार है :
//Namespace management idea from http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
(function( cursorManager ) {
//From: http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
var voidNodeTags = ['AREA', 'BASE', 'BR', 'COL', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'MENUITEM', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR', 'BASEFONT', 'BGSOUND', 'FRAME', 'ISINDEX'];
//From: /programming/237104/array-containsobj-in-javascript
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
//Basic idea from: /programming/19790442/test-if-an-element-can-contain-text
function canContainText(node) {
if(node.nodeType == 1) { //is an element node
return !voidNodeTags.contains(node.nodeName);
} else { //is not an element node
return false;
}
};
function getLastChildElement(el){
var lc = el.lastChild;
while(lc && lc.nodeType != 1) {
if(lc.previousSibling)
lc = lc.previousSibling;
else
break;
}
return lc;
}
//Based on Nico Burns's answer
cursorManager.setEndOfContenteditable = function(contentEditableElement)
{
while(getLastChildElement(contentEditableElement) &&
canContainText(getLastChildElement(contentEditableElement))) {
contentEditableElement = getLastChildElement(contentEditableElement);
}
var range,selection;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//Create a range (a range is a like the selection but invisible)
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
}
else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
}( window.cursorManager = window.cursorManager || {}));
उपयोग:
var editableDiv = document.getElementById("my_contentEditableDiv");
cursorManager.setEndOfContenteditable(editableDiv);
इस तरह, कर्सर निश्चित रूप से अंतिम तत्व के अंत में स्थित है, अंततः नेस्टेड है।
EDIT # 1 : अधिक सामान्य होने के लिए, जबकि कथन में उन सभी अन्य टैगों पर भी विचार करना चाहिए जिनमें पाठ नहीं हो सकता है। इन तत्वों को शून्य तत्व नाम दिया गया है , और इस प्रश्न में कुछ तरीके हैं कि किसी तत्व के शून्य होने पर कैसे परीक्षण किया जाए। इसलिए, यह मानते हुए कि एक फ़ंक्शन मौजूद है, canContainText
जो रिटर्न देता है true
यदि तर्क एक शून्य तत्व नहीं है, तो कोड की निम्न पंक्ति:
contentEditableElement.lastChild.tagName.toLowerCase() != 'br'
के साथ प्रतिस्थापित किया जाना चाहिए:
canContainText(getLastChildElement(contentEditableElement))
EDIT # 2 : उपरोक्त कोड पूरी तरह से अपडेट किया गया है, जिसमें वर्णित और चर्चा किए गए प्रत्येक परिवर्तन हैं
Uncaught TypeError: Cannot read property 'nodeType' of null
और यह getLastChildElement फ़ंक्शन से बुलाया जा रहा है। क्या आप जानते हैं कि इस समस्या के कारण क्या हो सकते हैं?
Geowa4 का समाधान एक textarea के लिए काम करेगा, लेकिन एक संतुष्ट तत्व के लिए नहीं।
यह समाधान कैरेट को एक संतोषप्रद तत्व के अंत तक ले जाने के लिए है। यह सभी ब्राउज़रों में काम करना चाहिए जो संतोषप्रद समर्थन करते हैं।
function setEndOfContenteditable(contentEditableElement)
{
var range,selection;
if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
{
range = document.createRange();//Create a range (a range is a like the selection but invisible)
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
selection = window.getSelection();//get the selection object (allows you to change selection)
selection.removeAllRanges();//remove any selections already made
selection.addRange(range);//make the range you have just created the visible selection
}
else if(document.selection)//IE 8 and lower
{
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
range.select();//Select the range (make it the visible selection
}
}
इसका उपयोग कोड के समान किया जा सकता है:
elem = document.getElementById('txt1');//This is the element that you want to move the caret to the end of
setEndOfContenteditable(elem);
selectNodeContents
निको के दोनों क्रोम और एफएफ में मुझे त्रुटियों दे रहा था का हिस्सा (अन्य ब्राउज़रों का परीक्षण नहीं किया है) जब तक मुझे पता चला कि मैं जाहिरा तौर पर जोड़ने के लिए आवश्यक .get(0)
तत्व है कि मैं समारोह खिला था। मुझे लगता है कि यह मेरे साथ नंगे जेएस के बजाय jQuery का उपयोग करना है? मैंने प्रश्न ४२३३२६५ में @jwarcheng से यह सीखा । सभी को धन्यवाद!
.get(0)
डोम तत्व को पुनः प्राप्त करता है जो jQuery आंतरिक रूप से संग्रहीत करता है। आप भी जोड़ सकते हैं [0]
, जो .get(0)
इस संदर्भ में बराबर है ।
यदि आप पुराने ब्राउज़रों की परवाह नहीं करते हैं, तो इसने मेरे लिए चाल चली।
// [optional] make sure focus is on the element
yourContentEditableElement.focus();
// select all the content in the element
document.execCommand('selectAll', false, null);
// collapse selection to the end
document.getSelection().collapseToEnd();
document.execCommand
अब अप्रचलित है developer.mozilla.org/en-US/docs/Web/API/Document/execCommand ।
श्रेणी के अंत में कर्सर सेट करना संभव है:
setCaretToEnd(target/*: HTMLDivElement*/) {
const range = document.createRange();
const sel = window.getSelection();
range.selectNodeContents(target);
range.collapse(false);
sel.removeAllRanges();
sel.addRange(range);
target.focus();
range.detach(); // optimization
// set scroll to the end if multiline
target.scrollTop = target.scrollHeight;
}
setCaretToEnd()
हर बार चालान न करें - इसे केवल तब ही लागू करें जब आपको इसकी आवश्यकता हो: जैसे कॉपी-पेस्ट के बाद, या संदेश की लंबाई को सीमित करने के बाद।
मुझे एक तत्व को संपादन योग्य बनाने की कोशिश में एक समान समस्या थी। क्रोम और फायरफॉक्स में यह संभव था लेकिन फायरफॉक्स में कैरेट या तो इनपुट की शुरुआत में चला गया या फिर इनपुट खत्म होने के बाद यह एक जगह चला गया। मुझे लगता है कि अंत उपयोगकर्ता के लिए बहुत भ्रामक, सामग्री को संपादित करने की कोशिश कर रहा है।
मुझे कई चीजों की कोशिश करने का कोई हल नहीं मिला। केवल एक चीज जो मेरे लिए काम करती थी, वह थी "पुरानी समस्या का समाधान करना", एक सादा पुराना पाठ-इनपुट इनसाइड माय डालकर। अब यह काम कर रहा है। "कंटेंट-एडिटेबल" की तरह लगता है कि अभी भी एज तकनीक से खून बह रहा है, जो काम कर सकता है या नहीं जैसा कि आप इसे पसंद करेंगे, संदर्भ के आधार पर।
फ़ोकस इवेंट के जवाब में संपादन योग्य अवधि के अंत में कर्सर ले जाना:
moveCursorToEnd(el){
if(el.innerText && document.createRange)
{
window.setTimeout(() =>
{
let selection = document.getSelection();
let range = document.createRange();
range.setStart(el.childNodes[0],el.innerText.length);
range.collapse(true);
selection.removeAllRanges();
selection.addRange(range);
}
,1);
}
}
और इसे इवेंट हैंडलर में बुलाएं (यहां प्रतिक्रिया दें):
onFocus={(e) => this.moveCursorToEnd(e.target)}}
के साथ समस्या contenteditable
<div>
और <span>
हल हो गई है जब आप शुरू में यह में लिखना प्रारंभ करें। इसके लिए एक वर्कअराउंड आपके div एलिमेंट पर फोकस इवेंट को ट्रिगर कर सकता है और उस फंक्शन पर, क्लियर और रीफिल कर सकता है जो पहले से ही div एलिमेंट में था। इस तरह से समस्या हल हो गई है और अंत में आप रेंज और चयन का उपयोग करके कर्सर को अंत में रख सकते हैं। मेरे लिए काम किया।
moveCursorToEnd(e : any) {
let placeholderText = e.target.innerText;
e.target.innerText = '';
e.target.innerText = placeholderText;
if(e.target.innerText && document.createRange)
{
let range = document.createRange();
let selection = window.getSelection();
range.selectNodeContents(e.target);
range.setStart(e.target.firstChild,e.target.innerText.length);
range.setEnd(e.target.firstChild,e.target.innerText.length);
selection.removeAllRanges();
selection.addRange(range);
}
}
HTML कोड में:
<div contentEditable="true" (focus)="moveCursorToEnd($event)"></div>