您现在的位置是:首页 > cms教程 > 帝国CMS教程帝国CMS教程
帝国cms编辑器ckeditor代码高亮前端显示mac风格
原创2025-09-18帝国CMS教程已有人查阅
导读前年写过一篇关于编辑器代码高亮的文章,很多人一知半解都在问,今天就详细的补充一下细节,到结束的完整过程,我尽量写的全面通俗易懂。已经写过的内容自行查看,只做补充。
前年写过一篇关于编辑器代码高亮的文章,很多人一知半解都在问,今天就详细的补充一下细节,到结束的完整过程,我尽量写的全面通俗易懂。已经写过的内容自行查看,只做补充。先看前面的内容不明白再回来看这篇教程。我们分三步走弄完整。
1,首先前提是你已经在编辑器添加了Code Snippet插件,如果没有?那么请查看这篇文章>>帝国cms编辑器ckeditor安装代码高亮插件
2,已经在编辑器添加了Code Snippet插件那么现在来进行>>帝国cms自带ckeditor编辑器代码高亮的方法codesnippet风格
3,添加行号,和头部圆圈等查看>>帝国cms高亮代码添加行号前端显示Mac OS风格
上次这篇教程很多人卡在了第二步、动手改造找到e/admin/ecmseditor/infoeditor/plugins/codesnippet目录下plugin.js修改很多人函数改错,
还有很多人卡在最后一步明明添加了
template: '<pre class="pure-highlightjs line-numbers ' + codeClass + '"><code class="' + codeClass + '"></code></pre>'
但是页面上只出现<pre class=" language-html">添加的pure-highlightjs line-numbers就是不出来,所以没有风格样式很难看。
问题在于模板中定义的pure-highlightjs和line-numbers类在upcast和downcast过程中没有被正确处理:
问题总结
upcast阶段:当从HTML内容转换为widget数据时,没有保留这些类
downcast阶段:当从widget数据转换为HTML输出时,这些类被完全移除
data更新阶段:当widget数据更新时,没有确保这些类被保留
针对上述问题我直接贴出我优化后的版本方便大家直接用或者参考,同时也做了一些安全措施。
更详细一点路径是:e\你的后台地址\ecmseditor\infoeditor\plugins\codesnippet\plugin.js,到这里这些问题都解决了,更新缓存可能无效,发布一篇文章,或者是之前的内容点修改然后发布然后查看就正常了,效果如代码号下面的。
/**
* @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or http://ckeditor.com/license
*/
/**
* @fileOverview Rich code snippets for CKEditor.
*/
'use strict';
( function() {
var isBrowserSupported = !CKEDITOR.env.ie || CKEDITOR.env.version > 8;
CKEDITOR.plugins.add( 'codesnippet', {
requires: 'widget,dialog',
lang: 'ar,bg,ca,cs,da,de,de-ch,el,en,en-gb,eo,es,et,eu,fa,fi,fr,fr-ca,gl,he,hr,hu,id,it,ja,km,ko,ku,lt,lv,nb,nl,no,pl,pt,pt-br,ro,ru,sk,sl,sq,sv,th,tr,tt,ug,uk,vi,zh,zh-cn', // %REMOVE_LINE_CORE%
icons: 'codesnippet', // %REMOVE_LINE_CORE%
hidpi: true, // %REMOVE_LINE_CORE%
beforeInit: function( editor ) {
editor._.codesnippet = {};
/**
* Sets the custom syntax highlighter. See {@link CKEDITOR.plugins.codesnippet.highlighter}
* to learn how to register a custom highlighter.
*
* **Note**:
*
* * This method can only be called while initialising plugins (in one of
* the three callbacks).
* * This method is accessible through the `editor.plugins.codesnippet` namespace only.
*
* @since 4.4
* @member CKEDITOR.plugins.codesnippet
* @param {CKEDITOR.plugins.codesnippet.highlighter} highlighter
*/
this.setHighlighter = function( highlighter ) {
editor._.codesnippet.highlighter = highlighter;
var langs = editor._.codesnippet.langs =
editor.config.codeSnippet_languages || highlighter.languages;
// We might escape special regex chars below, but we expect that there
// should be no crazy values used as lang keys.
editor._.codesnippet.langsRegex = new RegExp( '(?:^|\\s)language-(' +
CKEDITOR.tools.objectKeys( langs ).join( '|' ) + ')(?:\\s|$)' );
};
},
onLoad: function() {
CKEDITOR.dialog.add( 'codeSnippet', this.path + 'dialogs/codesnippet.js' );
},
init: function( editor ) {
editor.ui.addButton && editor.ui.addButton( 'CodeSnippet', {
label: editor.lang.codesnippet.button,
command: 'codeSnippet',
toolbar: 'insert,10'
} );
},
afterInit: function( editor ) {
var path = this.path;
registerWidget( editor );
// At the very end, if no custom highlighter was set so far (by plugin#setHighlighter)
// we will set default one.
if ( !editor._.codesnippet.highlighter ) {
var hljsHighlighter = new CKEDITOR.plugins.codesnippet.highlighter( {
languages: {
apache: 'Apache',
bash: 'Bash',
coffeescript: 'CoffeeScript',
cpp: 'C++',
cs: 'C#',
css: 'CSS',
diff: 'Diff',
html: 'HTML',
http: 'HTTP',
ini: 'INI',
java: 'Java',
javascript: 'JavaScript',
json: 'JSON',
makefile: 'Makefile',
markdown: 'Markdown',
nginx: 'Nginx',
objectivec: 'Objective-C',
perl: 'Perl',
php: 'PHP',
python: 'Python',
ruby: 'Ruby',
sql: 'SQL',
vbscript: 'VBScript',
xhtml: 'XHTML',
xml: 'XML'
},
init: function( callback ) {
var that = this;
if ( isBrowserSupported ) {
CKEDITOR.scriptLoader.load( path + 'lib/highlight/highlight.pack.js', function() {
that.hljs = window.hljs;
callback();
} );
}
// Method is available only if wysiwygarea exists.
if ( editor.addContentsCss ) {
editor.addContentsCss( path + 'lib/highlight/styles/' + editor.config.codeSnippet_theme + '.css' );
}
},
highlighter: function( code, language, callback ) {
var highlighted = this.hljs.highlightAuto( code,
this.hljs.getLanguage( language ) ? [ language ] : undefined );
if ( highlighted )
callback( highlighted.value );
}
} );
this.setHighlighter( hljsHighlighter );
}
}
} );
/**
* Global helpers and classes of the Code Snippet plugin.
*
* For more information see the [Code Snippet Guide](#!/guide/dev_codesnippet).
*
* @class
* @singleton
*/
CKEDITOR.plugins.codesnippet = {
highlighter: Highlighter
};
/**
* A Code Snippet highlighter. It can be set as a default highlighter
* using {@link CKEDITOR.plugins.codesnippet#setHighlighter}, for example:
*
* // Create a new plugin which registers a custom code highlighter
* // based on customEngine in order to replace the one that comes
* // with the Code Snippet plugin.
* CKEDITOR.plugins.add( 'myCustomHighlighter', {
* afterInit: function( editor ) {
* // Create a new instance of the highlighter.
* var myHighlighter = new CKEDITOR.plugins.codesnippet.highlighter( {
* init: function( ready ) {
* // Asynchronous code to load resources and libraries for customEngine.
* customEngine.loadResources( function() {
* // Let the editor know that everything is ready.
* ready();
* } );
* },
* highlighter: function( code, language, callback ) {
* // Let the customEngine highlight the code.
* customEngine.highlight( code, language, function() {
* callback( highlightedCode );
* } );
* }
* } );
*
* // Check how it performs.
* myHighlighter.highlight( 'foo()', 'javascript', function( highlightedCode ) {
* console.log( highlightedCode ); // -> <span class="pretty">foo()</span>
* } );
*
* // From now on, myHighlighter will be used as a Code Snippet
* // highlighter, overwriting the default engine.
* editor.plugins.codesnippet.setHighlighter( myHighlighter );
* }
* } );
*
* @since 4.4
* @class CKEDITOR.plugins.codesnippet.highlighter
* @extends CKEDITOR.plugins.codesnippet
* @param {Object} def Highlighter definition. See {@link #highlighter}, {@link #init} and {@link #languages}.
*/
function Highlighter( def ) {
CKEDITOR.tools.extend( this, def );
/**
* A queue of {@link #highlight} jobs to be
* done once the highlighter is {@link #ready}.
*
* @readonly
* @property {Array} [=[]]
*/
this.queue = [];
// Async init – execute jobs when ready.
if ( this.init ) {
this.init( CKEDITOR.tools.bind( function() {
// Execute pending jobs.
var job;
while ( ( job = this.queue.pop() ) )
job.call( this );
this.ready = true;
}, this ) );
} else {
this.ready = true;
}
/**
* If specified, this function should asynchronously load highlighter-specific
* resources and execute `ready` when the highlighter is ready.
*
* @property {Function} [init]
* @param {Function} ready The function to be called once
* the highlighter is {@link #ready}.
*/
/**
* A function which highlights given plain text `code` in a given `language` and, once done,
* calls the `callback` function with highlighted markup as an argument.
*
* @property {Function} [highlighter]
* @param {String} code Code to be formatted.
* @param {String} lang Language to be used ({@link CKEDITOR.config#codeSnippet_languages}).
* @param {Function} callback Function which accepts highlighted String as an argument.
*/
/**
* Defines languages supported by the highlighter.
* They can be restricted with the {@link CKEDITOR.config#codeSnippet_languages} configuration option.
*
* **Note**: If {@link CKEDITOR.config#codeSnippet_languages} is set, **it will
* overwrite** the languages listed in `languages`.
*
* languages: {
* coffeescript: 'CoffeeScript',
* cpp: 'C++',
* cs: 'C#',
* css: 'CSS'
* }
*
* More information on how to change the list of languages is available
* in the [Code Snippet documentation](#!/guide/dev_codesnippet-section-changing-languages-list).
*
* @property {Object} languages
*/
/**
* A flag which indicates whether the highlighter is ready to do jobs
* from the {@link #queue}.
*
* @readonly
* @property {Boolean} ready
*/
}
/**
* Executes the {@link #highlighter}. If the highlighter is not ready, it defers the job ({@link #queue})
* and executes it when the highlighter is {@link #ready}.
*
* @param {String} code Code to be formatted.
* @param {String} lang Language to be used ({@link CKEDITOR.config#codeSnippet_languages}).
* @param {Function} callback Function which accepts highlighted String as an argument.
*/
Highlighter.prototype.highlight = function() {
var arg = arguments;
// Highlighter is ready – do it now.
if ( this.ready )
this.highlighter.apply( this, arg );
// Queue the job. It will be done once ready.
else {
this.queue.push( function() {
this.highlighter.apply( this, arg );
} );
}
};
// Encapsulates snippet widget registration code.
// @param {CKEDITOR.editor} editor
function registerWidget( editor ) {
var codeClass = editor.config.codeSnippet_codeClass,
newLineRegex = /\r?\n/g,
textarea = new CKEDITOR.dom.element( 'textarea' ),
lang = editor.lang.codesnippet;
// 定义允许的额外类名(白名单方式)
var allowedPreClasses = ['pure-highlightjs', 'line-numbers'];
// 安全地添加ACF规则 - 只允许特定的类
editor.widgets.add( 'codeSnippet', {
// 明确指定允许的类,避免使用通配符
allowedContent: {
'pre': {
classes: allowedPreClasses
},
'code': {
classes: 'language-*',
attributes: '!class' // 只允许class属性
}
},
requiredContent: 'pre',
styleableElements: 'pre',
// 模板中使用安全的类名
template: '<pre class="pure-highlightjs line-numbers ' + codeClass + '"><code class="' + codeClass + '"></code></pre>',
dialog: 'codeSnippet',
pathName: lang.pathName,
mask: true,
parts: {
pre: 'pre',
code: 'code'
},
highlight: function() {
var that = this,
widgetData = this.data,
callback = function( formatted ) {
that.parts.code.setHtml( isBrowserSupported ?
formatted : formatted.replace( newLineRegex, '<br>' ) );
};
callback( CKEDITOR.tools.htmlEncode( widgetData.code ) );
editor._.codesnippet.highlighter.highlight( widgetData.code, widgetData.lang, function( formatted ) {
editor.fire( 'lockSnapshot' );
callback( formatted );
editor.fire( 'unlockSnapshot' );
} );
},
data: function() {
var newData = this.data,
oldData = this.oldData;
if ( newData.code )
this.parts.code.setHtml( CKEDITOR.tools.htmlEncode( newData.code ) );
if ( oldData && newData.lang != oldData.lang )
this.parts.code.removeClass( 'language-' + oldData.lang );
if ( newData.lang ) {
this.parts.code.addClass( 'language-' + newData.lang );
this.highlight();
}
this.oldData = CKEDITOR.tools.copy( newData );
},
// 安全的upcast方法
upcast: function( el, data ) {
if ( el.name != 'pre' )
return;
var childrenArray = getNonEmptyChildren( el ),
code;
if ( childrenArray.length != 1 || ( code = childrenArray[ 0 ] ).name != 'code' )
return;
if ( code.children.length != 1 || code.children[ 0 ].type != CKEDITOR.NODE_TEXT )
return;
// 安全地读取language-*类
var matchResult = editor._.codesnippet.langsRegex.exec( code.attributes[ 'class' ] );
if ( matchResult )
data.lang = matchResult[ 1 ];
textarea.setHtml( code.getHtml() );
data.code = textarea.getValue();
// 安全地处理pre元素的类
var existingClasses = (el.attributes['class'] || '').split(/\s+/);
var newClasses = [];
// 只保留白名单中的类和codeClass
for (var i = 0; i < existingClasses.length; i++) {
var cls = existingClasses[i];
if (allowedPreClasses.indexOf(cls) !== -1 || cls === codeClass) {
newClasses.push(cls);
}
}
// 添加必需的类(如果不存在)
if (newClasses.indexOf('pure-highlightjs') === -1) {
newClasses.push('pure-highlightjs');
}
if (newClasses.indexOf('line-numbers') === -1) {
newClasses.push('line-numbers');
}
if (newClasses.indexOf(codeClass) === -1) {
newClasses.push(codeClass);
}
el.attributes['class'] = newClasses.join(' ');
code.addClass( codeClass );
return el;
},
// 安全的downcast方法
downcast: function( el ) {
var code = el.getFirst( 'code' );
code.children.length = 0;
code.removeClass( codeClass );
// 清理pre元素的类,只保留允许的类
var existingClasses = (el.attributes['class'] || '').split(/\s+/);
var newClasses = [];
for (var i = 0; i < existingClasses.length; i++) {
var cls = existingClasses[i];
if (allowedPreClasses.indexOf(cls) !== -1) {
newClasses.push(cls);
}
}
el.attributes['class'] = newClasses.join(' ');
code.add( new CKEDITOR.htmlParser.text( CKEDITOR.tools.htmlEncode( this.data.code ) ) );
return el;
}
} );
// Returns an **array** of child elements, with whitespace-only text nodes
// filtered out.
// @param {CKEDITOR.htmlParser.element} parentElement
// @return Array - array of CKEDITOR.htmlParser.node
var whitespaceOnlyRegex = /^[\s\n\r]*$/;
function getNonEmptyChildren( parentElement ) {
var ret = [],
preChildrenList = parentElement.children,
curNode;
// Filter out empty text nodes.
for ( var i = preChildrenList.length - 1; i >= 0; i-- ) {
curNode = preChildrenList[ i ];
if ( curNode.type != CKEDITOR.NODE_TEXT || !curNode.value.match( whitespaceOnlyRegex ) )
ret.push( curNode );
}
return ret;
}
}
} )();
/**
* A CSS class of the `<code>` element used internally for styling
* (by default [highlight.js](http://highlightjs.org) themes, see
* {@link CKEDITOR.config#codeSnippet_theme config.codeSnippet_theme}),
* which means that it is **not present** in the editor output data.
*
* // Changes the class to "myCustomClass".
* config.codeSnippet_codeClass = 'myCustomClass';
*
* **Note**: The class might need to be changed when you are using a custom
* highlighter (the default is [highlight.js](http://highlightjs.org)).
* See {@link CKEDITOR.plugins.codesnippet.highlighter} to read more.
*
* Read more in the [documentation](#!/guide/dev_codesnippet)
* and see the [SDK sample](http://sdk.ckeditor.com/samples/codesnippet.html).
*
* @since 4.4
* @cfg {String} [codeSnippet_codeClass='hljs']
* @member CKEDITOR.config
*/
CKEDITOR.config.codeSnippet_codeClass = 'hljs';
/**
* Restricts languages available in the "Code Snippet" dialog window.
* An empty value is always added to the list.
*
* **Note**: If using a custom highlighter library (the default is [highlight.js](http://highlightjs.org)),
* you may need to refer to external documentation to set `config.codeSnippet_languages` properly.
*
* Read more in the [documentation](#!/guide/dev_codesnippet-section-changing-supported-languages)
* and see the [SDK sample](http://sdk.ckeditor.com/samples/codesnippet.html).
*
* // Restricts languages to JavaScript and PHP.
* config.codeSnippet_languages = {
* javascript: 'JavaScript',
* php: 'PHP'
* };
*
* @since 4.4
* @cfg {Object} [codeSnippet_languages=null]
* @member CKEDITOR.config
*/
/**
* A theme used to render code snippets. See [available themes](http://highlightjs.org/static/test.html).
*
* **Note**: This will only work with the default highlighter
* ([highlight.js](http://highlightjs.org/static/test.html)).
*
* Read more in the [documentation](#!/guide/dev_codesnippet-section-changing-highlighter-theme)
* and see the [SDK sample](http://sdk.ckeditor.com/samples/codesnippet.html).
*
* // Changes the theme to "pojoaque".
* config.codeSnippet_theme = 'pojoaque';
*
* @since 4.4
* @cfg {String} [codeSnippet_theme='default']
* @member CKEDITOR.config
*/
CKEDITOR.config.codeSnippet_theme = 'default';
本文标签:
很赞哦! ()
相关教程
图文教程
帝国cms动态页面调用栏目导航的方法
帝国cms动态页面是不支持默认标签使用的,除非修改一下让动态页面支持标签语法。如果不会也可以用PHP+SQL的方法写,如下方代码
帝国cms内容字段文本替换函数的代码
最近有小伙伴问帝国cms内容字段文本替换函数的方法,代码号乐此不疲的分享了下面这段代码,今天代码号就也分享出来给大家。
帝国CMS文章自动提取简介后双引号显示成”
一般的站长在正常情况下录入文章的时间一般是不会单独手动真写smalltext简单内容的,在正常的情况下,帝国会自动提取正文内容里的前部分文字为简介
帝国CMS批量修改内容页文件命名形式方法
有个站内容页文件命名形式以前用的不是信息ID,用的time()或其他date()、公共信息ID、md5() 、目录的形式储存的内页。
相关源码
-
(自适应)帝国cms7.5文章新闻博客整站源码( 带会员中心)本模板基于帝国CMS内核开发,为新闻资讯、个人博客及作品展示类网站设计。采用响应式布局技术,确保在手机、平板和电脑等不同设备上都能获得良好的浏览体验。查看源码 -
(PC+WAP)玻璃钢不锈钢钢材环保设备pbootcms网站模板采用PbootCMS内核开发的响应式网站模板,为玻璃钢环保设备制造、不锈钢钢材贸易企业设计,适配产品展示及企业服务场景。通过自适应技术实现PC与WAP端数据实时同步查看源码 -
(自适应响应式)工业机床工程农业机械设备网站源码下载框架适用于工程机械、机床设备等工业领域。通过模块调整可快速转型为农业机械、物流设备展示系统。预留7种工业产品展示模板。查看源码 -
pbootcms模板PC+WAP娱乐新闻资讯类博客网站源码该模板基于PbootCMS内核开发,专为娱乐新闻、健康生活类资讯网站设计,同时支持快速适配其他行业(如企业官网、博客门户等),仅需替换图文内容即可完成转型。查看源码 -
(PC+WAP)蓝色弹簧针厂家探针充电连接器设备网站源码下载基于PbootCMS开发的响应式模板,为弹簧针、探针连接器等电子元器件企业设计。模板采用工业蓝主色调,突出产品技术特性,支持多维度展示连接器产品的规格参数与应用场景,帮助制造企业建立专业线上展示平台。查看源码 -
(自适应)光伏测试仪器电站运维设备网站源码免费下载本模板为光伏检测设备与电站运维服务企业设计,采用PbootCMS内核开发,具备完整的设备展示、技术文档管理及客户服务功能模块。通过自适应结构与SEO优化框架,有效提升企业在移动端和搜索引擎中的专业形象。查看源码
| 分享笔记 (共有 篇笔记) |

