富文本编辑器CKEditor4简单使用-08(段落首行缩进插件 + 处理粘贴 Microsoft Word 中的内容后保持原始内容格式(包括首行缩进))
- 1. 缩进,特殊方式处理——修改原工具栏里的增加缩进量
- 2 缩进,插件处理
- 2.1 下载段落插件 textindent
- 2.2 使用段落插件 textindent
- 2.3 修改textindent插件中的plugins.js文件
- 2.3.1 修改插件按钮提示信息
- 2.3.2 修改插件里的缩进偏移量和缩进单位
- 2.4 开启textindent插件 并 看效果
- 2.4.1 开启插件
- 2.4.2 段落首行缩进测试
- 2.4.3 来源word粘贴(保留缩进格式测试)
- 2.5 附核心代码
- 2.6 关于安装插件的其他详细内容
- 3. 缩进,插件处理——优化(简直完美)
- 3.1 如果不优化存在的问题
- 3.2 修改插件的plugin.js——设置缩进2个字体空间
- 3.2.1 直接换单位(rem)
- 3.2.2 更改源码,计算缩进空间
- 3.2.2.1 更改位置
- 3.2.2.2 看效果
- 3.2.2.3 核心代码
- 3.2.2.4 更改后完整 plugin.js 代码
- 3.2.2.5 优化后完整 plugin.js 代码
- 4. 下载项目
- 5. word里有图片的问题(待解决)
- 4.1 问题描述
- 5.1 查看自己的CKEditor4版本号
- 5.2 关于Paste from Word插件
- 5.2.1 下载Paste from Word插件
- 5.3 解压所有插件
1. 缩进,特殊方式处理——修改原工具栏里的增加缩进量
-
请看上篇文章,如下:
富文本编辑器CKEditor4简单使用-07(处理浏览器不支持通过工具栏粘贴问题 和 首行缩进的问题).
2 缩进,插件处理
2.1 下载段落插件 textindent
-
下载段落缩进插件,如下:
https://ckeditor.com/cke4/addon/textindent.
-
备注:该插件没有依赖插件,所以只需要下载该一个插件即可使用!
2.2 使用段落插件 textindent
- 下载之后解压,然后放在plugins目录下,如下:
2.3 修改textindent插件中的plugins.js文件
2.3.1 修改插件按钮提示信息
- 这个看自己,因为提示信息是一串英文的,所以这里改成明了的汉字,如下:
2.3.2 修改插件里的缩进偏移量和缩进单位
- 如下:
2.4 开启textindent插件 并 看效果
2.4.1 开启插件
- 开启插件配置如下:
2.4.2 段落首行缩进测试
-
看效果
-
如果不修改缩进偏移量和缩进单位的话,原本效果如下:
-
修改缩进偏移量和缩进单位后的效果,如下:
2.4.3 来源word粘贴(保留缩进格式测试)
- 使用这个插件之后,从word里复制出的内容再粘贴格式保持不变(包括首行缩进格式),如下:
- 通过工具栏的按钮粘贴也是一样的可以实现缩进效果,但是不一样的是这种缩进不是缩进的两个字符(2em),而是缩进的两个字体的空间大小(可以理解是保持原文格式不变了)。
- 注意前提:一定要开启
textindent
插件,否则首行缩进格式丢失!
2.5 附核心代码
- text.html,如下:
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="robots" content="noindex, nofollow"> <title>Setting text part language</title> <script src="../ckeditor/ckeditor.js"></script> </head> <body> <textarea cols="80" id="editor2" name="editor2" rows="10"></textarea> <script> var editor = CKEDITOR.replace('editor2', { }); editor.on("beforeCommandExec", function (event) { // 显示粘贴按钮的粘贴对话框并右键单击粘贴 if (event.data.name == "paste") { event.editor._.forcePasteDialog = true; } // 不要显示Ctrl+Shift+V的粘贴对话框 if (event.data.name == "pastetext" && event.data.commandData.from == "keystrokeHandler") { event.cancel(); } }); </script> </body> </html>
- config.js,如下:
CKEDITOR.editorConfig = function( config ) { // 启用皮肤 config.skin = 'office2013'; // textindent-首行缩进插件 config.extraPlugins = 'textindent'; };
2.6 关于安装插件的其他详细内容
- 可参考下面的文章:
富文本编辑器CKEditor4简单使用-02(常用插件安装及使用).
3. 缩进,插件处理——优化(简直完美)
3.1 如果不优化存在的问题
- 上面我们把缩进量和单位配置成
2em
,看着测试没什么问题,但是我们通过复制粘贴发现,复制粘贴后缩进保留的还是原文的px
,所以我们上面测试看着没问题,那是因为字体刚刚好,如果我们把字体调大或者调小再次点击缩进按钮,问题就暴露出来了,如下:
- 所以,它是一个动态的,我们要做的是如何实现缩进两个字体(根据原文字体的大小缩进),所以我们要设置成动态的缩进2个字体的空间,也就是说:
当设置为2个字体的空间时,即首行缩进的距离为2个字体大小的距离。例如,如果你的文字大小为16px,那么缩进的距离就是32px。
3.2 修改插件的plugin.js——设置缩进2个字体空间
3.2.1 直接换单位(rem)
-
但是这个有个问题,如果正文字体大小都一样可以,如果第二段字体大小和第一段字体大小不一样的话,效果不是很理想(这时第一段可以实现效果,但是第二段不行)如下:
-
关于
em
和rem
在 CSS 中,em 和 rem 都是相对长度单位,其中 em 是相对于父元素的字体大小,而 rem 是相对于根元素的字体大小(即 html 元素的字体大小)。具体来说:- em:表示相对于当前元素的字体大小。例如,如果当前元素的字体大小为 16px,那么 1em 就等于 16px。
- rem:表示相对于根元素(即 html 元素)的字体大小。例如,如果根元素的字体大小为 16px,那么 1rem 就等于 16px。
由于 rem 单位是相对于根元素的字体大小,因此在整个页面中都是一致的。这使得使用 rem 单位更加方便和灵活,可以避免在多层嵌套中计算父元素字体大小的复杂性。
-
如果字体不一致的话,上面
rem
可能还是不能满足,这就需要计算了,如何实现,请继续……
3.2.2 更改源码,计算缩进空间
3.2.2.1 更改位置
- 如下:
3.2.2.2 看效果
-
如下:
3.2.2.3 核心代码
-
添加的核心代码如下:
// 第一个是span,获取span标签 var child_span = node.$.firstElementChild; // console.log(child_span); if(child_span!=null){ // 获取span里的 font-size属性的值 var spanFontSize = child_span.style.fontSize; indentation = 2 * parseFloat(spanFontSize) + "px"; // 更改缩进量和缩进单位 // console.log(spanFontSize); // console.log(indentation); }
3.2.2.4 更改后完整 plugin.js 代码
- 如下:
CKEDITOR.plugins.add( 'textindent', { icons: 'textindent', availableLangs: {'pt-br':1, 'en':1}, lang: 'pt-br, en', init: function( editor ) { var indentation = editor.config.indentation; var indentationKey = editor.config.indentationKey; if(typeof(indentation) == 'undefined') indentation = '2em'; if(typeof(indentationKey) == 'undefined') indentationKey = 'tab'; if(editor.ui.addButton){ editor.ui.addButton( 'textindent', { // label: editor.lang.textindent.labelName, label: '首行缩进', command: 'ident-paragraph', }); } if( indentationKey !== false){ editor.on('key', function(ev) { if(ev.data.domEvent.$.key.toLowerCase() === indentationKey.toLowerCase().trim() || ev.data.keyCode === indentationKey){ editor.execCommand('ident-paragraph'); ev.cancel(); } }); } editor.on( 'selectionChange', function() { var style_textindente = new CKEDITOR.style({ element: 'p', styles: { 'text-indent': indentation }, overrides: [{ element: 'text-indent', attributes: { 'size': '0'} }] }); if( style_textindente.checkActive(editor.elementPath(), editor) ) editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_ON); else editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_OFF); }); editor.addCommand("ident-paragraph", { allowedContent: 'p{text-indent}', requiredContent: 'p', exec: function(evt) { var range = editor.getSelection().getRanges()[0]; var walker = new CKEDITOR.dom.walker( range ), node; var state = editor.getCommand('ident-paragraph').state; while ( ( node = walker.next() ) ) { if ( node.type == CKEDITOR.NODE_ELEMENT ) { if(node.getName() === "p"){ // console.log(node); editor.fire('saveSnapshot'); if( state == CKEDITOR.TRISTATE_ON){ node.removeStyle("text-indent"); editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_OFF); } else{ // 第一个是span,获取span标签 var child_span = node.$.firstElementChild; console.log(child_span); if(child_span!=null){ // 获取span里的 font-size属性的值 var spanFontSize = child_span.style.fontSize; indentation = 2 * parseFloat(spanFontSize) + "px"; // 更改缩进量和缩进单位 } node.setStyle( "text-indent", indentation ); editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_ON); } } } } if(node === null){ node = editor.getSelection().getStartElement().getAscendant('p', true); console.log(node); // var outerHtml = node.getOuterHtml(); // console.log(outerHtml); // 获取 childNodes // var childNodes = node.$.childNodes; // console.log(childNodes); // 第一个是span,获取span标签 var child_span = node.$.firstElementChild; // console.log(child_span); if(child_span!=null){ // 获取span里的 font-size属性的值 var spanFontSize = child_span.style.fontSize; indentation = 2 * parseFloat(spanFontSize) + "px"; // 更改缩进量和缩进单位 // console.log(spanFontSize); // console.log(indentation); } editor.fire('saveSnapshot'); if( state == CKEDITOR.TRISTATE_ON){ node.removeStyle("text-indent"); editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_OFF); } else{ node.setStyle( "text-indent", indentation ); editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_ON); } } } }); } });
3.2.2.5 优化后完整 plugin.js 代码
- 上述代码修改2处,并且原本也有重复代码,优化后如下:
CKEDITOR.plugins.add( 'textindent', { icons: 'textindent', availableLangs: {'pt-br':1, 'en':1}, lang: 'pt-br, en', init: function( editor ) { var indentation = editor.config.indentation; var indentationKey = editor.config.indentationKey; if(typeof(indentation) == 'undefined') indentation = '2em'; if(typeof(indentationKey) == 'undefined') indentationKey = 'tab'; if(editor.ui.addButton){ editor.ui.addButton( 'textindent', { // label: editor.lang.textindent.labelName, label: '首行缩进', command: 'ident-paragraph', }); } if( indentationKey !== false){ editor.on('key', function(ev) { if(ev.data.domEvent.$.key.toLowerCase() === indentationKey.toLowerCase().trim() || ev.data.keyCode === indentationKey){ editor.execCommand('ident-paragraph'); ev.cancel(); } }); } editor.on( 'selectionChange', function() { var style_textindente = new CKEDITOR.style({ element: 'p', styles: { 'text-indent': indentation }, overrides: [{ element: 'text-indent', attributes: { 'size': '0'} }] }); if( style_textindente.checkActive(editor.elementPath(), editor) ) editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_ON); else editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_OFF); }); editor.addCommand("ident-paragraph", { allowedContent: 'p{text-indent}', requiredContent: 'p', exec: function(evt) { var range = editor.getSelection().getRanges()[0]; var walker = new CKEDITOR.dom.walker( range ), node; var state = editor.getCommand('ident-paragraph').state; while ( ( node = walker.next() ) ) { if ( node.type == CKEDITOR.NODE_ELEMENT ) { if(node.getName() === "p"){ calculateAndDoFirstLineIndent(); } } } if(node === null){ node = editor.getSelection().getStartElement().getAscendant('p', true); calculateAndDoFirstLineIndent(); } /** * 计算并处理首行缩进 */ function calculateAndDoFirstLineIndent(){ editor.fire('saveSnapshot'); if( state == CKEDITOR.TRISTATE_ON){ node.removeStyle("text-indent"); editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_OFF); } else{ // 第一个是span,获取span标签 var child_span = node.$.firstElementChild; if(child_span!=null){ // 获取span里的 font-size属性的值 var spanFontSize = child_span.style.fontSize; // 更改缩进量和缩进单位(缩进2个字体的空间) indentation = 2 * parseFloat(spanFontSize) + "px"; } node.setStyle( "text-indent", indentation ); editor.getCommand('ident-paragraph').setState(CKEDITOR.TRISTATE_ON); } } } }); } });
4. 下载项目
-
如果不想下载官网项目,下载后还需要单独下载插件,可直接从下面链接下载,包括常用的插件,项目拿来即用,如下:
ckeditor4(4.22.1-含上传图片、快速表格、首行缩进等插件).
5. word里有图片的问题(待解决)
4.1 问题描述
- 如果粘贴的word里有图片,复制之后图片不展示,如下:
5.1 查看自己的CKEditor4版本号
- 后续下载插件有的会根据CKEditor4的版本下载对应插件的版本号,所以先确定一下自己的版本号,在浏览器的控制台中输入命令即可查询,查询版本号的方式如下:
CKEDITOR 或 CKEDITOR.version
5.2 关于Paste from Word插件
5.2.1 下载Paste from Word插件
- 下载地址:
https://ckeditor.com/cke4/addon/pastefromword. - 下载所需的所有依赖插件,如下:
- 关于
Paste from Word
插件,如下:
5.3 解压所有插件
- 解压所有插件并放到plugins目录下(已有的插件不用替换),如下
- 问题是:此插件无论怎么配置都不生效,把默认插件换成下载的插件之后重新配置还是不生效,不知道此插件啥情况!!!
- 参考官网配置如下:
https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_config.html#cfg-pasteFromWordRemoveFontStyles. - 感兴趣的、用过的朋友可以交流一下!