Статьи

Как создать блок кода jQuery

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

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



Блок кода-фрагмента будет построен из базового элемента <pre> ; это идеальный элемент для использования, потому что он отображает все, что вы вставляете в него, в виде обычного текста шрифтом фиксированной ширины, например, в моноширинном пространстве, что идеально подходит для четкого и краткого отображения примеров кода. Он также сохраняет разрывы строк, которые мы можем использовать для добавления функций нумерации и чередования строк.

Еще одна причина, по которой мы используем тег <pre>, заключается в том, что он является идеальной основой для нашего блока кода; в браузерах с отключенным JavaScript или в тех, которые просто не поддерживают его, код будет по-прежнему отображаться приемлемо. Он будет выделяться из остального текста на странице и не будет превращаться во что-то совершенно бесполезное и смешное.

Начните со следующей страницы в вашем текстовом редакторе:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.01//EN» «http://www.w3.org/TR/html4/strict.dtd»>
<html>
  <head>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″>
    <title>jQuery Code-snippet Box</title>
    <link rel=»stylesheet» type=»text/css» href=»code-snippet.css»>
  </head>
  <body>
    <hr /><h2>CSS Code:</h2>
    <pre class=»snippet»>#selector { color:#000000;
.another-selector { font-size:20px;
tagname { width:100%;
    <script type=»text/javascript» src=»jquery-1.3.2.js»></script>
    <script type=»text/javascript»>
    </script>
  </body>
</html>

Сохраните страницу как code-snippet.html в каталоге, в котором уже находится текущая версия jQuery. Без стилизации и вмешательства скрипта страница должна выглядеть так:


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


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

В пустой элемент <script> внизу <body> добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$(function() {
          
  //process contents of snippets
  $(«pre.snippet»).each(function(){
                    
  //get contents of <pre> and create list and container
  var currentItem = $(this),
    currentContents = currentItem.text(),
    contents = (currentItem.text().indexOf(«\n») != -1) ?
    list = $(«<ol>»),
    container = $(«<div>»).addClass(«snippet-container»).insertBefore(currentItem.prev());
                        
  //remove original contents and wrap in container
  currentItem.text(«»).prev().andSelf().appendTo(container);
                    
  //normalize height
  (currentItem.height() > 0) ?
                    
  //create list item
  $.each(contents, function(i, val) {
              
  //create list item and inner p
  var li = $(«<li>»).appendTo(list),
    p = $(«<p>»).text(val).appendTo(li);
  
    //add stripe class
    (i%2 === 0) ?
    });
            
    list.appendTo(currentItem);
  });
});

Давайте пройдемся по каждой части кода, чтобы увидеть, что он делает; сначала мы выбираем каждый элемент <pre>, который имеет имя класса фрагмента, и для каждого найденного мы выполняем анонимную функцию. В этой функции мы сначала устанавливаем пять переменных; первая переменная является селектором для текущего элемента <pre> , который мы кэшируем по соображениям производительности. В нашем коде мы будем неоднократно использовать ссылку $ (this), поэтому имеет смысл сохранить ее в переменной для быстрого доступа.

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

Большинство браузеров обнаруживают разрывы строк в JavaScript, используя символ новой строки \ n, поэтому сначала мы видим, содержит ли какой-либо из них внутренний текст элемента <pre>, а затем, если это так, используют их. IE обнаруживает разрывы строк не так, как в других браузерах, поэтому, если \ n символов не найдено, мы выполняем разделение, используя символ возврата каретки \ r .

Следующая переменная содержит новый элемент упорядоченного списка; использование элемента <ol> идеально, поскольку он автоматически обрабатывает нумерацию строк фрагмента кода. Последняя переменная указывает на новый контейнер <div>, которому мы присваиваем имя класса, а затем добавляем на страницу непосредственно перед элементом <h2>, который предшествует блоку фрагмента.

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

Firefox, кажется, вставляет разрыв строки в элемент <pre> , который дает высоту элемента, когда он вообще не должен иметь никакой высоты (так как мы удалили содержимое). Чтобы противостоять этому, мы определяем, имеет ли пустой элемент <pre> высоту больше 0 , и, если это так, мы устанавливаем поле margin-top нашего нового элемента <ol>, чтобы подтянуть его к вершине элемента. Это делает только Firefox, но лучше проверять высоту, чем проверять Firefox. Обнаружение функции через анализатор браузера выигрывает каждый раз.


Следующий раздел кода посвящен добавлению классов, которые мы можем использовать для эффекта чередования; так как мы поместили содержимое элемента <pre> в массив, а не объект jQuery, мы не можем использовать стандартный метод each, как мы это делали с элементами <pre> на странице.

Вместо этого мы можем использовать jQuery для каждого служебного метода, который вызывается непосредственно для объекта jQuery $ . Метод принимает 2 аргумента, первый — это объект для перебора, в нашем случае это массив содержимого , а второй — анонимная функция, выполняемая для каждого элемента в массиве. Наша функция автоматически передает два аргумента; i — индекс элемента, который в данный момент повторяется, а val — содержимое элемента массива.

В нашей функции мы сначала создаем новый элемент списка для нашего <ol> и вставляем новый элемент абзаца, содержащий содержимое текущего элемента массива. Новый элемент добавляется к элементу <ol>, который мы создали ранее. Затем мы добавляем классы чередования; для этого мы используем оператор модуля JavaScript, чтобы определить, является ли текущий индекс массива нечетным или четным; для каждого четного индекса мы добавляем полосу класса, а для каждого нечетного индекса мы добавляем класс небрежной . Использование 2 классов для чередования означает, что мы можем легко установить оба цвета чередования, вместо того чтобы настаивать на том, что один из них белый.

На этом этапе наша страница примера теперь должна выглядеть так:



Теперь мы можем добавить стили для виджета кода-фрагмента и чередования; в новом файле в вашем текстовом редакторе добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
.snippet-container {
  width:630px;
  background-color:#e1e1e1;
}
.snippet-container h2 {
  margin:0 0 10px;
  font-weight:normal;
}
.snippet { border:1px solid #999999;
.snippet ol {
  margin:0;
  font-weight:bold;
}
.snippet ol li { padding-left:10px;
.snippet ol p {
  margin:0;
  white-space:pre-wrap;
}
.snippet .stripe { background-color:#f5f5f5;
.snippet .unstripe { background-color:#ffffff;

Сохраните его как code-snippet.css в том же каталоге, что и страница примера. Большая часть этого CSS предназначена исключительно для оформления и была выбрана произвольно в соответствии с моими предпочтениями. Вы можете изменить любой из шрифтов, цветов, ширины или чего-либо еще. Самым важным функциональным CSS, который мы установили, является относительное расположение в каждом блоке фрагмента и правило пробела на внутренних элементах <p> в каждом элементе списка; если мы не установим этот параметр для предварительной переноски текста, то каждая строка будет переполнена контейнером фрагмента, если он слишком длинный, вместо того, чтобы переходить к следующей строке.

С добавлением нашей таблицы стилей окно фрагмента теперь выглядит так:



В этом примере до сих пор мы использовали очень простой CSS в качестве примера кода, показанного в поле фрагмента. Можем ли мы добавить любой другой тип кода, который мы хотим? Давайте взглянем. Сразу после первого элемента <pre> на странице добавьте следующий код: [/ sourcecode]

01
02
03
04
05
06
07
08
09
10
<pre>[sourcecode language=»snippet» originalClass=»snippet»]<!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.01//EN» «http://www.w3.org/TR/html4/strict.dtd»>
<html>
  <head>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″>
    <title>An Example Web Page</title>
  </head>
  <body>
    <p>This is a basic web page</p>
  <body>
<html>

Все в значительной степени то, что мы имели раньше, с одним существенным отличием мы не можем использовать символ < при отображении тегов HTML в нашем примере кода. Если бы мы поместили <html> в наш тег <pre> , он будет интерпретирован как элемент <html> и вызовет предупреждение HTML. Чтобы преодолеть это, мы можем указать сущность HTML

1
<

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


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


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

Непосредственно после строки кода, которая читает list.appendTo (currentItem); добавьте следующий код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//create tools
var toolContainer = $(«<div>»).addClass(«tools-container»),
  toolList = $(«<ul>»).addClass(«tool-list»).appendTo(toolContainer),
  listItem1 = $(«<li>»).addClass(«tool-item»).text(«|»).appendTo(toolList),
  listItem2 = $(«<li>»).addClass(«tool-item»).appendTo(toolList),
  plain = $(«<a>»).addClass(«tool»).attr({ id: «plain», href: «#», title: «Show code as plain text» }).text(«Show Plain»).prependTo(listItem1).click(function(e) {
  //stop event
  e.preventDefault();
                
    //create container for plain code
    if ($(this).closest(«.snippet-container»).find(«.snippet»).children(«.display-box»).length === 0) {
      var displayBox = $(«<div>»).addClass(«display-box»).height($(this).closest(«.snippet-container»).find(«.snippet»).height()).text(currentContents).appendTo(currentItem);
    }
                
    //show or hide the plain code
    $(this).closest(«.snippet-container»).find(«.snippet»).children(«.display-box»).slideToggle();
  
    //change text on the link
    ($(this).text() == «Show Plain») ?
  }),
  printBox = $(«<a>»).addClass(«tool»).attr({ id: «print», href: «#», title: «Print Code» }).text(«Print»).prependTo(listItem2).click(function(e) {
  //stop event
  e.preventDefault();
  
  //open new page to print from
  var title = currentItem.prev().text(),
    currentSnippet = $(this).closest(«.snippet-container»).find(«.snippet»),
    printWindow = window.open(«», «printWindow», «width=» + (currentSnippet.width() + 25) + «, height=» + (currentSnippet.height() + 50));
  
  printWindow.document.write(«<hr /><h2>» + title + «<\/h2><pre id=’code’><\/pre>»);
  $(«#code», printWindow.document).text(currentContents);
  printWindow.print();
});
            
toolContainer.appendTo(container);

Все, что мы делаем, это создаем целую кучу переменных, очень похожих на то, что мы делали в начале первого куска кода ранее; помните, что мы все еще находимся в контексте метода each (), который вызывается для всех элементов <pre> на странице. Сначала мы создаем контейнер для новых инструментов и присваиваем ему имя класса для стилизации, но не добавляем его прямо во фрагмент.

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


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

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

Затем мы используем эффект slideToggle () jQuery, чтобы показать или скрыть простой код в зависимости от того, виден ли он уже. Мы также меняем текст ссылки при каждом нажатии, что дает посетителю простой способ переключения между простым и красивым видом кода.

Следующая и последняя переменная, которую мы создаем, — это еще один элемент привязки, который будет использоваться в инструменте печати; к этому элементу также прикреплен обработчик событий, который будет выполняться при каждом нажатии. В обработчике событий мы начинаем с того, что снова создаем некоторые переменные, кэшируем текстовое содержимое элемента заголовка фрагмента кода и текущего элемента <pre> фрагмента кода.

Мы также создаем новое окно, используя традиционный метод JavaScript open () ; первый аргумент, который принимает этот метод — это URL открываемой страницы; у нас нет ранее существующей страницы, мы собираемся создать ее с нуля, поэтому мы устанавливаем этот аргумент в пустую строку. Второй аргумент — это имя нового окна, которое очень важно, поскольку мы обращаемся к нему несколько раз в одно мгновение. Наконец, мы устанавливаем размеры нового окна так, чтобы оно было немного больше, чем оригинальное поле кода.

После того, как окно создано, мы затем используем document.write в окне с адресом, которое мы дали ему, и пишем заголовок, содержащий содержимое элемента заголовка, который мы кэшировали, и пустой элемент pre, которому мы присваиваем идентификатор . Использование document.write кажется неправильным после использования jQuery, но, к сожалению, это единственный метод, который работает.

Когда в новом окне есть элемент <pre>, мы можем использовать jQuery, чтобы выбрать его, используя его идентификатор , предоставив ссылку на новое окно в качестве контекста селектора. Затем мы добавляем текстовое содержимое исходного элемента <pre>, который мы кэшировали еще в начале скрипта, и, наконец, вызываем метод print () JavaScript для печати нового окна.

JavaScript-метод print () очень простой, он просто распечатывает всю страницу; мы не можем сказать, чтобы он печатал только выбранные элементы, поэтому мы создаем новую страницу, содержащую только соответствующий заголовок и простой код, и печатаем ее вместо этого. Есть способы, которыми мы могли бы сделать это без создания новой страницы; мы могли бы добавить имя класса печати к каждому элементу на странице и использовать его, чтобы скрыть их с помощью CSS. На больших страницах с большим количеством элементов это было бы крайне неэффективно. Кроме того, мы не можем определить, когда печать закончилась, поэтому показ элементов снова после печати также будет проблематичным.

Теперь, когда все инструменты созданы, мы можем, наконец, добавить их на страницу, добавив их в каждый контейнер сниппета.


Новым инструментам также понадобится немного CSS, чтобы привести их в порядок и расположить; внизу code-snippet.css добавьте следующий новый код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
.tools-container { position:absolute;
.tool-list { margin:6px 0 0;
.tool-list li {
  list-style-type:none;
}
.tool-list li a {
  text-decoration:none;
  font-style:italic;
  outline:1px dotted #e1e1e1;
}
.tool-list li a:hover { text-decoration:underline;
.snippet .display-box {
  position:absolute;
  display:none;
}

Опять же, это в основном произвольные стили, которые, на мой взгляд, хорошо выглядят. Не стесняйтесь менять их, хотя я думаю, что нижняя часть поля кода — это хорошее место для них, и это то место, для которого мы намеренно оставили место, поэтому, если вы действительно хотите переместить их, вы можете настроить нижний отступ. контейнера сниппета. Новые инструменты должны выглядеть так:


При щелчке простой ссылки контейнер с простым кодом должен отображаться, и метка ссылки будет меняться:


Когда инструмент печати выбран, должно появиться новое окно с кодом и диалоговое окно печати:


Обратите внимание, что это довольно медленно в IE8 и немного темпераментно, иногда окно печати открывается, а иногда нет. Кроме того, поле для печати не отображается в Opera.


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

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