null

Liferay 6 и SyntaxHighlighter

Год назад я уже писал о решении задачи интеграции плагина SyntaxHighlighter в состав Liferay Portal. За это время успела выйти новая версия портала - Liferay 6, в силу чего задача вновь стала актуальной. Посмотрим, как изменилось её решение после обновления портала.

Напомню суть описанного в прошлом году решения. Во-первых, нам нужно поместить сам SyntaxHighlighter в JS-библиотеки Liferay и сконфигурировать портал таким образом, чтобы подсветка исходников была применена к выбранным нами портлетам (обычно это отображение сетевого контента, блоги и Wiki). Во-вторых, нам нужно добавить SyntaxHighlighter-плагин в текстовый редактор, чтобы автор текста мог отмечать выбранные фрагменты как исходный код.

Наиболее важным отличием Liferay 6 от предыдущей версии с точки зрения визуального редактирования текста стало обновление дефолтного текстового редактора - теперь вместо FCKEditor v.2.X используется CKEditor v3. Помимо всего прочего, в новой версии немного изменились правила регистрации плагинов, в силу чего предложенная в моей предыдущей заметке конфигурация перестала работать. Кроме того, несколько изменилась структура исходников самого портала, что тоже приходится учитывать при интеграции плагина.

С учётом всех перечисленных изменений, процесс интеграции функции подсветки синтаксиса в текстовый редактор портала теперь выглядит так:

1. Скачиваем SyntaxHighlighter и плагин для CKEditor.

2. Скачиваем исходники Liferay Portal. Можно скачать и бинарники - т. к. править будем только конфиги, сути процесса это не изменит, но в этом случае пути к файлам будут несколько отличаться от приведённых здесь. Открываем исходники. Напомню, что исходники Liferay представляют из себя проект для IDE Netbeans, так что логично будет использовать именно эту среду разработки (хотя для сборки хватит и "голого" Apache Ant).

3. Копируем SyntaxHighlighter в каталог portal-web/docroot/html/js исходников портала. В итоге этот каталог станет выглядеть как-то так:

jek@jek-laptop:/opt/projects/liferay6/liferay-portal-src-6.0.6$ ls -lA portal-web/docroot/html/js/
итого 40
drwxr-xr-x 121 jek jek 4096 2011-04-06 15:09 aui
-rw-------   1 jek jek  594 2011-04-02 03:12 barebone.jsp
drwx------   3 jek jek 4096 2011-04-02 03:12 calendar
drwx------  10 jek jek 4096 2011-04-06 15:10 editor
-rw-------   1 jek jek  594 2011-04-02 03:12 everything.jsp
drwx------   2 jek jek 4096 2011-04-02 03:11 firebug
drwx------   2 jek jek 4096 2011-04-02 03:12 jquery
drwx------   2 jek jek 4096 2011-04-02 03:11 liferay
drwx------   3 jek jek 4096 2011-04-02 03:12 misc
drwx------   5 jek jek 4096 2011-04-02 03:12 syntaxhighlighter

4. Конфигурируем настройки нужных нам портлетов так, чтобы в них подсвечивался исходный код. Делается это путём модификации файла portal-web/docroot/WEB-INF/liferay-portlet.xml в исходниках. К конфигурации нужных нам плагинов нужно добавить такие строчки (тут с прошлого года ничего не изменилось):

<header-portlet-css>/html/js/syntaxhighlighter/styles/shCore.css</header-portlet-css>
<header-portlet-css>/html/js/syntaxhighlighter/styles/shThemeDefault.css</header-portlet-css>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shCore.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushAS3.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushBash.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushCss.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushCSharp.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushCpp.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushDelphi.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushDiff.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushJava.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushJScript.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPerl.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPhp.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPlain.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPython.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushRuby.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushSql.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushVb.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushXml.js</header-portlet-javascript>
<header-portlet-javascript>/html/js/syntaxhighlighter/customConfig.js</header-portlet-javascript>

Например, конфигурация портлета "Отображение сетевого контента" после всех модификаций будет выглядеть так:

<portlet>
	<portlet-name>15</portlet-name>
	<icon>/html/icons/journal.png</icon>
	<struts-path>journal</struts-path>
	<configuration-action-class>com.liferay.portlet.journal.action.ConfigurationActionImpl</configuration-action-class>
	<indexer-class>com.liferay.portlet.journal.util.JournalIndexer</indexer-class>
	<open-search-class>com.liferay.portlet.journal.util.JournalOpenSearchImpl</open-search-class>
	<scheduler-entry>
		<scheduler-event-listener-class>com.liferay.portlet.journal.messaging.CheckArticleMessageListener</scheduler-event-listener-class>
		<trigger>
			<simple>
				<property-key>journal.article.check.interval</property-key>
				<time-unit>minute</time-unit>
			</simple>
		</trigger>
	</scheduler-entry>
	<friendly-url-mapper-class>com.liferay.portal.kernel.portlet.DefaultFriendlyURLMapper</friendly-url-mapper-class>
	<friendly-url-mapping>journal</friendly-url-mapping>
	<friendly-url-routes>com/liferay/portlet/journal/journal-friendly-url-routes.xml</friendly-url-routes>
	<portlet-data-handler-class>com.liferay.portlet.journal.lar.JournalPortletDataHandlerImpl</portlet-data-handler-class>
	<webdav-storage-token>journal</webdav-storage-token>
	<webdav-storage-class>com.liferay.portlet.journal.webdav.JournalWebDAVStorageImpl</webdav-storage-class>
	<control-panel-entry-category>content</control-panel-entry-category>
	<control-panel-entry-weight>1.0</control-panel-entry-weight>
	<asset-renderer-factory>com.liferay.portlet.journal.asset.JournalArticleAssetRendererFactory</asset-renderer-factory>
	<workflow-handler>com.liferay.portlet.journal.workflow.JournalArticleWorkflowHandler</workflow-handler>
	<preferences-unique-per-layout>false</preferences-unique-per-layout>
	<use-default-template>false</use-default-template>
	<scopeable>true</scopeable>
	<private-request-attributes>false</private-request-attributes>
	<private-session-attributes>false</private-session-attributes>
	<render-weight>50</render-weight>
	<header-portlet-css>/html/portlet/journal/css/main.jsp</header-portlet-css>
	<!-- syntax highlighter -->
	<header-portlet-css>/html/js/syntaxhighlighter/styles/shCore.css</header-portlet-css>
	<header-portlet-css>/html/js/syntaxhighlighter/styles/shThemeDefault.css</header-portlet-css>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shCore.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushAS3.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushBash.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushCss.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushCSharp.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushCpp.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushDelphi.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushDiff.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushJava.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushJScript.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPerl.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPhp.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPlain.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushPython.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushRuby.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushSql.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushVb.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/scripts/shBrushXml.js</header-portlet-javascript>
	<header-portlet-javascript>/html/js/syntaxhighlighter/customConfig.js</header-portlet-javascript>
	<!-- ... -->
	<header-portlet-javascript>/html/portlet/journal/js/main.js</header-portlet-javascript>
	<css-class-wrapper>portlet-journal</css-class-wrapper>
	<add-default-resource>true</add-default-resource>
</portlet>

Теперь наш портал сможет показывать отформатированный и подсвеченный код. Осталось добавить поддержку добавления фрагментов кода в текстовый редактор. В новом Liferay вместо старого FCKEditor используется его новая версия - CKEditor v3. Старая версия плагина не подходит к новой версии редактора, но, к счастью, существует порт этого плагина для CKEditor, которым мы и воспользуемся. Помимо этого, в новой версии портала несколько изменились правила добавления плагинов в текстовый редактор, так что наша итоговая конфигурация будет несколько отличаться от прошлогодней.

5. Качаем плагин и помещаем его в каталог исходников portal-web/docroot/html/js/editor/ckeditor_diffs/. Содержимое этого каталога в процессе сборки портала будет добавлено в CKEditor. В предыдущей версии Liferay для той же цели был предназначен каталог _fckeditor.

6. Добавляем кнопку вызова плагина на панель управления текстовым редактором. Для этого нужно изменить файл ckconfig.jsp, который лежит в том же каталоге. Заменяем его содержимое на следующее:

<%@ page import="com.liferay.portal.kernel.util.HtmlUtil" %>
<%@ page import="com.liferay.portal.kernel.util.ParamUtil" %>

<%
String cssPath = ParamUtil.getString(request, "cssPath");
%>

CKEDITOR.addStylesSet(
	'liferayStyles',
	[

	// Block Styles

	{name: 'Normal', element : 'p'},
	{name: 'Heading 1', element : 'h1'},
	{name: 'Heading 2', element : 'h2'},
	{name: 'Heading 3', element : 'h3'},
	{name: 'Heading 4', element : 'h4'},

	//Special classes

	{name: 'Preformatted Text', element:'pre'},
	{name: 'Cited Work', element:'cite'},
	{name: 'Computer Code', element:'code'},

	//Custom styles

	{name : 'Info Message', element : 'div', attributes : {'class' : 'portlet-msg-info'}},
	{name : 'Alert Message', element : 'div', attributes : {'class' : 'portlet-msg-alert'}},
	{name : 'Error Message', element : 'div', attributes : {'class' : 'portlet-msg-error'}}
	]
);

CKEDITOR.config.contentsCss = '<%= HtmlUtil.escape(cssPath) %>/main.css';

CKEDITOR.config.entities = false;

CKEDITOR.config.resize_enabled = false;

CKEDITOR.config.height = 265;

CKEDITOR.config.stylesCombo_stylesSet = 'liferayStyles';

CKEDITOR.config.extraPlugins = 'syntaxhighlight';
CKEDITOR.config.toolbar_Full.push(['Code']);

CKEDITOR.config.toolbar_liferay = [
	['Styles', 'FontSize', '-', 'TextColor', 'BGColor'],
	['Bold', 'Italic', 'Underline', 'StrikeThrough'],
	['Subscript', 'Superscript'],
	'/',
	['Undo', 'Redo', '-', 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'SelectAll', 'RemoveFormat'],
	['Find', 'Replace', 'SpellCheck'],
	['OrderedList', 'UnorderedList', '-', 'Outdent', 'Indent'],
	['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
	'/',
	['Source'],
	['Link', 'Unlink', 'Anchor'],
	['Image', 'Flash', 'Table', '-', 'Smiley', 'SpecialChar', 'Code']
];

CKEDITOR.config.toolbar_liferayArticle = [
	['Styles', 'FontSize', '-', 'TextColor', 'BGColor'],
	['Bold', 'Italic', 'Underline', 'StrikeThrough'],
	['Subscript', 'Superscript'],
	'/',
	['Undo', 'Redo', '-', 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'SelectAll', 'RemoveFormat'],
	['Find', 'Replace', 'SpellCheck'],
	['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],
	['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
	'/',
	['Source'],
	['Link', 'Unlink', 'Anchor'],
	['Image', 'Flash', 'Table', '-', 'Smiley', 'SpecialChar', 'LiferayPageBreak', 'Code']
];

CKEDITOR.config.toolbar_editInPlace = [
	['Styles'],
	['Bold', 'Italic', 'Underline', 'StrikeThrough'],
	['Subscript', 'Superscript', 'SpecialChar'],
	['Undo', 'Redo'],
	['SpellCheck'],
	['OrderedList', 'UnorderedList', '-', 'Outdent', 'Indent'], ['Source', 'RemoveFormat'],
];

CKEDITOR.config.toolbar_email = [
	['FontSize', 'TextColor', 'BGColor', '-', 'Bold', 'Italic', 'Underline', 'StrikeThrough'],
	['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
	['SpellCheck'],
	'/',
	['Undo', 'Redo', '-', 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'SelectAll', 'RemoveFormat'],
	['Source'],
	['Link', 'Unlink'],
	['Image']
];

Пересобираем и развёртываем портал. В текстовом редакторе должна появится кнопка форматирования кода:

Новая кнопка
 

Текст, добавляемый с помощью этого плагина, будет отформатирован в соответствии с правилами выбранного языка:

Подсветка bash

Коротко о себе:

Работаю ведущим программистом в компании Tune IT и ассистентом кафедры Вычислительной техники в Университете ИТМО .

Занимаюсь проектами, связанными с разработкой разного рода веб-приложений (порталы, CRM-системы, системы электронного документооборота), а также, в рамках научной работы на кафедре, изучаю возможности применения семантического анализа в задачах САПР.

Ничего не найдено. n is 0