posts - 615, comments - 10490, trackbacks - 594, articles - 0
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2007-01-08 08:38  webabcd  阅读(...)  评论(...编辑  收藏
原文地址:http://aspalliance.com/1092_Rich_Text_Editor_Part_I
[原文源码下载]


开发一个自己的HTML在线编辑器(一)


摘要
在本文中,Haissam Abdul Malak将给大家详细介绍如何使用javascript开发一个HTML在线编辑器,它可以应用于web应用程序中,特别是论坛,社区和博客。这个编辑器支持基于XHTML创建文本的功能。


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


文章内容
介绍
在用户控件中添加HTML代码
javascript文件
编辑器属性
添加一个样式表
结论


介绍
我的一个朋友在一个正在开发的项目(一个博客网站)中遇到了一些问题,是关于文本编辑器的。在研究了所有免费的编辑器之后,他发现没有一个是他所需要的,所以我接下了这个任务,帮他开发一个HTML在线编辑器的用户控件,我认为和大家分享这个控件是个好主意,达到了知识共享的目的。

这个编辑器包括如下一些特性
1、工具栏包括了全部的功能(下面已列出)
    ·排列(居左,居中,居右)
    ·字体格式(加粗,下划线,斜体,字号,字体,文字颜色)
    ·计算单词数,删除格式,插入水平线,撤销,重复,插入字符

2、HTML模式结合到了一个框架中,文本模式结合到了另一个框架中。注意这两个框架只能有一个被显示。

3、有两个图标,分别是“HTML视图”和“设计模式”,一个文本框用来显示单词数,最后有两个隐藏文本框用来存储用户输入的数据。

要看懂这个实例,你需要有javascript和HTML的相关知识。


在用户控件中添加HTML代码
这部分我们将创建一个用户控件(hamHtmlEditor.ascx),并且在其中写一些必需的HTML代码。注意该用户控件不包含<head>, <body> 或 <form> 标记。

我们将创建3个表格来显示所有的图标,另外还要有3个下拉列表框。其中2个表格放在控件的顶端,1个表格放在控件的底部。每个图标都有3个事件,分别是onmouseover,onmouseup,onclick,处理这些事件的是javascript文件中的javascript代码。把javascript代码和HTML代码分开,可以让你更容易理解和调试。然后我们将创建3个层,第一个层包含一个已经有的HTML页(TextArea.htm)。我使用一个HTML页是因为如果用户输入了一个rul,它可以自动的把它转换为HTML代码并呈现在你的文本中。第二个层包括了1个textarea,在用户使用期间,它用来显示HTML代码(默认隐藏)。第3个层包含了一些符号,当用户点击“插入符号”后,这个层将被现实(默认隐藏)。

为了使用户能够输入文字,你必须在控件被使用的时候,将其设置为“设计模式”

列表1
onload="document.frames['HamHtmlEditor1_content'].document.designMode='on'"

请下载这个项目以知道如何正确的创建所有的HTML标记
图1



javascript文件
这部分我们将写一些处理用户事件的函数。首先,我们将定义一些全局变量,其中每一个变量都有自己的功能,但最多的是用来存储图标在被单击之前或者默认的值—“No”。只有一个变量有另一个功能,这个变量是sourceText,它用来存储用户输入的文本。

列表2
var sourceText= '';
var imgStatusBold = 'No';
var imgStatusItalic = 'No';
var imgStatusUnderLine = 'No';
var imgStatusLeft = 'No';
var imgStatusCenter = 'No';
var imgStatusRight = 'No';
var imgStatusRemoveF= 'No';
var imgStatusWCount = 'No';
var imgStatusInsertL = 'No';

基于上面这些变量的值,当用户点击了1个图标,将检查相关的变量是否是“Yes”,它用来指明相关的图标并不是第一次加载时的图标。当用户控件全部加载完毕,我们将立即设置这些图标为他们的初始状态,当我们需要改变图标状态的时候,如果原来的值为“No”,就把它变为“Yes”。

有三个功能分别被称作onmouseover,onmouseup,和onclick。Onmouseover触发函数ChangeImg(),作用是当用户把鼠标放到图标上则改变所显示的图标的状态,这个函数需要两个参数(容器ID和新图标路径)。注意工具栏上的图标在web应用程序中被放置到“Images”文件夹下。

列表3
function ChangeImg(id, imgsrc)
{
    
var imgSrc = "Images/" + imgsrc;
    document.getElementById(id).src 
= imgSrc;
}

Onmouseup函数的功能是用户的鼠标离开一个图标时,把这个图标该回其初始的状态,它需要3个参数(容器ID,新图标路径和1个变量)

列表4
function ReturnImg(id, imgsrc, ownVar)
{
    
if(ownVar == 'No')
    
{
        
var imgSrc = "Images/" + imgsrc;
        document.getElementById(id).src 
= imgSrc;
    }

}

第3个参数用来说明这个图标是否是被选中的状态,默认值是“No”。

单击图标后执行一个指定的动作,一个单独的javascript方法被调用,每一个动作都有标准的写法。

列表5
document.frames['HamHtmlEditor1_content'].document.execCommand('JustifyLeft',false,null);

使用上面这个方法可以使用户输入的文字居左。ExecCommand将在文档中执行一个命令。它使用一个预先组合到一起的功能来直接在浏览器中操作页面的布局。注意,只有在页面完全加载完毕后才能使用它。

列表6
function MakeBold(boldover, bold)
{
    
var img = document.getElementById('Bold')       
    
var imgBold = "Images/" + boldover
    
var imgNotBold = "Images/" + bold
    img.src 
= imgBold;
                  
    
if(imgStatusBold == 'Yes')
    
{
        imgStatusBold
='No';
        img.src 
= "Images/" + bold;
    }

    
else
    
{
        imgStatusBold
= 'Yes'
    }

    document.frames['HamHtmlEditor1_content'].document.execCommand('bold',
false,null);
    document.frames['HamHtmlEditor1_content'].focus();                
}

上面这段代码的功能是使用户输入的文字加粗的。当用户点击了加粗按钮,我们要改变这个按钮的状态。设置相关的全局变量为“Yes”,意思是该按钮已被选中。每次用户单击按钮,我们都要检查相关的变量,来确定之前按钮是否是被选中的状态,然后我们给选中的文字加粗。它需要两个参数,第一个用来存储鼠标经过时加粗按钮的图标路径,第二个用来存储正常加粗按钮的路径。相同的语法也在,斜体和下划线中适用。

对文字进行排列,我们使用与MakeBold()相似的函数,但是,3个排列功能的按钮只能有一个是被选中状态,其它两个要变为初始的未被选中的状态。

为了完成上面指出的那个execCommand命令,请参考
http://www.course.com/downloads/newperspectives/crweb3/documents/dhtml_t02.html

现在我们创建一个计算用户输入的单词数的函数。定义一个变量,默认值为0。在定义另一个变量用来存储用户输入的文本,我们将拆开这个变量,并且将拆开的结果保存到一个数组中,然后检查数组内每个元素的长度,如果是零则不计数,如果不是零则计数变量加1。计数完后,我们把该值赋给用于显示计数的文本框。

列表7
var wordCount = document.frames['HamHtmlEditor1_content'].document.body.innerText;
var count = 0;
countWithSpace 
= wordCount.replace('\n', '');
countWithoutSpaces 
= countWithSpace.split(' ');
for(i=0;i<countWithoutSpaces.length;i++)
{
    
if(countWithoutSpaces[i].length>0)
    
{
        count 
+=1;
    }

    window.parent.document.getElementById('HamHtmlEditor1_TxtCount').value 
= count;
}

当单击“删除格式”按钮后,我们调用一个javascript函数,发送命令“RemoveFormat”给execCommand用来删除选中文本的格式。

如果想删除某些已经有格式的文本的格式,这个功能将是非常有用的。

列表8
function RemoveFormating()
{     
    document.frames['HamHtmlEditor1_content'].document.execCommand('RemoveFormat');
    document.frames['HamHtmlEditor1_content'].focus();
}

“撤销”和“重做”功能与上面这段javascript类似。给execCommand发送“undo”或“redo”将执行撤销和重做功能。需要一个参数来指明命令的名字。

列表9
function Formats (style)
{
    document.frames['HamHtmlEditor1_content'].document.execCommand(style);
    document.frames['HamHtmlEditor1_content'].focus();
}

当用户单击“插入符号”按钮,我们将在该按钮之后显示第3个层来出示所有符号图片。我们使用javascript来做这件事。

列表10
function ShowDiv(images)
{
    
var div = document.getElementById(images);
    
if(div.style.display == 'block')
        div.style.display 
= 'none';
    
else
        div.style.display 
= 'block';
}

图2:用户单击“插入符号”后,编辑器的外观


当用户点击第3个层的任意一个符号时,另一个javascript函数被调用,它用来在编辑器中指针的位置处插入符号。这个函数需要3个参数。第一个参数用来指定execCommand的命令来在文档中插入一个图片(InsertImage),第二个参数是图片的路径,第三个参数是该图片所在的层的id。注意所有的符号在web应用程序中被放置在一个“Emoticons”文件夹下。

列表11
function insertImages(style,url,images)
{
    document.getElementById(images).style.display 
= 'none'
    document.frames['HamHtmlEditor1_content'].focus();
    HamHtmlEditor1_content.document.execCommand(style,'',url)
    document.frames['HamHtmlEditor1_content'].focus();
}

当单击“HTML视图”按钮后,第二个层被显示,而第一个层则被隐藏。这个层的“readonly”属性被设置成了“true”,意思是用户在此状态下不能对其编辑,我们只能在这个层里看到HTML代码。

列表12
function TransformtoHtml()
{
    document.getElementById('HamHtmlEditor1_Div2').style.display 
= 'block';
    document.getElementById('HamHtmlEditor1_Div2').innerText 
= 
    document.frames['HamHtmlEditor1_content'].document.body.innerHTML;
}

当单击“设计模式”按钮后,第二个层则被隐藏

列表13
function TransformToText()
{
    document.getElementById('HamHtmlEditor1_Div2').style.display 
= 'none';
}

下拉列表用来让用户选择预先设定好的数据。

第一个是字号,尺寸在1(10pt)到7(22pt)之间。这个按钮被单击后,要调用一段javascript函数。这个函数获得用户在下拉列表里选择的值,然后作为第三个参数发送给execCommand。第一个参数是“FontSize”,用来执行设置文字大小的命令。注意,下拉列表中的字号大小是预先在用户控件中的HTML代码里定义好的。

列表14
function ChangeFont()
{
    
var fontSize = document.getElementById('FontDropDownonchange');
    document.frames['HamHtmlEditor1_content'].document.execCommand('FontSize',
0,fontSize.options[fontSize.selectedIndex].text);
    document.frames['HamHtmlEditor1_content'].focus();
}

接下来这段代码用来改变字体。第一个参数是“FontName”,用来执行设置文字字体的命令,第二个参数是false或者0,第三个参数是用户所选择的文字。

列表15
function ChangeFontName()
{
    
var fontName = document.getElementById("FontFamilyName");
    document.frames['HamHtmlEditor1_content'].document.execCommand('FontName',
false,fontName.options[fontName.selectedIndex].text);
    document.frames['HamHtmlEditor1_content'].focus();
}

第三个下来列表用来选择所选文字的颜色。这些颜色是预先定义好的,如果你想可以设置更多的颜色,请修改相关的HTML代码。

列表16
function ChangeFontColor()
{
    
var fontColor = document.getElementById("Color");
    document.frames['HamHtmlEditor1_content'].document.execCommand('ForeColor',
false,fontColor.options[fontColor.selectedIndex].text);
    document.frames['HamHtmlEditor1_content'].focus();
}

最后的功能用来把用户输入的文本值存储到一个隐藏字段中,其详细的HTML值存储到另一个隐藏字段中。这样即使编辑器失去焦点,也可以获取到值,下一部份你可以看到在编码的过程中通过使用两个属性来取得隐藏字段的值。

列表17
function CloneText()
{
    document.getElementById('HamHtmlEditor1_ContentTxt').innerText 
= document.frames['HamHtmlEditor1_content'].document.body.innerText;
    document.getElementById('HamHtmlEditor1_ContentHtml').value 
= document.frames['HamHtmlEditor1_content'].document.body.outerHTML;
}

这部分完成后,你的javascript文件就准备完了。你如果想在你的用户控件中使用这个文件,就需要在代码中加入<head>标签。如下
<script src="HTMLEditor.js" language="javascript" type="text/javascript></script>

如果你想调试javascript,需要加一个词“debugger”。这样编译时将开始调试模式。或者你也可以设置你的IE浏览器,把“禁用脚本调试(Internet Explorer)”和“禁用脚本调试(其他)”两个复选框的选中状态取消,然后添加你的端点。(译者注:调试js可以参考这篇文章:在Visual Studio中调试JavaScript


编辑器属性
如果想将用户输入的文本保存为.txt文件或者把HTML代码保存到另一个.txt文件,你可以在这个控件中添加以下两种属性:

首先在你的ascx.cs页面创建两个字段。

列表18
protected System.Web.UI.HtmlControls.HtmlInputText ContentTxt;
protected System.Web.UI.HtmlControls.HtmlInputText ContentHtml;

创建两个被保护的变量,保存以上创建的字段的值。

列表19
protected string _text;
protected string _html;

第一个属性被称为“ContentText”,它可以获取文本并在你的后置代码中赋值给一个变量。

ContentTxt被声明成一个HtmlInputText控件,它的Value属性被存储到_text字符串变量中。

列表20
public string ContentText
{
    
get 
    
{
        
return _text = ContentTxt.Value;
    }

    
set
    
{
        _text 
= value;
    }

}

第二个属性被称为“ContentInnerHtml”,它可以获得详细的HTML代码。

ContentHtml被声明成一个HtmlInputText控件,它的Value属性被存储到_html字符串变量中。

列表21
public string ContentInnerHtml
{
    
get
    
{
        
return _html  = ContentHtml.Value;
    }

    
set
    
{
        _html 
= value;
    }

}


添加一个样式表
在这部分我们将创建一个样式表(Styles.css),用来修改工具栏和框架的UI。我们将设置工具栏的背景颜色为蓝色。框架右侧和底部的也设置成相同的颜色。通过修改下面的代码,你可以随便设置控件的界面(UI)。
列表22
.HtmlView
{
    background-color
:white;
    border-bottom-width
:medium;
    border-bottom-style
:solid;
    border-bottom-color
:cornflowerblue;
    border-right-width
:medium;
    border-right-color
:cornflowerblue;
    border-right-style
:solid;
}

.FirstDiv
{
    background-color
:white;
    border-bottom-width
:medium;
    border-bottom-style
:solid;
    border-bottom-color
:cornflowerblue;
    border-right-width
:medium;
    border-right-color
:cornflowerblue;
    border-right-style
:solid;
}

.toolbar
{
    background-color
:cornflowerblue;
    background-repeat
:repeat;
}

现在在你用户控件的<head>标签内链接上这个样式表,代码如下:
<LINK href="Styles.css" type="text/css" rel="stylesheet">

图3


注意如果你要在用户控件中包含多个实体,你必须为这些div层创建动态的标识。请注意,div层的ID被设置成了“userControlID_divlayer”。


结论
我们可以看到,开发你自己的HTML在线编辑器并不是很困难。在这篇文章里我详细的解释了javascript语言和XHTML。这是HTML在线编辑器的第一个版本,我们非常感谢你使用它并且提供给我们你的意见。它的第二个版本,将会有更多的特性,如果你有什么好的注意,欢迎告诉我们。我们目前正在开发第二个版本,它也将通过这个网站发布出来,其会增加复制,粘贴,剪切,项目符号,项目编号,打印等功能以及一个可自定义的工具栏。

希望这篇文章有阅读的价值。

[原文源码下载]

祝编程愉快!