Ngoài ra còn có một vấn đề khác.
Giải pháp của Nico Burns hoạt động nếu div contenteditable
không chứa các phần tử đa cấp khác.
Ví dụ: nếu div chứa div khác và các div khác chứa nội dung khác bên trong, có thể xảy ra một số sự cố.
Để giải quyết chúng, tôi đã sắp xếp các giải pháp sau đây, đó là một sự cải tiến của 's Nico một:
//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: https://stackoverflow.com/questions/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: https://stackoverflow.com/questions/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 || {}));
Cách sử dụng:
var editableDiv = document.getElementById("my_contentEditableDiv");
cursorManager.setEndOfContenteditable(editableDiv);
Bằng cách này, con trỏ chắc chắn được đặt ở cuối phần tử cuối cùng, cuối cùng được lồng vào nhau.
EDIT # 1: Để trở nên chung chung hơn, câu lệnh trong khi cũng nên xem xét tất cả các thẻ khác không thể chứa văn bản. Các phần tử này được đặt tên là các phần tử void và trong this question có một số phương pháp về cách kiểm tra xem một phần tử có bị vô hiệu hay không. Vì vậy, giả định rằng tồn tại một hàm gọi là canContainText
trả true
nếu đối số không phải là một yếu tố vô hiệu, các dòng mã sau đây:
contentEditableElement.lastChild.tagName.toLowerCase() != 'br'
nên được thay thế bằng:
canContainText(getLastChildElement(contentEditableElement))
EDIT # 2: Mã ở trên được cập nhật đầy đủ, với mọi thay đổi được mô tả và thảo luận
Thú vị, tôi đã có thể mong đợi trình duyệt tự động xử lý trường hợp này (không phải là tôi ngạc nhiên vì nó không có, các trình duyệt dường như không làm những điều trực quan với nội dung có thể chỉnh sửa được). Bạn có một ví dụ về HTML, nơi giải pháp của bạn hoạt động nhưng tôi không? –
Trong mã của tôi có một lỗi khác. Tôi sửa nó rồi. Bây giờ, bạn có thể xác minh rằng mã của tôi hoạt động trong [trang này] (http://html5demos.com/contenteditable), trong khi mã của bạn không phải là –
Tôi gặp lỗi khi sử dụng hàm của bạn, giao diện điều khiển cho biết 'Lỗi Loại không bắt buộc: Không thể đọc property 'nodeType' của null' và điều này là từ hàm getLastChildElement đang được gọi. Bạn có biết điều gì có thể gây ra vấn đề này không? – Derek