Подсвечивание кода с помощью jQuery и Chili

В этом руководстве мы научимся подсвечивать исходный код с помощью плагина Chili для jQuery. Мы узнаем, как видоизменять Chili для повышения читаемости и удобства использования подсветки в собственных функциях.

[Демо] [Исходный код]

Содержание

Введение

В первом руководстве вы узнаете, как подсвечивать исходный код с помощью плагина jQuery Chili. И это не очередная быстрая справка по Chili: мы научимся видоизменять Chili по собственному усмотрению и интегрировать в него собственные функции для повышения читаемости подсвечиваемого кода.

С чего начать

xHTML

Для начала возьмем несложную разметку с контентной областью и боковой панелью, пока ничего особенного. Воспользуемся двумя примерами боксов, один с полосой прокрутки и один – без. Вот как выглядит вся разметка:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
 <head> 
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 
 
 <title>Demo for - 'Подсветка исходного кода с jQuery и Chili'</title> 
 
 <link rel="stylesheet" type="text/css" media="screen" href="css/reset.css" /> 
 <link rel="stylesheet" type="text/css" media="screen" href="css/960.css" /> 
 <link rel="stylesheet" type="text/css" media="screen" href="css/main.css" /> 
 </head> 
 
 <body> 
 <div class="container_12" id="wrapper"> 
 <div class="grid_8" id="content"> 
 <h1>Demo for '<a href="#">Подсветка исходного кода с jQuery и Chili</a>'</h1> 
 
 <p> 
 В первом примере мы хотим показать отрывок кода jQuery. Заметьте, что у бокса подсветки нет горизонтальной полосы прокрутки, потому что контент входит весь. 
 </p> 
 
 <!-- relevant for the tutorial! - start --> 
<pre><code>$(document).ready(function() { 
 $('div:first').text('DOM Ready!') 
});</code></pre> 
 <!-- важно! - end --> 
 
 <p> 
 Во втором примере возьмем немного CSS. Заметьте, что сейчас у нас есть горизонтальная полоса прокрутки, поскольку длинные строки в боксе не помещаются. 
 </p> 
 
 <!-- relevant for the tutorial! - start --> 
<pre><code>html { font-size: 16px; } 
body { font-size: 62.5%; font-family: Verdana, Arial, sans-serif; color: #555555; background: #22384d url(../images/bg.jpg) repeat-x; } 
a { color: #0F67A1; text-decoration: none; } 
a:hover { text-decoration: underline; }</code></pre> 
 <!-- важно! - end --> 
 
 <div id="footer"> 
 (c) 2009 - <a href="http://thisblog.usejquery.com/">В этом блоге используется jQuery</a> 
 </div> 
 </div> 
 
 <div class="grid_4" id="sidebar"> 
 <ul> 
 <li> 
 <h2>What's that?</h2> 
 <p> 
 Это демо-страница руководства с сайта <a href="http://thisblog.usejquery.com/">«В этом блоге используется jQuery»</a>. 
 Если вы пришли откуда-то еще, можете проверить, как работает эта демо-страница. 
 </p> 
 </li> 
 </ul> 
 </div> 
 <div class="clear"></div> 
 </div> 
 </body> 
</html>

Все по самому минимуму. Обратим внимание на подсвеченный бокс:


Бокс без подсветки
Нужно только вставить jQuery, Chili и наш скрипт в заголовок и отредактировать исходный код в этих местах.

CSS

Таблица стилей тоже самая базовая, ничего особенного в ней нет. В коде помечено, на что нужно обратить внимание в данном случае:

html { font-size: 16px; } 
body { font-size: 62.5%; font-family: Verdana, Arial, sans-serif; color: #555555; background: #22384d url(../images/bg.jpg) repeat-x; } 
a { color: #0F67A1; text-decoration: none; } 
a:hover { text-decoration: underline; } 
 
#wrapper { background: white url(../images/sidebar_bg.jpg) repeat-y top right; } 
 
#content { } 
 #content h1 { font-size: 2.4em; font-weight: normal; line-height: 32px; margin: 30px 0 50px 0; } 
 #content p { font-size: 1.4em; line-height: 22px; margin-bottom: 20px; } 
 
 /* важно! - start */ 
 #content pre { 
 font-size: 12px; 
 line-height: 20px; 
 width: 620px; 
 overflow: auto; 
 overflow-y: hidden; 
 background: url(../images/code_bg.jpg); 
 margin: 10px 0 20px 0; 
 } 
 
 #content pre code { display: block; margin-left: 20px; } 
 /* важно! - end */ 
 
#footer { text-align: center; margin: 50px 0 20px 0; } 
 
#sidebar { } 
 #sidebar ul { margin-top: 20px; } 
 #sidebar ul li { font-size: 1.2em; padding: 20px 0 20px 0; border-bottom: 1px solid #dddcdc; line-height: 18px; } 
 #sidebar ul li h2 { font-size: 1.2em; margin-bottom: 8px; }

Маленькие помощники

Вот две дополнительных таблицы стилей, помогающие немного ускорить процесс. В следующей демонстрации я буду часто использовать эти две полезные таблицы, но каждый раз напоминать об этом не буду. Просто не забывайте об этом.

У нас имеется файл reset.css. Как и следует из названия, он предназначен для сбрасывания стилей браузера по умолчанию. Лично мне нравится вариант Эрика Мейера.

Файл 960.css – это система разметки, помогающая буквально за минуту придать разметке нужный стиль для всех распространенных разрешений.

Загрузка, вставка и активация Chili

Итак, мы настроили демо-страницу, и теперь самое время поставить Chili. Во-первых, загрузите самую свежую версию. На момент написания данного руководства это версия 2.2.

Извлекаем из архива нужные нам файлы: jquery.chili-2.2.js, recipes.js и языковые файлы (recipes). В нашем примере мы пользуемся только JavaScript и CSS, поэтому нам понадобятся js.js и css.js. Теперь файловая структура примера выглядит следующим образом:

/js/
 jquery-1.3.2.min.js
 /chili/
 jquery.chili-2.2.js
 recipes.js
 js.js
 css.js

Затем вставляем jQuery, Chili и Recipes в заголовок:

<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/chili/jquery.chili-2.2.js"></script>
<script type="text/javascript" src="js/chili/recipes.js"></script>

Теперь активируем Chili, установив атрибуты класса в тэгах pre и code:

<pre class="ln-124"><code class="js">$(document).ready(function() {
 $('div:first').text('DOM Ready!')
});</code></pre>

Класс In-124 предписывает Chili начать обработку упорядоченного списка со 124-й строки. Чтобы начать с первой, ставьте просто In-. Класс js сообщает Chili, какой язык мы хотим подсветить.

Вот и почти все. Один небольшой нюанс: в конце нужно вернуть числа в упорядоченные списки, поскольку reset.css убрал list-style. Для этого добавим небольшую строку в main.css:

#content ol { list-style: decimal; margin-left: 25px; }

Вуаля! За несколько несложных шагов мы получили подсвеченный код, не написав при этом ни строки JavaScript. А теперь перейдем к самой интересной части 🙂


CSS, подсвеченная с помощью Chili

Видоизменение Chili

Как вы могли заметить, Chili работает просто великолепно. Безупречная интеграция, мгновенное срабатывание. Но что лично мне не нравится, так это хелпер селектора. Сама идея хорошая, но вот реализация явно подкачала.


Поэтому мы немного поменяем код Chili, чтобы этот хелпер не появлялся всякий раз, когда пользователь выбирает исходный код. Позже мы даже заменим эту функцию своей собственной.

Хелпер регулируется в строке 504 файла jquery.chili-2.2.js:[/HTML]

function enableSelectionHelper( el ) { 
 var element = null; 
 $( el ) 
 //...

Чтобы его отключить, сначала вернем управление вызывающей программе:

function enableSelectionHelper( el ) { 
 return false; //деактивация хелпера селектора 
 var element = null; 
 $( el ) 
 //...

Вот и все: хелпер Chili отключен, и теперь мы заменим его на собственные функции jQuery.

Улучшение читаемости длинных строк кода

В нашем примере второй подсвеченный бокс имеет горизонтальную полосу прокрутки, поскольку ширина (width) бокса недостаточна для контента. Мы хотим сделать так, чтобы бокс увеличивался по ширине, когда пользователь наводит на него курсор мыши, и возвращался к первоначальному размеру, когда пользователь курсор убирает. Можно даже придать этому процессу немного шарма, добавив небольшую анимацию с использованием jQuery.

Для начала важно убедиться, что мы вставили скрипт в заголовок до Chili. Таким образом мы удостоверимся в том, что скрипт будет работать с оригинальным DOM. Позже Chili сможет его модифицировать.

<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script> 
<script type="text/javascript" src="js/demo.js"></script> 
<script type="text/javascript" src="js/chili/jquery.chili-2.2.js"></script> 
<script type="text/javascript" src="js/chili/recipes.js"></script>

Проблема

Как определить, есть у бокса горизонтальная полоса прокрутки или нет? Конечно, первым на ум приходит использовать width() в блоке <code>. Если ширина больше, чем <pre>, тогда у нее должна быть полоса прокрутки. Аргумент понятный, но работать это не будет, потому что прочитать реальную ширину блока <code> невозможно. Вот небольшой пример и его результат:

$(document).ready(function() { //действие по готовности DOM 
 var codeBox = $('#content pre code:last'); //получаем второй бокс с полосой прокрутки 
 
 //показываем ширину родительского <pre> и <code> 
 alert('<pre> width: ' + codeBox.parent().width() + "n" + '<code> width: ' + codeBox.width()); 
});

Результат показывает, что ширина блока даже меньше, чем блока – из-за margin-left.


Проблема ширины с горизонтальной полосой прокрутки
И тут не поможет ни чтение innerWidth(), ни плагин Dimensions.

Решение

Чтобы определить, есть или нет горизонтальная полоса прокрутки у блока <pre>, нужно знать не ширину, а высоту блоков <pre> и <code>! Попробуем вот на этом примере:

$(document).ready(function() { //действие по готовности DOM 
 //получаем первый и второй (последний) элемент бокса для сравнения 
 var codeBoxOne = $('#content pre code:first'); 
 var codeBoxTwo = $('#content pre code:last'); 
 
 //показываем высоту 
 alert( 
 "Code-Box 1:n<pre> height - " + codeBoxOne.parent().height() + "n<code> height - " + codeBoxOne.height() + "nn" + 
 "Code-Box 2:n<pre> height - " + codeBoxTwo.parent().height() + "n<code> height - " + codeBoxTwo.height() 
 ); 
});

Результат:


Вывод параметров height
Отсюда видим, что у второго бокса, который с полосой прокрутки, высота по блокам разная! Дополнительную высоту блоку <pre> придает сама полоса прокрутки. Таким образом мы получаем формулу: если высота <pre> больше высоты <code>, то бокс нужно расширить.

Код

$(document).ready(function() { //действие по готовности DOM 
 var initialWidth = $('#content pre:first').width(); //сохраним начальную ширину боксов для сброса при убирании курсора 
 
 $('pre').hover(function() { //при наведении курсора 
 if($(this).height() > $(this).children().height()) { //если <pre> больше <code> 
 var openSpace = Math.round(($('body').width() - initialWidth) / 2 - 10); //считаем место справа с margin-right на 10px 
 
 if($(this).width() == initialWidth) { //запускаем анимацию только в стартовой точке (начальная ширина) 
 $(this).animate({ width : initialWidth + openSpace }, 'fast'); //увеличиваем ширину анимацией 
 } 
 } 
 }, function() { //при убирании курсора 
 $(this).animate({ width : initialWidth }, 'fast'); //сброс к начальным значениям анимацией 
 }); 
});

Теперь разобьем этот небольшой скрипт на элементы, что тоже интересно.

var initialWidth = $('#content pre:first').width(); //сохраним начальную ширину боксов для сброса по убиранию курсора

Во-первых, сохраним первоначальную ширину боксов, чтобы не было статических значений. Преимущество в том, что так мы сможем менять дизайн страницы и ширину боксов, не трогая скрипт.

var openSpace = Math.round(($('body').width() - initialWidth) / 2 - 10); //считаем место справа с margin-right на 10px

Теперь считаем, сколько осталось места, чтобы расширить рамку кода направо.

if($(this).width() == initialWidth) { //запускаем анимацию только в стартовой точке (начальная ширина)

Анимацию мы запускаем только тогда, если мы еще в стартовой точке первоначальной ширины. Если мы уже в анимации, то заново запускать ее не надо.

Вот и все, теперь боксы расширяются при наведении курсора. Немного огорчает то, что эта функция не работает в IE, поскольку полосы прокрутки не дают дополнительную высоту. Но мне кажется, что те, кто всерьез интересуется исходными кодами, не особо жалуют IE. Но даже если они им пользуются, им просто придется прокрутить вручную, что вряд ли испортит впечатление от сайта.

Улучшение удобства использования с помощью Plain Text

Поскольку мы убрали из Chili хелпер селектора, пользователю стало сложно выбрать и скопировать исходный код. В одних браузерах проблем нет, но в других копируются еще и номера строк. В итоге получается бардак, поэтому попробуем сделать функцию более дружественной.

Нам нужно, чтобы текстовая область с исходным кодом появлялась только при необходимости и менялась местами с подсвеченным боксом. Это делается с помощью следующего кода:

$(document).ready(function() { //действие только по готовности DOM 
 $('#content pre').each(function() { //по каждому боксу 
 $(this) 
 .before('<a href="#" class="codeswitch">Просмотр исходника в Plain Text</a>') //пишем код прямо перед боксом 
 .after('<textarea rows="' + ($(this).children().html().split("n").length-1) + '" cols="50">' + $(this).children().html() + '</textarea>'); //пишем текстовую область с содержанием бокса 
 }); 
 
 $('.codeswitch').toggle(function() { //прячем бокс кода и показываем текстовую область 
 $(this) 
 .text('View this source as Highlighted Code') //меняем текст ссылки 
 .next().hide().next().show(); //сначала бокс, потом текстовая область 
 }, function() { //прячем текстовую область и показываем бокс кода 
 $(this) 
 .text('Просмотр исходника в Plain Text') 
 .next().show().next().hide(); 
 }); 
});

Снова разделим этот фрагмент кода на интересные части.

$('#content pre').each(function() { //по каждому боксу 
 $(this) 
 .before('<a href="#" class="codeswitch">Просмотр исходника в Plain Text</a>') //пишем код прямо перед боксом 
 .after('<textarea rows="' + ($(this).children().html().split("n").length-1) + '" cols="50">' + $(this).children().html() + '</textarea>'); //пишем текстовую область с содержанием бокса 
});

Здесь мы прокручиваем все <pre> (боксы). Перед блоком <pre> ставим ссылку, чтобы пользователь смог переключаться между боксом и текстовой областью. Первый next() представляет бокс, второй – текстовую область. Если бокс виден, тогда мы его прячем и показываем текстовую область, и наоборот. Каждый раз мы меняем текст ссылки, чтобы пользователь понимал, что произойдет при клике на нее.

Естественно, можно и нужно задать текстовой области стиль через CSS:

#content textarea { width: 620px; line-height: 20px; margin: 10px 0 20px 0; font-size: 12px; display: none; }

Сейчас текстовая область по умолчанию скрыта и у нее такие же width, line-height и margin, как и бокса.

Заключение

Симпатично выглядит, правда? Несколько простых шагов, и мы получили удобный и хорошо читаемый бокс с помощью Chili и модифицированного кода jQuery. Не стесняйтесь высказывать свои комментарии, пожелания и вопросы.

Данная статья является переводом Highlight your source code with jQuery and Chili.
Переведено проектом для вебмастера: территория вебразработки

Меню