Делаем syntax highlighter plugin для TinyMCE
Многие из нас сталкивались с проблемой подсветки программного кода в своем блоге. Наверно, одно из самых лучших на сегодняшний день решений - это highlight.js, разработан Иваном Сагалаевым.
Это все круто конечно, но меня не устраивало то, что каждый раз, когда кто-то зайдет на страничку статьи, его браузер будет во всем DOM дереве искать нужные теги и производить их обработку.
Ставим задачу
- подсветка синтаксиса, неважна технология, важно просто, удобно и оптимизировано
- возможность работать с этим в TinyMCE
- возможность видеть подсвеченный код в TinyMCE
Решение
Все оказалось достаточно простым, благодаря уже реализованному плагину для TinyMCE. Скачиваем SyntaxHL, он предоставит простую функциональность popup-a с выбором типа, а так же настройками вставляемого кода. Сохраняем его в tiny_mce/plugins/ и подключаем. В настройках инициализации TinyMCE делаем следующее:
tinyMCE.init({
// подключаем плагин
plugins : "... ,syntaxhl, ....",
// определяем местоположение кнопки
theme_advanced_buttons1 : "... , syntaxhl, ...",
....................................
// Подключаем таблицу стилей подсветки
content_css : "/_inc/highlighter/", // стили можно перечислять через запятую
Если вы все сделали правильно, то в редакторе должна появится кнопка.
Теперь скачиваем последнюю версию Highlight.js с сайта разработчика и копируем ее в tiny_mce/plugins/syntaxhl/js/hljs. Подключаем движек подсветки синтаксиса. Для этого открываем файл tiny_mce/plugins/syntaxhl/dialog.htm, и добавляем перед закрывающим тегом </head>:
<script type="text/javascript" src="js/hljs/highlight.pack.js"></script>
Открываем файл tiny_mce/plugins/syntaxhl/js/dialog.js, ищем строки:
var SyntaxHLDialog = {
init : function() {
},
меняем на
var SyntaxHLDialog = {
wrapper: document.createElement('div'),
init : function() {
},
В том же файле
textarea_output = '<pre class="brush: ';
textarea_output += f.syntaxhl_language.value + ';' + options + '">';
textarea_output += tinyMCEPopup.editor.dom.encode(f.syntaxhl_code.value);
textarea_output += '</pre> '; /* note space at the end, had a bug it was inserting twice? */
tinyMCEPopup.editor.execCommand('mceInsertContent', false, textarea_output);
tinyMCEPopup.close();
заменяем на:
f.syntaxhl_code.value = f.syntaxhl_code.value.replace(/</g,'<');
f.syntaxhl_code.value = f.syntaxhl_code.value.replace(/>/g,'>');
textarea_output = '<pre><code ';
textarea_output += 'class="' + f.syntaxhl_language.value + '">';
textarea_output += f.syntaxhl_code.value;
textarea_output += '</code></pre> ';
/* делаем подсветку сразу и передаем полученный HTML в tinyMCE */
this.wrapper.innerHTML = textarea_output;
hljs.highlightBlock(this.wrapper.firstChild.firstChild, ' ');
tinyMCEPopup.editor.execCommand('mceInsertContent', false, this.wrapper.innerHTML);
tinyMCEPopup.close();
Теперь немного разберем, что мы сделали. Мы создали элемент-обертку и сперва вставляем в него код, далее при помощи метода hljs.highlightBlock подсвечиваем нужные символы и вставляем в tinyMCE уже подготовленный для отображения код.
Таким же образом, можно подключить и любой другой движек подсветки синтаксиса.
Теперь при нажатии на кнопочку syntaxHL у вас должно появиться окно, в которое вы можете вставить код, выбрать его тип, и он будет обрамлен в нужные нам теги.
Нюансы
Откроем файл tiny_mce/plugins/syntaxhl/dialog.html и вносим небольшие поправки в названия языков (например, в SyntaxHL по умолчанию JavaScript обозван value="jscript", и Highlight.js такой класс не поймет, поэтому его надо переименовать в value="javascript"), а так же сортируем их в удобной нам последовательности. У меня выглядит так:
<select name="syntaxhl_language" id="syntaxhl_language">
<option value="php">PHP</option>
<option value="javascript">Javascript</option>
<option value="css">CSS</option>
<option value="html">XML/XHTML</option>
<option value="sql">SQL</option>
<option value="cpp">C++</option>
<option value="bash">Bash(Shell)</option>
<option value="perl">Perl</option>
<option value="ruby">Ruby</option>
<option value="plain">Plain(Text)</option>
<option value="diff">Diff</option>
<option value="delphi">Delphi</option>
<option value="groovy">Groovy</option>
<option value="java">Java</option>
<option value="python">Python</option>
<option value="scala">Scala</option>
<option value="vb">VB</option>
<option value="csharp">C#</option>
</select>
ВНИМАНИЕ! Если у вас стоит русифицированный tinyMCE, то вам необходимо перейти в папку tiny_mce/plugins/syntaxhl/langs/ и сделать копии имеющихся там файлов en.js и en_dlg.js, и переименовать в ru.js и ru_dlg.js соответственно.
Чтобы видеть подсветку в tinyMCE, нужно в его инициализации добавить одну из тем highlight.js
Результат
Готовое решение можно скачать ЗДЕСЬ
Если Вас заинтерисовала эта статья, то так же полезно будет почитать это: Вырезается вводимый HTML-код в TinyMCE?