Сегодня расскажу вам чудесную историю про то, как добавить в редактор CKEditor полноэкранный режим.
Достаточно часто при написании статей в блоге я ловил себя на мысли, что окно редактора для ввода контента очень маленькое и это жутко бесит. Конечно в редакторе есть по умолчанию справа внизу специальная кнопка для растягивания (рисунок ниже)

Вот только в нашем случае это не поможет. Дело в том, что редактор находится внутри портлета, который размещен внутри страницы в определнном блоке, который определяется шаблоном страницы. У нас используется трёхколоночный макет. Из-за этого нет возможности растягивать редактор по ширине.
В какой-то момент я понял, что больше не могу с этим жить и нужно просто добавить эту фичу в редактор. Для меня было очевидно, что это базовая фича должна быть уже написана в каком-то виде и велосипедов писать не придётся. В чертогах моего сознания этот редактор ассоциировался с библиотекой CKEditor, о которой я несколько раз слышал, но трогать не приходилось.
Узнав у коллег, что действительно в портелете блогов у нас используется CKEditor, я отправился на оффициальный сайт этого компонента. Стоило мне открыть демо на сайте. И я сразу же увидел заветную кнопку. Вот она. Манящая и чарующая. Фича о которой я мечтаю.

Казалось, что дело в шляпе. Осталось просто показать её в интерфейсе или прикрутить штатными мехназимами CKEditor'а. Минутка поиска в Google и я узнаю, что эта кнопка добавляется с помощью плагина на CKEditor. Плагин называется maximize. Скачать его и почитать о нём можно тут. Мало того, что есть штатные механизмы добавления в редактор полноэкранного режима, так ещё и оказалось, что в блоге моего коллеги уже есть статья, описывающая процесс установки плагина для CKEditor в 7 Liferay. Советую ознакомиться с ней и поблагодарить автора за её создание.
Если коротко, то в нашу задачу входит написание двух OSGI фрагментов. C помощью первого мы подсунем в Лайфрейный CKEditor наш плагин (статические файлы), а вторым мы поправим настройки редактора, указав ему использовать наш новый плагин, а также настроим toolbar редактора, чтобы в нём появилась долгожданная кнопка.
Настоятельно рекоммендую прочитать статью Ивана, ссылку на которую я дал выше, ибо ниже я буду приводить лишь выжимки кода без объяснений.
Проект из архетипа, с важным указанием как потом это связать с ckeditor'ом.
mvn archetype:generate \
-DarchetypeGroupId=com.liferay \
-DarchetypeArtifactId=com.liferay.project.templates.fragment \
-DliferayVersion=7.0 \
-DartifactId=maximaze-plugin \
-Dpackage=com.test \
-DgroupId=com.test \
-Dversion=1.0 \
-DhostBundleSymbolicName=com.liferay.frontend.editor.ckeditor.web \
-DhostBundleVersion=1.0.43
Копируем код скачанного плагина сюды
src/
└── main
└── resources
└── META-INF
└── resources
└── ckeditor
└── plugins
└── КОПИРОВАТЬ СЮДА!
Во втором модуле создаём(без ключей Dhost*) компонент наследник BaseEditorConfigContributor и указываем плагин maximize. Плюс необходимо настроить toolbar. Код будет примерно следующий:
@Component(
immediate = true,
property = {
"editor.name=ckeditor",
"editor.config.key=contentEditor",
"javax.portlet.name=com_liferay_blogs_web_portlet_BlogsPortlet",
"javax.portlet.name=com_liferay_blogs_web_portlet_BlogsAdminPortlet",
"service.ranking:Integer=1000000"
},
service = EditorConfigContributor.class
)
public class EditorConfig extends BaseEditorConfigContributor {
@Override
public void populateConfigJSONObject(JSONObject jsonObject, Map<String, Object> inputEditorTaglibAttributes, ThemeDisplay themeDisplay, RequestBackedPortletURLFactory requestBackedPortletURLFactory) {
String extraPlugins = jsonObject.getString(ConfigConstants.EXTRA_PLUGINS_KEY);
jsonObject.put(ConfigConstants.ALLOWED_CONTENT_KEY, true);
if (!extraPlugins.isEmpty()) {
extraPlugins += ",";
}
extraPlugins += "maximize";
jsonObject.put("extraPlugins", extraPlugins);
JSONArray toolbars = JSONFactoryUtil.createJSONArray();
toolbars.put("Maximize"); //Добавили кнопку в toolbar
jsonObject.put("toolbar_liferayArticle", toolbars);
jsonObject.put("toolbar_liferay", toolbars);
jsonObject.put("toolbar_simple", toolbars);
jsonObject.put("toolbar_editInPlace", toolbars);
jsonObject.put("toolbar_tablet", toolbars);
jsonObject.put("toolbar_email", toolbars);
}
}
После выполнения этих не хитрых операций мы получаем готовый код, который можно деплоить в портал (сначала фрагмент со статикой, а потом конфиг). Но в нашей бочке мёда оказалась ложка дёгтя. На нашем портале возник неприятный баг. Заключается он в следующем. Если зайти на портал в Firefox'е, перейти в полноэкранный режим в CKEditor и выйти из этого режима назад, то окажется, что стиль курсора теперь text (выглядит примерно так 'ⵊ'). При этом при наведении на разные элементы поведение смены стиля курсора странное. Я полез смотреть css'ные стили и увидел, что есть выставленное браузером у body свойство cursor:text. При это правило пришло из какого-то странного файла conteneditable.css.

Возможно у вас такой проблемы не возникнет, но если вы тоже по какой-то причине словили такой баг, то дальнейшее может быть для вас полезно. А для везунчиков, сразу проспойлерю информацию, которую я выяснил в ходе дебага проблем с курсором. Оказывается, что фрагмент с кодом библиотеки при деплое игнорировался. Это обусловлено тем, что у Liferay уже есть Maximize из коробки и достаточно добавить нужную кнопку в Toolbar.
В общем, мы выяснили, что проблемы есть в Firefox и это связано с каким-то contentEditable. Не долго думая я полез в код этого плагина. Он состоит из одного небольшого JS файла. И там как раз упоминается этот самый contentEditable. Вот в этой функции.
function refreshCursor( editor ) {
if ( editor.editable().isInline() )
return;
// Refresh all editor instances on the page (https://dev.ckeditor.com/ticket/5724).
var all = CKEDITOR.instances;
for ( var i in all ) {
var one = all[ i ];
if ( one.mode == 'wysiwyg' && !one.readOnly ) {
var body = one.document.getBody();
// Refresh 'contentEditable' otherwise
// DOM lifting breaks design mode. (https://dev.ckeditor.com/ticket/5560)
body.setAttribute('contentEditable', false);
body.setAttribute('contentEditable', true);
}
}
if ( editor.editable().hasFocus ) {
editor.toolbox.focus();
editor.focus();
}
}
А вызывается это чудо в двух местах. И вызывается эта функция только для Firefox'а (проверка на gecko).
// Fixing positioning editor chrome in Firefox break design mode. (https://dev.ckeditor.com/ticket/5149)
CKEDITOR.env.gecko && refreshCursor( editor );
Этот прекрасный фикс нам всё портит. Попробуем его закомментировать.

Через какое-то продолжительное время, я увидел в инструментах разработчика браузера, что там отображаются JS'ники всех плагинов для CKEditor'а кроме моего. 'Радости' моей не было предела. Оказывается мой фрагмент не применился. Я начал судоржно смотреть содержимое jar архива, проверять правильный ли файл я кидаю в каталог deploy. Всё было верно. Насколько я понял позже, дело в том, что в Liferay вроде бы есть из коробки этот плагин. Но он там лежит не как отдельный плагин со своей директорией, а собран в кучу со всем внутри какого-то JS-ника в один bundle. Разбираться в том как работают кишки Liferay и что они там придумали с OSGI сил уже не было и я пошёл на радикальные шаги. Я переименовал плагин maximize на maximize2, чтобы засунуть его в Liferay и подключить. Теперь мой отладочный вывод наконец-то появился в браузере.
В конце концов я решил проблему чуть-чуть изменив код плагина. Изменения внёс в функцию refreshCursor. Изначальный вариант можете посмотреть чуть выше. А итоговый вот:
function refreshCursor( editor ) {
if ( editor.editable().isInline() )
return;
// Refresh all editor instances on the page (https://dev.ckeditor.com/ticket/5724).
var all = CKEDITOR.instances;
for ( var i in all ) {
var one = all[ i ];
if ( one.mode == 'wysiwyg' && !one.readOnly ) {
var body = one.document.getBody();
// Refresh 'contentEditable' otherwise
// DOM lifting breaks design mode. (https://dev.ckeditor.com/ticket/5560)
if (this.state == CKEDITOR.TRISTATE_ON) {
body.setAttribute('contentEditable', false);
body.setAttribute('contentEditable', true);
}
}
}
if ( editor.editable().hasFocus ) {
editor.toolbox.focus();
editor.focus();
}
}
Как видите добавилась всего одна проверка. А теперь можно взглянуть на результат:

На этом, пожалуй, откланяюсь!