构建您自己的 JavaScript 编辑器
实现您的 JavaScript 编辑器的分步指南。
引言
几个月前,我遇到一个需要构建自己的编辑器的情况,该编辑器将接受某些标签和属性。我认为分享我是如何以浏览器独立的方式构建我的编辑器会非常有趣。要查看演示,请单击此处。
使用代码
当时我想到的第一件事是我的设计器的容器是什么,一个IFrame
,一个div
,还是什么。然后我决定把它做成一个div
,我会将其 contentEditable 属性设置为 true。
第二件事是好的,现在我的 div
可以在设计时被最终用户编辑,我如何将标签应用于选定的内容。下面你会找到一个我构建的实用程序库,它具有构建编辑器所需的基本的各种方法。在下一部分中,我将展示并解释 Editor
类。现在,让我们从实用程序库中的重要方法开始。
// This function is used to get the selected Range.
GetSelectedRange : function(controlContent){
var selectedRange = null;
if(document.selection)
selectedRange = document.selection.createRange();
else if(window.selection)
selectedRange = window.selection.createRange();
if(selectedRange == null){
if(window.getSelection() != null)
{
if (this.Exists(window.getSelection().getRangeAt))
selectedRange = window.getSelection().getRangeAt(0);
else { // Safari!
var range = document.createRange();
range.setStart(window.getSelection().anchorNode,
window.getSelection().anchorOffset);
range.setEnd(window.getSelection().focusNode,
window.getSelection().focusOffset);
selectedRange = range;
}
}
}
var t = null;
if(selectedRange != null && this.BrowserType.IE)
{
t = this.CheckParentById(controlContent.id,selectedRange.parentElement());
}
else{
t = this.RangeCompareNode(selectedRange,controlContent);
}
if(!t && controlContent != null)
selectedRange = null;
return selectedRange;
}
上面的代码以一种浏览器独立的方式获取选定的范围对象,以便稍后在编辑器中使用它。然后它检查选定的范围是否在我们的编辑器 div
范围内。如果不是,则返回 null
,否则返回该范围。在这里,我们检查该范围是否在父节点内,还是不在 Internet Explorer 之外的其他浏览器中。
// This function is used to get if the selected range in the
//required parent in firefox.
RangeCompareNode : function(range,node){
var nodeRange = node.ownerDocument.createRange();
try {
nodeRange.selectNode(node);
}
catch (e) {
nodeRange.selectNodeContents(node);
}
var nodeIsBefore =
range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
if (nodeIsBefore && !nodeIsAfter)
return false;
if (!nodeIsBefore && nodeIsAfter)
return false;
if (nodeIsBefore && nodeIsAfter)
return true;
return false;
}
在这里,我们检查范围是否在父节点内,或者不是用于 Internet Explorer 浏览器
// This function is used to Check whether a parent element
// contains the child element or not using the parentId.
CheckParentById : function(parentId,child){
while(child != null){
if(child.id == parentId) return true;
child = child.parentNode;
}
return false;
}
基本上,编辑器在 RBMEditor
命名空间中初始化。我将重点介绍编辑器中的一些重要方法。Execute Command 方法首先获取当前选定的范围,然后从该范围中提取 HTML。之后,它会检查效果是否已经应用,如果是,则使用 ExecuteUndoCommand
方法删除该效果。如果未应用该效果,那么我们从命令创建一个新元素。然后,SetHTMLFromSelection
方法将使用选定的 HTML 中的新命令元素替换当前选定的范围。
ExecuteCommand: function(sCommand,id,value,name,isControl){
var selection = RBM.GetSelectedRange(this.controlContent);
if(selection == null)
return;
var html = this.GetHTMLFromSelection(selection);
var undo = this.ExecuteUndoCommand(sCommand,new String(html));
if(!undo){
var element = this.CreateNewNode(sCommand,id,value,html);
if(element != null)
this.SetHTMLFromSelection(selection,element);
}
}
GET
HTML 方法将解析 HTML 和代码,并从 HTML 代码中删除不受支持的标签和属性。
GetHTML: function(sCode){
//return sCode;
var ts = new String(sCode);
var parts = ts.split("<");
var subpart = '';
var i = 0;
var j = 0;
var totalStr = '';
var tagName = '';
var readTag = true;
var readSub = true;
for(i = 0; i < parts.length;i++)
{
if(parts[i] == '')
continue;
subpart = '';
tagName = '';
readTag = true;
readSub = true;
for(j = 0; j < parts[i].length; j++)
{
if(parts[i].substr(j,1) == '>')
readSub = false;
if(parts[i].substr(j,1) == ' ' || parts[i].substr(j,1) == '>')
readTag = false;
if(readSub == true)
subpart = subpart + parts[i].substr(j,1);
if(readTag == true)
tagName = tagName + parts[i].substr(j,1);
}
if(this.IsSupportedTag(tagName) == false)
{
parts[i] = parts[i].replace(subpart + '>',' ');
parts[i] = parts[i].replace('/' + tagName + '>',' ');
}
else
{
parts[i] = '<' + parts[i];
parts[i] = this.RemoveUnknownAttributes
(subpart.replace(tagName,''),parts[i]);
}
}
var retValue = '';
for(i = 0; i < parts.length;i++)
{
if(parts[i] != '')
retValue = retValue + parts[i];
}
var tnewValue = new String(retValue);
return tnewValue;
}
那么如何使用编辑器。首先,你需要从 Editor
类初始化一个对象,并给它你想作为编辑器的 div
id,但要初始化它,你需要这样放
var editor;
RBM.AddListener(window,'load',RbmInit);
function RbmInit(){
editor = new RBMEditor.Editor('oDiv')
}
现在要调用命令,只需键入以下内容,您可以将 BOLD 命令更改为 EditorCommands
中列出的任何命令,你可以在代码中找到或添加其中的任何其他命令。
editor.ExecuteCommand(RBMEditor.EditorCommands.BOLD);
最后,希望这篇文章能帮助你开始构建自己的编辑器。如果您对更高级的技术或更多功能(例如如何添加链接、图像等)有任何疑问,请随时问我。稍后我将尝试为如何使用此类命令增强编辑器单独发帖。
历史
- 2009 年 3 月 25 日:初始发布