【发布时间】:2014-06-15 15:04:51
【问题描述】:
我有一个内部构建的 WYSIWYG 编辑器,它能够使用 JavaScript 范围和选择对象选择内容并将其转换为列表(它也可以执行其他操作)。这类似于在插入 BR 标记时将插入符号移动到行尾(我使用 Tim Down 的示例,提供 here)来实现这一点,但是我需要将光标保持在初始节点内,以便更多节点可以插入。初始节点将是 OL | UL 标记,我需要能够插入带有所选文本的列表项。
我用来处理这个的代码:
OverrideListCreation: function (commandName, showDefaultUI, commandValue, context) {
var html;
var contextHtml = context.range.htmlText;
var insertSuccess;
var element;
console.log("ContextHtml: " + contextHtml);
if (commandName == "insertorderedlist") {
element = this.designModeDocument.createElement("ol");
} else {
element = this.designModeDocument.createElement("ul");
}
element.setAttribute("class", "content");
element.setAttribute("style", "margin: 1em;");
insertSuccess = this.InsertNodeAtCursor(context, element, false);
element = this.designModeDocument.createElement("li");
element.setAttribute("class", "content");
element.setAttribute("style", "margin: 0em;");
if (contextHtml.search(/<br>/gi) > -1) {
console.log("ContextHtml Length: " + contextHtml.length);
console.log("Multiline Check - Passed");
var lines = contextHtml.split(/<br>/gi);
for (var i = 0; i < lines.length; i++) {
element.innerHTML = lines[i];
insertSuccess = this.InsertNodeAtCursor(context, element, false);
if (insertSuccess === false) {
return;
}
}
} else if (contextHtml.length > 1 && contextHtml.search(/<br>/gi) === -1) {
console.log("Single Line Check w/o BR - Passed");
element.innerHTML = contextHtml;
insertSuccess = this.InsertNodeAtCursor(context, element, false);
if (insertSuccess === false) {
return;
}
} else {
console.log("ContextHtml is empty, insert an empty list element");
insertSuccess = this.InsertNodeAtCursor(context, element, false);
if (insertSuccess === false) {
return;
}
}
return;
供参考:上下文对象代码:
GetDesignModeContext: function () {
var context = new Object();
try {
if (this.designModeDocument.selection) {
context.selection = this.designModeDocument.selection;
context.range = context.selection.createRange();
context.selectedText = context.range.text;
switch (context.selection.type) {
case "None":
case "Text":
context.parentElement = context.range.parentElement();
break;
case "Control":
context.parentElement = context.range.item(0);
break;
default:
context.parentElement = this.designModeDocument.body;
break;
}
}
else if (this.designModeDocument.getSelection || this.designEditor.getSelection) {
context.selection = this.designEditor.getSelection();
context.selectedText = context.selection.toString();
try {
context.range = context.selection.getRangeAt(0);
}
catch (e) {
context.range = this.designModeDocument.createRange();
}
function IsSelectedTextNode(container, offset, start) {
if (container.nodeType != 3) return false;
var startIndex = start ? offset : 0;
var endIndex = start ? container.nodeValue.length : offset + 1;
var text = container.nodeValue.substring(startIndex, endIndex);
return (context.selectedText == text);
}
var r = context.range;
var p = null;
if (r.startContainer == r.endContainer) {
if (r.collapsed) {
p = r.startContainer;
}
else if (r.startOffset - r.endOffset <= 1 &&
r.startContainer.hasChildNodes()) {
p = r.startContainer.childNodes[r.startOffset];
}
}
else if (IsSelectedTextNode(r.startContainer, r.startOffset, true)) {
p = r.startContainer;
}
else if (IsSelectedTextNode(r.endContainer, r.endOffset, false)) {
p = r.endContainer;
}
if (!p) p = r.commonAncestorContainer;
while (p.nodeType == 3) p = p.parentNode;
context.parentElement = p;
}
if (context.parentElement == null) return null;
if (context.parentElement.nodeType != 1) return null;
if (context.parentElement.ownerDocument != this.designModeDocument) return null;
}
catch (e) {
return null;
}
return context;
},
光标代码处的插入节点:
InsertNodeAtCursor: function (context, domElement, positionEnd) {
var selection, range;
if (typeof this.designModeDocument.getSelection != "undefined" && context.selection) {
//console.log("getSelection is supported by this browser && Context.Selection was not undefined.");
selection = this.designModeDocument.getSelection() || context.selection;
if ((selection.getRangeAt && selection.rangeCount) && context.range) {
//console.log("getRangeAt & rangeCount are supported by this browser && Context.Range is not undefined");
range = selection.getRangeAt(0) || context.range;
range.deleteContents();
//console.log("Inserting BR Element Node");
range.insertNode(domElement);
//console.log("Setting Position of Cursor");
if (positionEnd) {
range.setEndAfter(domElement);
range.setStartAfter(domElement);
} else {
}
//console.log("Selection Clean-up");
selection.removeAllRanges();
selection.addRange(range);
return true;
}
} else if (typeof this.designModeDocument.selection != "undefined" && context.selection) {
//console.log("Using alternate selection method.");
if (typeof selection.createRange && context.range) {
//console.log("Using alternate range method.");
range = selection.createRange || context.range;
var tmpElement = this.designModeDocument.createElement("div");
tmpElement.appendChild(domElement);
this.PasteHtml(range, tmpElement.innerHTML);
range.select();
this.designModeDocument.removeChild(tmpElement);
return true;
}
} else {
return false;
}
},
我最初的想法是将 setStartAfter 和 setEndAfter 函数更改为不移动光标,但这不起作用,这就是为什么在这些函数后面有一个空的 else 块。
编辑:我确实有一个旧版本的列表创建代码,它将获取选定的文本并通过用开始和关闭列表标签替换断行来围绕它构建列表项,之后它将它们粘贴到可编辑的文档中(最初的目标是 IE。原始代码是作为包含的脚本文件编写的,这就是它具有不同结构的原因。
function doCommandIERangeList(strCommand, bShowDefaultUI, strOptional) {
// Get a text range for the selection
var strHTML;
var strHTMLFromControl;
var tr = getIFrameDocument(_strIFrame).selection.createRange();
strHTMLFromControl = tr.htmlText;
//if there are break lines present create a new list
//otherwise we just want to switch between list types
if (strHTMLFromControl.search(/<BR>/gi) > -1) {
if (strCommand == "InsertOrderedList") {
strHTML = "<ol>";
} else {
strHTML = "<ul>";
}
strHTML += "<li>" + strHTMLFromControl.replace(/<BR>/gi, "</li><li>") + "</li>";
tr = getIFrameDocument(_strIFrame).selection.createRange();
if (strCommand == "InsertOrderedList") {
strHTML += "</ol>";
} else {
strHTML += "</ul>";
}
//IE Version Check to remove somewhat randomly placed <br> tags when trying to format a set of text instructions as a List Range
if (IsIE9()) {
strHTML = strHTML.replace(/[\r\n]/g, "");
}
if (IsIE10()) {
strHTML = strHTML.replace(/[\r\n]/g, "");
}
tr.pasteHTML(strHTML);
} else {
//needed to switch between ul and ol
tr.execCommand(strCommand, bShowDefaultUI, strOptional);
}
// Reselect and give the focus back to the editor
tr.select();
frames.editor.focus();
}
更新:我想出了如何构建 HTML(我将在下面发布代码)并插入到文档中,但是列表项在编辑器窗口中没有正确呈现。 有什么想法吗?
OverrideListCreation: function (commandName, showDefaultUI, commandValue, context) {
var html;
var contextHtml = context.range.htmlText;
var insertSuccess;
var parentElement,element;
console.log("ContextHtml: " + contextHtml);
if (commandName == "insertorderedlist") {
parentElement = this.designModeDocument.createElement("ol");
parentElement.setAttribute("type", "1");
} else {
parentElement = this.designModeDocument.createElement("ul");
parentElement.setAttribute("type", "disc");
}
parentElement.setAttribute("class", "content");
parentElement.setAttribute("style", "margin: 1em;");
if (contextHtml.search(/<br>/gi) > -1) {
console.log("ContextHtml Length: " + contextHtml.length);
console.log("Multiline Check - Passed");
var lines = contextHtml.split(/<br>/gi);
for (var i = 0; i < lines.length; i++) {
console.log("Lines @ " + i + ": " + lines[i]);
element = this.designModeDocument.createElement("li");
element.setAttribute("class", "content");
element.setAttribute("style", "margin: 0em;");
if (typeof element.innerHTML != "undefined") {
element.innerHTML = lines[i]
} else {
element.textContent = lines[i];
}
parentElement.appendChild(element);
}
} else if (contextHtml.length > 1 && contextHtml.search(/<br>/gi) === -1) {
console.log("Single Line Check w/o BR - Passed");
element = this.designModeDocument.createElement("li");
element.setAttribute("class", "content");
element.setAttribute("style", "margin: 0em;");
if (typeof element.innerHTML != "undefined") {
element.innerHTML = contextHtml
} else {
element.textContent = contextHtml
}
parentElement.appendChild(element);
} else {
console.log("ContextHtml is empty, insert an empty list element");
element = this.designModeDocument.createElement("li");
element.setAttribute("class", "content");
element.setAttribute("style", "margin: 0em;");
parentElement.appendChild(element);
}
insertSuccess = this.InsertNodeAtCursor(context, parentElement, false);
return;
指定类型属性(对 HTML 5 不友好)并没有解决我的问题,因此它们未被使用。
【问题讨论】:
标签: javascript html html-lists wysiwyg