dojo/text!.
Dojo Rich Text编辑器Dijit.Editor旨在使外观和工作像文字处理程序一样。 它具有工具栏,HTML输出和支持新命令,新按钮和其他功能的插件体系结构。 而且,您不必担心浏览器不兼容。 该编辑器支持多种浏览器,包括Internet Explorer(IE)6/7/8,Firefox3,Chrome和Safari。
在本文中,了解Dojo富文本编辑器的基础知识以及如何使用Dojo提供的插件来提高性能。 您还将创建自己的插件,并学习如何扩展编辑器工具栏。
Dojo Rich Text编辑器
图1显示了经典的Dojo Rich Text Editor。 它的工具栏包含几个有用的命令,例如剪切,复制和粘贴。 您可以以WYSIWYG格式编辑内容。
图1. Dojo Rich Text编辑器
使用编辑器非常简单。 第一步是要求进入您使用编辑器的页面。 在进行所有dojo.require调用的位置(通常是head脚本标签)执行此操作。 您还需要导入CSS文件以选择主题,例如Claro。 确保将body元素CSS类设置为claro
,如清单1所示。
清单1.导入编辑器类定义
<html>
<head>
<title>Dojo Rich Text Editor</title>
<style type="text/css">
@import "../../../dijit/themes/claro/claro.css";
</style>
<script type="text/javascript">
dojo.require("dijit.Editor");
</script>
</head>
<body class="claro">
</body>
</html>
创建编辑器有两种方法:以编程方式或以声明方式。 两种方法是相同的。 清单2显示了如何以声明方式创建编辑器。
清单2.以声明方式创建编辑器
<div dojoType="dijit.Editor" id="editor1">
<p>
This is the content of the editor.
</p>
</div>
如果浏览创建的编辑器的DOM树,则会发现该编辑器由两部分组成:工具栏和iframe区域。 iframe文档的designMode
属性设置为on
,它使您可以直接编辑iframe的内容。 这是编辑器的动力。
启用设计模式后,浏览器使您可以通过调用内置命令来修改内容。 例如,您可以通过在Firefox中调用命令execCommand('bold',false, null)
来将所选文本设置为粗体。 每个浏览器中的内置命令都不同。 幸运的是,编辑器可以进行标准化,因此您可以调用编辑器提供的统一API来修改内容。
要使用Dojo Rich Text Editor,请单击工具栏上的按钮图标以触发事件(例如,单击),如图2所示。事件由编辑器或其插件捕获。 通过调用内置命令或直接修改DOM节点,可以更改iframe文档的DOM树。
图2.处理编辑请求的工作流程
外挂程式
通过Dojo Rich Text Editor的可插入体系结构,您可以通过在编辑器中实现和注册插件来扩展功能。 插件是为编辑器添加功能或更改编辑器行为的工具。 Dojo包括几个编辑器插件,您也可以编写自己的插件。
默认情况下会启用某些插件,例如“撤消”,“重做”,“剪切”和“复制”。 大多数插件都有一个关联的工具栏按钮,例如FindReplace插件。 某些插件(例如EnterKeyHandling)会在不更改工具栏的情况下影响编辑器的行为。 编辑器将按以下方式加载和初始化插件。
- 导入必要CSS文件。
某些插件可能具有与之关联CSS文件。 CSS文件定义了插件的UI布局,因此您需要先将CSS文件导入文档中。
- 在
extraPlugins
列表中声明该插件。应该在
extraPlugins
列表中声明该插件,以便编辑器可以根据该声明创建插件实例,如清单3所示。清单3.声明插件
<div dojoType="dijit.Editor" id="editor1" extraPlugins="['FindReplace']"> <p> This is the content of the editor. </p> </div>
清单3中的示例声明了一个名为
FindReplace
的插件。 - 将声明的插件混入完整的插件列表。
编辑器会将声明的插件与默认插件混合到完整的插件列表中。 在此阶段,编辑器将保存一个插件名称列表。 实际的插件将在以下步骤中创建。
- 创建编辑器的工具栏。
编辑器仅创建
dijit.Toolbar
的实例,并将其附加到其DOM节点的子节点,如清单4所示。清单4.创建编辑器的工具栏
if(!this.toolbar){ // if you haven't been assigned a toolbar, create one this.toolbar = new dijit.Toolbar({ dir: this.dir, lang: this.lang }); this.header.appendChild(this.toolbar.domNode); }
- 根据列表创建插件实例。
所有的魔术都在这里发生。 编辑器枚举插件名称列表,并一一调用这些名称上的
addPlugin
。 在addPlugin
方法中,将创建插件,并setToolbar
它们的setEditor
和setToolbar
方法以初始化其上下文。清单5.创建插件实例
postCreate: function(){ ... // Create the plug-in one by one dojo.forEach(this.plugins, this.addPlugin, this); ... } addPlugin: function(/*String||Object*/plugin, /*Integer?*/index){ ... // Get the plug-in instance that is referenced by paremeter o.plugin. var o={"args":args,"plugin":null,"editor":this}; dojo.publish(dijit._scopeName + ".Editor.getPlugin",[o]); // Set the plug-in's context plugin.setEditor(this); if(dojo.isFunction(plugin.setToolbar)){ plugin.setToolbar(this.toolbar); } ... }
创建并初始化所有声明的插件。
创建自己的插件
如果Dojo工具包提供的插件不能满足您的需求,则可以构建自己的插件。 Dojo富文本编辑器使您可以扩展编辑器的功能。 您可以创建一个新的插件类,该类继承自dijit._editor._Plugin
并将其添加到编辑器的插件列表中。
编辑器插件的生命周期
dijit._editor._Plugin
是编辑器插件的基类,通常是工具栏上的单个按钮以及一些关联的代码。 它定义了插件的生命周期。
当插件的生命周期通过addPlugin
函数添加到编辑器中时开始,从而发布Dojo主题,以便插件可以自行构造。 然后分别调用插件的setEditor
和setToolbar
函数,以将插件安装到编辑器中。 默认情况下, setEditor
函数:
- 创建对编辑器的本地引用。
- 创建命令按钮。
- 将编辑器的
execCommand
方法连接到按钮。 - 将插件的
updateState
方法连接到编辑器。
这很简单。 setToolbar
的默认行为甚至更简单:它将先前创建的命令按钮添加到工具栏。
至此,初始化完成,插件生命周期进入“无尽”事件驱动阶段,直到有人销毁整个编辑器并结束生命周期为止,该生命周期将调用插件的destroy
方法。
总而言之,生命周期功能为:
-
Editor.addPlugin
- 插件的构造函数
-
plugin.setEditor
-
plugin.setToolbar
- 事件驱动阶段。 不断调用
plugin.updateState
。 -
Editor.destroy
-
plugin.destroy
-
为了更好地了解细节,您将在以下各节中编写一个名为FindReplace的查找/替换插件。 FindReplace在编辑器中的文本中搜索给定的关键字,如果找到则将其突出显示。 它还支持用新内容替换关键字。 要实现该插件,您将设计一个特殊的工具栏,该工具栏在单击命令按钮时显示。
继承dijit._editor._Plugin
第一步是通过继承基类dijit._editor._Plugin
来建立一个空代码框架,如清单6所示。
清单6.新插件的基本代码框架
dojo.provide("dojox.editor.plugins.FindReplace");
dojo.require("dijit._editor._Plugin");
dojo.declare("dojox.editor.plugins.FindReplace", dijit._editor._Plugin, {
// When you click the command button, you show a toolbar,
// instead of executing some editor commands.
useDefaultCommand: false,
// You can just use the original method.
// setEditor: function(editor){},
setToolbar: function(editorToolbar){
this.inherited(arguments);
//TODO: Create your additional find/replace toolbar here,
// and append it after the editor toolbar.
},
updateState: function(){
// You don't need to handle anything when editor state is updated.
// So just leave this empty.
},
destroy: function(){
this.inherited(arguments);
//TODO: Remember to destroy the toolbar you created.
}
});
// Register this plug-in so it can construct itself when the editor publishes a topic.
dojo.subscribe(dijit._scopeName + ".Editor.getPlugin", null, function(o){
if(!o.plugin && o.args.name.toLowerCase() === "findreplace"){
o.plugin = new dojox.editor.plugins.FindReplace({});
}
});
扩展工具栏
第二项任务是在编辑器工具栏上创建一个按钮。 setEditor
方法将自动为您执行此操作; 您需要做的就是使用不同的标签和图标。 清单7显示了最简单的方法。
清单7.在编辑器工具栏中创建一个ToggleButton
...
dojo.declare("dojox.editor.plugins.FindReplace", dijit._editor._Plugin, {
...
// You'd like to use a toggle button to show/hide your own find/replace toolbar.
buttonClass: dijit.form.ToggleButton,
// As long as you provide a command, the CSS class of the button icon will be
// generated automatically. For this one, it will be "dijitEditorFindReplace".
command: "findReplace",
// You can also use localization here.
getLabel: function(){
return "Find and Replace";
},
...
});
...
当您有CSS类dijitEditorFindReplace
的背景图像时,您可以看到示例按钮,如图3所示。
图3.插件示例的新按钮
下一步是创建查找/替换工具栏,并将其绑定到命令按钮。 您需要一个用于搜索字符串的字段,另一个用于替换字符串的字段,一个查找按钮和一个替换按钮。 如果要使其功能更强大,可以添加许多其他内容使其看起来更专业,例如“全部替换”按钮或“区分大小写搜索”和“向后搜索”复选框。 您可以编写一个简单的单独的小部件来容纳所有这些东西,如清单8所示。
清单8.创建一个查找/替换工具栏
dojo.declare("dojox.editor.plugins.FindReplacePane", [dijit._Widget, dijit._Templated], {
// With templates, you don't need to create all the stuff manually.
templateString: dojo.cache("dojox.editor.plugins", "FindReplacePane.html"),
// There are widgets in template. Tell the parser to parse them.
widgetsInTemplate: true
});
在FindReplacePane.html中,您可以直接使用dijit.Toolbar和其他表单小部件。 清单9中的示例将标签和文本字段(或复选框)组合在一起以形成一个新的小部件,以使代码更简单。
清单9.查找/替换工具栏的内容
<div><div dojotype="dijit.Toolbar" dojoattachpoint="frToolbar">
<div dojoattachpoint="findField" dojotype="dojox.editor.plugins._FindReplaceTextBox"
label="Find:"></div>
<div dojoattachpoint="replaceField" dojotype="dojox.editor.plugins._FindReplaceTextBox"
label="Replace with:"></div>
<div dojotype="dojox.editor.plugins._ToolbarLineBreak"></div>
<div dojoattachpoint="findButton" dojotype="dijit.form.Button"
label="Find" showLable="true"></div>
<div dojoattachpoint="replaceButton" dojotype="dijit.form.Button"
label="Replace" showLable="true"></div>
<div dojoattachpoint="replaceAllButton" dojotype="dijit.form.Button"
label="Replace All" showLable="true"></div>
<div dojoattachpoint="matchCase" dojotype="dojox.editor.plugins._FindReplaceCheckBox"
label="Match case"></div>
<div dojoattachpoint="backwards" dojotype="dojox.editor.plugins._FindReplaceCheckBox"
label="Backwards"></div>
</div></div>
使用dojoattachpoint
您可以轻松地将小部件作为FindReplacePane
的属性来FindReplacePane
。 dojox.editor.plugins._ToolbarLineBreak
是用于多行工具栏的非常有用的小部件。
现在您已经有了按钮和工具栏,是时候将它们连接在一起了。 您所要做的就是将工具栏放置在适当的位置,并定义单击切换按钮时的操作。 清单10显示了一个示例。
清单10.连接按钮和工具栏
// This initialization work should be done in setToolbar,
// because you want to be sure that the editor toolbar is ready.
setToolbar: function(editorToolbar){
// Super class will add the command button to the editor toolbar for you.
this.inherited(arguments);
// Create your find/replace toolbar, place it after the editor toolbar,
// hide it, and start it up.
var frtb = this.frToolbar = new dojox.editor.plugins.FindReplacePane();
frtb.placeAt(toolbar.domNode, "after");
dojo.style(frtb.domNode, "display", "none");
frtb.startup();
// Toggle it when your toggle button is clicked...
this.connect(this.button, "onChange", "_toggleFindReplace");
...
},
_toggleFindReplace: function(toShow){
// Remember the original height.
var height = dojo.marginBox(this.editor.domNode).h
dojo.style(this.frToolbar.domNode, "display", toShow ? "block" : "none");
// Resize the editor to maintain the height.
this.editor.resize({h: height});
}
图4显示了您的示例现在的样子。
图4.查找/替换工具栏
处理事件并实现功能
现在,使“查找”和“替换”按钮正常工作。 您可以在setToolbar
方法中进行设置,如清单11所示。
清单11.处理事件
setToolbar: function(editorToolbar){
...
var tb = this._frToolbar = ...
// Connect methods to the onClick events of the buttons.
this.connect(tb.findButton, "onClick", "_find");
this.connect(tb.replaceButton, "onClick", "_replace");
this.connect(tb.replaceAllButton, "onClick", "_replaceAll");
// Make the ENTER key work for the "Find" text field.
this.connect(tb.findField, "onKeyDown", function(evt){
if(evt.keyCode == dojo.keys.ENTER){
this._find();
dojo.stopEvent(evt);
}
});
...
}
那很简单。 下一步是实现_find
函数。 对于非IE浏览器,您可以简单地使用window.find。 对于IE而言,情况变得有些复杂。 您需要编写一个适配器函数来消除浏览器的差异,如清单12所示。
清单12. Find的实现
// An adapter function to make all browsers look the same.
_findText: function(txt, isCaseSensitive, isBackwards){
if(!txt){ return false; }
var ed = this.editor, win = ed.window, doc = ed.document;
var found = false;
if(win.find){
found = win.find(txt, isCaseSensitive, isBackwards,
false, false, false, false);
}else if(doc.selection){
/* IE */
// Focus to restore position/selection,
// then shift to search from current position.
ed.focus();
var txtRg = doc.body.createTextRange();
var curPos = doc.selection ? doc.selection.createRange() : null;
if(curPos){
txtRg.setEndPoint(isBackwards ? "EndToStart" : "StartToEnd",
curPos);
}
var flags = isCaseSensitive ? 4 : 0;
if(backwards){
flags = flags | 1;
}
found = txtRg.findText(txt, txtRg.text.length, flags);
if(found){
txtRg.select();
}
}
return found;
},
_find: function(){
var tb = this._frToolbar;
return this._findText(tb.findField.get("value"),
tb.matchCase.get("value"), tb.backwards.get("value"));
}
再次运行页面以查看效果,如图5所示。
图5.查找文本
现在,您可以在大多数现代浏览器上使用有用的“查找”功能。
以编程方式编辑内容
Dojo Rich Text Editor提供了一个统一的API execCommand
,您可以使用它来调用内置命令。 有许多命令可用,例如撤消,重做,剪切,复制,粘贴,粗体和斜体。 对于内置命令,请参阅dijit.Editor文档的完整列表(见相关主题 )。
对于示例插件,您需要在编辑器中插入一些文本以替换选定的文本。 当然,对此有一个内置命令— inserthtml
。 您所要做的就是:
- 检查所选文本是否与
find
字段中的文本匹配。 - 如果是,请调用
editor.execCommand("inserthtml", replaceText);
清单13显示了代码。
清单13.替换实现
_replace: function(){
var tb = this._frToolbar;
var txt = tb.findField.get("value");
if(!txt){ return false; }
var repTxt = tb.replaceField.get("value") || "";
var isCaseSensitive = tb.caseSensitive.get("value");
var isBackwards = tb.backwards.get("value");
var ed = this.editor;
ed.focus();
//Replace the current selected text if it matches the find field.
var selected = dojo.withGlobal(ed.window, "getSelectedText",
dijit._editor.selection, [null]);
if(selected && (isCaseSensitive ?
(selected === txt) : (selected.toLowerCase() === txt.toLowerCase()))){
ed.execCommand("inserthtml", repTxt);
return true;
}
return false;
}
您应该在编辑器中使用iframe窗口而不是整个页面的窗口来调用getSelectedText
。 图6显示了结果。
图6.替换文字
您现在知道编写编辑器插件的基本细节。 也许您可以继续自己执行全部替换功能。
结论
在本文中,您了解了Dojo Rich Text Editor的可插拔体系结构。 插件机制使您可以扩展编辑器的功能。 使用Dojo Rich Text Editor,您可以在应用程序中部署功能强大的文本编辑器。 您可以轻松使用和自定义编辑器以满足您的特定要求。
翻译自: https://www.ibm.com/developerworks/web/library/wa-master/index.html
dojo/text!.