原文地址:http://aspalliance.com/1156_Rich_Text_Editor__Part_II
[原文×××]


[翻译]开发一个自己的HTML在线编辑器(二)


原文发布日期:2007.02.27
作者: Haissam Abdul Malak
翻译: webabcd


文章内容


介绍
在我们一起研究了如何开发一个HTML在线编辑器后(第一部分在这里 http://aspalliance.com/1092_Rich_Text_Editor_Part_I  )(译者注: 中文在这里),现在来给它增加一些特性,扩展它的功能,使它更实用。本文我们将了解这些新的特性是如何实现的,所有的新增功能都是用javascript来写的。

从之前的文章你看到了开发一个你自己的HTML在线编辑器是多么简单。当然,我们的第一个版本只包括一些标准功能,现在,我们要给它增加一些新的功能,我敢说,它将包括更多的特性并且更加实用。

下面列出这些新增的特性
1、删除线:可以给用户输入的文本增加删除线
2、减少/增加缩进:可以减少或增加文本的缩紧
3、插入图片:可以新开一个窗口让用户选择需要上传的图片,然后直接插入到编辑器里
4、复制,剪切和粘贴:通过剪切板实现复制,剪切和粘贴的功能
5、打印:在文本模式的时候可以调出打印对话框进行打印
6、项目符号和编号:可以在文本的开头增加项目符号和编号
7、插入线:可以在文本中插入一条线

在我们的用户控件里增加一些HTML代码
这部分我们将在工具栏处增加一些新的HTML元素。我们主要是放置了一些图片,为了实现上面提及过的行为并且处理这些事件以实现它们的功能。

列表1
<IMG class=StrikeOut id=Strikethrough
οnmοuseοver="ChangeImg('Strikethrough','strikethrough.over.gif')"
title="Strike Through" this.HamEditorChildID %>' )"
οnmοuseοut="ReturnImg('Strikethrough','strikethrough.gif',imgStatusUnderLine)"
src="Images/strikethrough.gif" />
 
上面的列表增加了一个img的HTML控件,它的onmouseover事件将调用一段javascript函数(我之前的文章已经对此解释过了),以改变图片的选中状态,onclick事件将调用另一段javascript函数以得到选中的文本,onmouseover将返回图片最初的状态。本次新增的功能除了插入图片外都将使用于此相同的概念。

请下载源码以查看所有的HTML标签是如何创建的

图1
 
javascript文件
这一部分我们将在已经创建好的javascript文件内增加一些新的功能,从而去处理这些新特性的事件。所有的这些功能都被定义到了这个javascript文件内,然后被编辑器引用

列表2
function Formats(style,editorId)
{
         // 存储Iframe的id
         var finalDivId = editorId + '_content';
                                    
         // 设置焦点
        document.frames[finalDivId].focus();
                                    
         // 应用新的命令
        document.frames[finalDivId].document.execCommand(style);
                                    
         // 设置焦点
        document.frames[finalDivId].focus();
}
 
本文所列的几乎所有的新增的事件处理都会使用上面的功能。它有两个参数:第一个参数是需要应用的命令,例如复制、粘贴之类的没;第二个参数是编辑器的id。我们使用一个相同的功能(execCommand)来应用这些变化。

列表3
function SetBorders(id)
{
         // 设置
         var imgBorder = document.getElementById(id);
        imgBorder.style.borderStyle = "solid";
        imgBorder.style.borderWidth = "thin";
        imgBorder.style.borderColor = "#688B9A";
}
 
在插入表情的时候将会调用上面的函数。当鼠标经过了一个表情文件,我们将会调用这个函数设置表情图片的边框。用这种方法,可以方便用户观察到鼠标是经过了哪一个表情图片。注意我们增加了一个“x”图片,用于当用户不需要选择任何表情图片的时候关闭div层。

图2
 
列表4
function ClearBorders(id)
{
         // 清除
         var imgBorder = document.getElementById(id);
        imgBorder.style.borderStyle = "solid";
        imgBorder.style.borderWidth = "thin";
        imgBorder.style.borderColor = "white";
}
 
当鼠标离开一个表情图片的时候清除它的边框样式则调用这个函数

列表5
function SetImage(editorId,path,e)
{
         // 获得单击位置
         var height = e.clientY + parseInt('5');
         // 获得被单击图片的高度
         var offsetHeight = parseInt(e.offsetY);
        height = height - offsetHeight;
                                            
         // 获得单击位置(宽)
         var width = e.clientX
         // 获得被单击图片的宽度
         var offsetWidth = parseInt(e.offsetX);
        width = width - offsetWidth;
                                            
         // 存储iframe的id
         var finalDivId = editorId + '_content';
        path = unescape(path);
                                                        
         // 从用户的电脑里插入一个图片    
        window.open('UploadImages.aspx?path=' + path +
         '&f=' + finalDivId, null,'width=500px,height=50px,titlebar=no,menubar=no,statusbar=no,toolbar=no,top='
         + height + 'left=' + width );                                                                        
}
 
我们创建了一个新的被称作UploadImages.aspx的webform,它来实现插入图片的特性。当用户单击了插入图片的图标后,这个form被打开,它允许用户从他/她的电脑内选择一个图片上传到服务器从而实现把图片插入到编辑器内的功能。这个webform还包括了两个文本框,用于让用户指定他/她上传图片后图片所显示的宽度和高度。当这个webform打开的时候显示如下

图3
 
用户已经可以浏览他/她的电脑选择一个图片并上传到服务器了,我们是在后置代码中处理文件上传的。我提供了一个选项,可以让管理员设置图片上传到服务器后所存放的目录。我将在后置代码的部分中详细解释这些。我们规定高度属性的最小值为100px,宽度属性的最小值为150px,并且这也是默认值

列表6
function insertsImage(p_w_picpathurl,editorId,height,width)
{
        opener.document.frames[editorId].focus();
                        
         if(p_w_picpathurl != "" | editorId!= "")
        {
                p_w_picpathurl = unescape(p_w_picpathurl);
                 var p_w_picpathurl = p_w_picpathurl + ' "'    + "width= " + width + "px " + " " + "height= "+ height + "px";

                opener.document.frames[editorId].document.execCommand('InsertImage', false,p_w_picpathurl);
        }
        opener.document.frames[editorId].focus();
}
 
当用户点击了插入图片后将调用这段函数。在这个单击事件中,我们上传了文件并且通过javascript把这个图片插入到编辑器中,显示的宽度和高度就是我们所指定的

图4
后置代码
这部分我们将了解如何在后置代码中实现上传图片的功能,并且将知道管理员如何设置图片上传的路径。

列表7
public string FilePath
{
        get
        {
                 return _filePath;
        }
        set
        {
                _filePath = Server.HtmlEncode(Request.ApplicationPath + value);
        }
}
 
上面的这个string类型的属性用于让管理员设置图片上传的默认路径。接下来的列表将告诉你如何在你的webform中指定这个路径。

列表8
InBlock.gif string p_w_picpathPath = "/UserImages";
InBlock.gif((hamHtmlEditor) this.FindControl( "HamHtmlEditor1")).FilePath = p_w_picpathPath;
 
列表9
public string Location
{
        get
        {
                return _location;
        }
        set
        {
                _location = value;
        }
}
 
为了使图片上传到web服务器后可以直接插入到编辑器里,我们需要使用上面这个属性,它用于获得编辑器的ID

列表10
InBlock.gif if (heightValidator.IsValid && widthValidator.IsValid)
InBlock.gif{
InBlock.gif         string elementToInsert = Request.QueryString[ "f"];
InBlock.gif         if(UploadImage.PostedFile != null && UploadImage.PostedFile.ContentLength > 0)
InBlock.gif        {
InBlock.gif                 try
InBlock.gif                {
InBlock.gif                         string fileName = System.IO.Path.GetFileName(UploadImage.PostedFile.FileName);
InBlock.gif                         string fileLocation = Request.QueryString[ "path"] + "/" + fileName;    
InBlock.gif                         this.ImagePath = Server.HtmlEncode(fileLocation);
InBlock.gif                         this.Location = elementToInsert;
InBlock.gif                        Button1.Enabled = false;
InBlock.gif                        UploadImage.PostedFile.SaveAs(Server.MapPath(fileLocation));
InBlock.gif                }
InBlock.gif                 catch(Exception ex)
InBlock.gif                {
InBlock.gif                        Response.Write( "<script language=javascript>alert('"+ex.Message.ToString().Replace( @"\",@"\\")+ "');</script>");
InBlock.gif                }
InBlock.gif                 finally
InBlock.gif                {
InBlock.gif                        Button1.Enabled = true;
InBlock.gif                }
InBlock.gif        }
InBlock.gif}
 
上面这段代码是写在插入图片按钮的点击事件里的。它的作用是上传图片到指定的路径,try catch块用于处理异常事件。

注意:有一个要非常注意的地方就是ASPNET(注:windows 2003 下是NETWORK SERVICE)用户是否有你的上传目录的写入权限。

列表11
public bool ShowHeader
{
        get
        {
                return _Header;
        }
        set
        {
                _Header = value;
        }
}
 
这是一个Boolean类型的属性。如果设置它为false则工具栏不会显示。

图5
 
当你把ShowHeader属性设置为false的时候编辑器显示如上。工具栏和其他的图标都将被隐藏。

图6
 
这就是增加了一个新的特性之后的编辑器的最终版本


结论
这个编辑器的版本只在IE中进行了测试。下一个版本中我将让它在更多的浏览器中工作。如果你有增强这个编辑器功能的建议或者提出其中的bug,我将非常欢迎。我也会把它封装成一个自定义控件,使你能更简单的使用它。希望你能从本文中获得一些有用的信息。

[原文×××]
 
祝编程愉快!