bz home

Язык разметки по-новому

Simple HTML Engine.

Оглавление

Зачем всё это нужно?

Попытаюсь ответить на этот вопрос.

Начав опыты сайтостроения (не промышленного, а домашне-страничного), я заметил, что просто создавать статический html и выкладывать на сайт — не самый удобный способ. Существует масса вещей, которые раздражают и мешают, затрудняя и замедляя процесс. Причём многое из этого — почти бесполезная трата сил и времени, что в свою очередь только усиливает раздражение. А некоторые вещи (например, выставление где нужно размеров картинок) просто не предназначены для человека — венца творения природы и прямо таки обязаны быть автоматизированы. Что в итоге оборачивается тем, что материал есть, а оформить и выложить его неохота, и сайт обновляется редко.

Вот каким образом я размышлял дальше.

Когда пишется содержательная часть документа для публикации в web, не очень-то удобно заморачиваться со всякими сужебными вещами типа расстановки абзацев, на каждой страничке писать заголовок, подвал и т.п. Хочется сконцентрироваться именно на содержимом, а всё остальное чтобы как-то само подставлялось. Это же опухнешь, каждый абзац отбивать <p> и </p>. Не то чтобы очень это сложно, но раздражает переключение раскладки клавиатуры, сама необходимость их вставлять, да и просто хочется набрать текст и сразу уже увидеть какой-никакой результат. Хочется проще. ПРОЩЕ! Именно в этом заключается успех такой технологии, как Wiki. Вот именно оттуда мы некоторые полезности и позаимствуем.

Ну и в самом деле, кто мешает придумать некоторые договорённости, которые позволят подставлять html-разметку на лету? Например, нет ничего проще, чем принять, что абзац отбивается сверху и снизу пустыми строками. Легко? Конечно. А также элементарно (кхе-кхе) реализуемо. Это — раз.

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

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

Хорошо, что ещё нужно? Теперь хочется, чтобы всякие служебные вещи вроде общего оформления, навигации, меню и т.п. тоже не отвлекали, а брались как-то сами, но поддавались гибкой настройке. Что же, давно придумана такая концепция, как шаблоны. Удобно? Берём, заверните.

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

Ещё одна побочная (но немаловажная) задача, которую я по ходу дела решал — написание всяческих README к своим программам. Если не нужна графика или другие экзотические вещи, то напрашивается их писать в обычном текстовом формате. При этом хотелось бы, чтобы для публикации в интернете оно само превращалось в html без лишних телодвижений. Вроде бы это тоже удалось.

В результате получилось Simple HTML Engine.

Вот некоторые свойства Simple HTML Engine:

Форматирование текста

Абзацы в тексте

Простой текст разбивается на абзацы с помощью пустых строчек. Просто оставить пустую строку сверху и снизу абзаца, весь блок текста будет аккуратно отбит тегами <p> и </p>. Как, например, этот. А также все прочие абзацы в этом тексте. Элементарно. И на редкость удобно.

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

Текст в
несколько
строк.

Другой
абзац.

Результат:

Текст в несколько строк.

Другой абзац.

Заголовки

Заголовки выделяются в тексте знаками "=" в начале и конце строки вот так: "==Заголовок==". Всё просто. Один знак равно — заголовок первого уровня. Два — второго. И так далее. Вот пример:

=заголовок 1-го уровня=
==заголовок 2-го уровня==
===заголовок 3-го уровня===

Результат:

заголовок 1-го уровня

заголовок 2-го уровня

заголовок 3-го уровня

Замечание: может сделать как раз наоборот, чем больше "=", тем крупнее заголовок?

Списки

Как бы нам представить списки? Когда список записывается в простом текстовом файле, обычно его выделяют звёздочками "*" в начале строки. Вот так и поступим.

Для нумерованных списков возьмём "#". Это вполне естественно (да и в Wiki также).

  1. нумерованный список (ol)
  2. из двух пунктов.

Смешанный список:

  1. номер

А как задавать вложенные списки второго, третьего и так далее уровней? Может отступами? Давайте так и поступим:

* item1
* item2
   * item21
   * item22
      * item221
          # item2211
  * item3
 * item4

Результат:

  • item1
  • item2
    • item21
    • item22
      • item221
        1. item2211
  • item3
  • item4

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

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

Таблицы

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

Явно указанные пробелы вокруг значения в ячейке указывают на то, в какую сторону оно должно быть отцентрировано. Чтобы ввести в ячейку символ "|", можно его заэкранировать с помощью "\" вот так: "\|". Чтобы превратить ячейку в заголовок (тег th), вводим первым символом в ячейке "^".

Примеры:

|^1|^2|^3|
|ячейка 1|ячейка 2|палочка \||
|  вправо| центр  |влево    |

Результат:

123
ячейка 1ячейка 2палочка |
вправо центр влево

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

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

[[table[[tr
	[[td:11]][[td:12]]
]][[tr
	[[td:21]][[td:22]]
]]]]

Результат:

1112
2122

Не сказать, что изящно, но в html-е будет выглядеть никак не лучше.

Замечание: не стоит ли сделать явное задание центрирования по-другому, например использовать "|>" для прижимания влево, а "|<" — вправо? Достоинство текущей реализации в том, что таблица в исходном тексте выглядит вполне похожей на таблицу по внешнему виду... С другой стороны заголовки всё равно выделяются специально. С третьей — можно эти заголовки и не выделять.

Прочие средства форматирования

Четыре и больше минуса "-" (или подчерка "_") подряд в строке дают горизонтальную линейку. Вот пример внизу:

Горизонтальная линия

Обработка тегов

Картинки

Будем задавать картинки в таком виде: [[img:just_image.gif]]. Почему так? Во-первых, это довольно компактно и однозначно. А во-вторых, если почитать секцию продвинутых средств форматирования, то всё сразу встанет на свои места в стройной концепции понимания окружающего мира.

Тем не менее, вот пример [[img:just_image.gif]]:

just_image.gif

(На рамочки, если они видны, внимания не обращаем — это работают каскадные стили.)

Теперь слегка дополним эту конструкцию для удобства использования. Во-первых, чтобы можно было задавать сразу несколько картинок сразу, просто перечислив их через запятую вот так [[img:just_image.gif,just_image2.gif]]:

just_image.gifjust_image2.gif

...и чтобы можно было указывать подписи под картинками [[img:just_image.gif;Длинная предлинная, очень длинная Подпись к картинке]]:

just_image.gif
Длинная предлинная, очень длинная Подпись к картинке

И, наконец, всё вместе [[img:just_image.gif,just_image2.gif;А тут сразу две картинки с одной подписью]]:

just_image.gifjust_image2.gif
А тут сразу две картинки с одной подписью

Особенности представления картинок следующие. Если картинка одна и подписи нету, то создаётся просто элемент <img>, если есть подпись или указано несколько файлов, то все картинки это вместе с подписью оборачивается в <div class='img'>. Зачем это нужно? Просто чтобы картинки и подпись были вместе. При этом явно указанные атрибуты добавляются в div, если он есть, а если нету, то в img. Класс с именем img соответственно позволит задать такое представление, какое нужно.

И завершающий штрих. Если рядом с текстом, который мы пишем присутствует каталог img, в котором лежит картинка с точно таким же именем, что мы вставляем, то исходная картинка будет ссылкой на эту в каталоге img. Для чего? Для того, чтобы можно было, например, посмотреть картинку в более высоком разрешении. Я обычно так и организую свои файлы. Лично мне удобно. А если кому не нравится, то просто не создавайте каталог img или не кладите в него соответствующие файлы картинок.

Вопрос: Как делить атрибуты картинок между "div" и "img"? И нужно ли?

Ссылки

Для ссылок будем использовать следующую конструкцию: [[a:sample.html;ссылка]], что должно превратиться в: ссылка.

Почему так? Во-первых это довольно компактно и удобно, во-вторых, это единообразно с элементами <img>. А в-третьих — см. те же соображения, что и для картинок по поводу продвинутых техник форматирования.

Другие теги

Предформатированный текст задаётся тегом [[pre]]:

Пред
    формати
           рованный

     текст
=

Просто теги div и span:

текст внутри div может содержать вложенные теги

Тут ссылка с вложенным форматировнным жирным шрифтом и курсивом текстом.

Пустой тег ([[]]) экранирует обработку тегов. Может оказаться полезным.

Некоторые дополнительные полезности

Первая строчка в файле считается заголовком страницы и попадает в <title>. Для прочего доступа к заголовку страницы следует использовать метаинформацию.

Если рядом с исходным текстом есть файл style.css, то движок автоматически подключит его как стиль. Так что если понадобится какое-либо форматирование с помощью CSS — на здоровье. При этом форматирование хорошо отделено от содержательной части. Что есть плюс.

Аналогично для файла icon.ico. Создавайте себе иконки сайта и кладите рядом. Подхватятся автоматически.

Если в конце строки последним символом стоит "\", то к ней подклеивается следующая строчка (как в юниксах).

Не забывайте, что параграф не будет выделен в элемент p, если он начинается с тега. По идее он не должен начинаться с тега, который описывает блок, но определить это на этапе работы движка не представляется возможным, так как каскадные стили или скрипты могут переопределить свойство display элемента, да и не хочется заниматься этим разбором — слишком сложно. Workaround следующий: если уж угораздило в начале абзаца использовать какой-то тег, то чего уж останавливаться — можно и сам абзац тегом p выделить. Автору виднее, что там такое должно быть. Сделано это специально, так как приносит больше пользы чем вреда (так ли это?).

Некоторые полезные замены на лету.

Будем заменять конструкцию "пробел + двойной минус + пробел" на "&nbsp;&mdash;пробел" — для того, чтобы по-человечески можно было записывать тире в тексте. А "открывающую скобку + латинскую 'c' + закрывающую скобку" сами понимаете на что.

Аналогично, последовательности [<[ и ]>] заменяются на [[ и ]]. Зачем? Просто чтобы можно было показать на странице "[[" или "]]". Всё равно знаки < и > нужно заменять на &lt; и &gt;, иначе броузерам башню сносит. А если уж так нужно показать "[<[", то всё равно придётся писать "[&lt;[".

Двумя косыми палочками (/) будем выделять курсив (только в одной строке, без переносов на новую строку), а двумя звёздочками (*) — жирный текст. Вот пример курсива и жирного шрифта. Вложенность тоже возможна, заботьтесь сами о правильной вложенности. Аналогично подчерки (_) соответствуют подчёркиванию, а тильды (~) — перечёркиванию. Если хочется сделать выделение многострочным — на выбор: или использовать соответствующий тег явно, или в конце строки добавить обратный слеш, склеив этим самым строки. А эти конструкции задуманы для быстрого выделения одного-двух слов.

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

Как пример использования pre_replace, можно продемонстрировать такое: пусть у нас страница перегружена картинками и прямо таки просится упростить показ новых картинок. Тогда можно сделать такую замену: "/[(.*)\.jpg]/" => "[[img:$1.jpg]]", после чего констукции вида [file.jpg] будут автоматически преобразовввываться в [[img:file.jpg]]. Так как подстановка будет сделана до какой либо обработки, то стандартный механизм разбора тегов сделает всю последующую работу сам. Остальные примеры можно посмотреть в файле конфигурации движка.

Маленькие хитрости со стилями. Если определить стили вот так:

.left {float:left}
.right {float:right}

то дальше можно будет использовать их следующим образом в img, div и прочих тегах:

just_image.gif
картинка справа
[[img(right):just_image.gif;картинка справа]] даст картинку справа. Тут-то и пригождается факт, что все классы перечисляются через пробел, соответственно все они работают независимо.

Для задания стилей различных стандартных элементов форматирования (абзацев, заголовков, списков...) удобно пользоваться следующим приёмом. Заключить элемент, который требует специального форматирования в соответствующий div с указанием имени класса и добавить в CSS стиль с таким классом и соответствующим элементом. Пример:

стиль:
.wide table { width: 100%; }

документ:
...
[[div(wide)

|широкая|таблица|

]]
...

результат:
широкаятаблица

Интересно, что тег [[!--:]] даёт пусть и не совсем правильный, но вполне работающий XML-коментарий, см. исходный код. (:

Пример коментария

Продвинутая техника

Продвинутая техника тегов

Теги в тексте задаются с помощью квадратных скобок: [[тег]]. Так их можно легко выделить из общего контекста. На теги можно повесить исполнение собственного кода (механизм плагинов, собственно все текущие действия в плагинах и реализованы). Если плагинов для тега нет, то он по простым и понятным правилам преобразуется в html-ный <тег>. Примером такого могут служить уже упоминавшиеся выше теги div и span.

Теперь вкусности для тех, кто дочитал аж до сюда. Продвинутая техника форматирования задаётся с помощью тегов следующего вида:

**[[tag(**[attribute=]value,attribute=...):optional params;text**]]**

при этом tag(attribute=value,attribute=...):optional params должно быть на одной и той же строчке, а text может быть многострочным. Также (attribute=value,attribute=...) и optional params могут отсутствовать. И преобразуется данная конструкция в следующее:

<tag attribute='value' attribute='...'>text</tag>

Атрибутов может быть много, задаются через запятую. Если имя атрибута (до знака "=") не задано, то считается, что это атрибут class. При этом, если значений атрибута несколько, то они будут разделены пробелом (это важно для CSS)!

А optional params используется в тегах:

  • a для задания href='...'
  • img для задания src='...'
  • нужно ли где-нибудь ещё?

Более сложный пример: [[div(menu,top,onclick=func();):text]] будет преобразовано в <div class='menu top' onclick='func();'>text</div>.

Таблица соответствия (в html-коде страницы в xml-комментариях можно увидеть реальные результаты преобразования):

Исходный кодРезультат
[[tag]] <tag />
[[tag(value)]] <tag class='value' />
[[tag(value1,attr1=value2,attr2=value3)]] <tag attr1='value2' attr2='value3' class='value1' />
[[tag:text]] <tag>text</tag>
[[tag(value):text]] <tag class='value'>text</tag>
[[tag(value1,attr1=value2,attr2=value3):text]] <tag attr1='value2' attr2='value3' class='value1'>text</tag>
[[tag(value1,valueX,attr1=value2,class=value3):text]] <tag attr1='value2' class='value1 valueX value3'>text</tag>

Более формальный синтаксис:

**[[** tag [attribute list] [: content] **]]**
attribute list ::= { attribute , } attribute
attribute ::= [ name = ] value
content ::= [ optional parameters ; ] text

Почему теги, атрибуты и параметры должны быть в одной строке. Это ограничение накладывается из-за того, что движок читает файл построчно и построчно же обрабатывает и отдаёт. Чтение файла целиком в память может оказаться накладным, если файлы будут очень большими, и необоснованным. Можно конечно подчитывать по мере надобности дополнительные строчки, но пока вроде не нужно было.

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

Зачем это нужно так сложно, чем обычные html-теги не устраивают?

  • так компактнее, чем в html, потому что отсутствуют закрывающие теги. Любой закрывающий тег в html будет длиннее трёх символов, а тут всего два
  • это позволяет использовать возможности редакторов по нахождению соответствия между открывающими и закрывающими скобками, что бывает весьма удобно
  • соответствие открывающих и закрывающих тегов поддерживается автоматически. Теперь невозможно, например, забыть поставить слэш в закрывающем теге </ > (привет расплывшимся таблицам).

При этом никто (повторяю — никто!) не мешает испольовать классические html-теги для констукций, которые не удаётся записать с помощью вышеозначенного или по любой другой причине. Движок их просто пропустит как есть. Пример:

Прямое использование тегов тоже не возбраняется.

Примеры использования продвинутой техники тегов

Посмотрим, что в результате получилось. Что ещё можно сделать и как использовать.

Что у нас есть ещё? Формы? Попробуем:

[[form(action=...)

Input:
[[input(name=field1)]]

List:
[[select(size=3)
	[[option:item1]]
	[[option:item2]]
	[[option:item3]]
	[[option:item4]]
]]

Drop Down List:
[[select
	[[option:item1]]
	[[option:item2]]
	[[option(selected=selected):item3]]
	[[option:item4]]
]]

Textarea:
[[textarea(rows=3,cols=20):this is text in text area input]]

Button:
[[input(type=submit,value=Ok)]]
]]

Результат:

Input:

List:

Drop Down List:

Textarea:

Button:

Не сказать, чтобы супер, но, пожалуй, что-то в этом есть. Списки хорошо получились, удобно записывать. А можно сделать плагинчик, который для select разрисует соответствующие ему option.

Плагины

Начиная с версии 0.0.5 появился механизм плагинов. Что это такое и как оно работает. На самом деле движок, считывая очередной тег, смотрит, не определён ли у нас плагин с таким именем? Если определён, то он и вызывается. Если нет, то тег записывается в html-ной форме, это вроде бы как действие по-умолчанию. На самом деле поддержка тегов a, img и pre была вынесена в подключаемые модули, как только такая возможность появилась.

Как этоn плагин выглядит. Это код на PHP с тремя функциями: для открытия тэга, для закрытия тэга и тот случай, когда тег пустой, т.е. не содержит внутри ничего. Вызываются эти функции в соответствующие моменты времени (см. примеры в исходниках — там всё элементарно). Увы, обрабатывать в плагине весь текст, который попал между открытием тега и его закрытием, целиком не получится, кроме как если этот текст идёт в одной строчке и не содержит других тегов.

Вот пример работы тестового плагина, который просто выводит переданные ему при вызове параметры:

[[testplugin(class1,attr=value):a,b,c;split
multiline
text]]

Преобразуется в:

a,b,c;split multiline text

Пример плагина formula (не TeX конечно, но...):

[[formula:\int_0^{&infin;} e^{x_i^2}dx + \sum_{i=0}^10 y_i^2]]
[[formula:E=mc^2]]
0 exi2dx + Σi=010 yi2 (1)
E=mc2 (2)

Formula list:

[[formula(list)]]
[1][2]

Пример плагина для неалфавитных символов (причём оба в одном файле):

E=mc[[^:2]]
H[[_:2]]O

E=mc2 H2O

Есть ещё крайне полезный плагин //[[include(file)]]//, который должен быть обязательно подключен, если мы хотим использовать шаблоны для страниц. Поведение его вполне естественно: вставка в документ содержимого из файла. Может быть вложенным.

Стоит ли тут расписывать про технические детали реализации? Вроде не надо, достаточно один раз заглянуть в код и всё будет и так понятно.

Стандартные плагины

Шаблоны

Шаблоны — это элементарно. Сердцем шаблонов является плагин //[[include]]//.

Задаём в настройках движка соответствующий параметр, ссылающийся на файл шаблона (может быть как с абсолютным, так и с относительным путём), и готовим соответствующий шаблон. Если шаблон задан и файл такой существуюет, то движок начинает обработку с этого шаблона, включая все описанные тут возможности. В том месте, куда нужно включить содержимое запрошенного файла, должен стоять вызов плагина //[[include]]// без параметров. Вот собственно и всё, что нужно.

Конечно же никто не мешает вставить в шаблон что-то типа [[include(submenu.ext)]] и тогда при наличии файла submenu.ext, его содержимое попадёт на страницу. А если такой файл отсутствует, то соответственно не попадёт.

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

Даже и не знаю, что ещё можно добавить про шаблоны.

Ну вот пример простого шаблона:

[[div(header):заголовок]]

<!-- navigation -->
[[div(navigation):[[navpath]]]]
[[div(menu):[[menu]]]]
<!-- /navigation -->

[[div(content)
<!-- main content -->
[[include]]
<!-- /main content -->
]]

[[div(footer):(c) копирайты]]

Метаинформация

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

Обработка идёт в следующем порядке:

  1. Параметры устанавливаются в файле конфигурации движка.
  2. Загружается метаинформация для каталога, в котором расположена отображаемая страница.
  3. Загружается метаинформация отображаемой страницы.

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

Как задаётся метаинформация.

Метаинформация на уровне файла задаётся следующим образом. Первой строкой всегда является заголовок файла (элемент title из заголовка). Дальше могут идти сколько угодно (в том числе и отсутствовать) строк вида "name=value". Первая же пустая строка говорит о том, что метаинформация закончилась.

Пара "name=value" понимается как имя параметра (до знака "=") и значение. Например, для задания другого шаблона можно задать "template=other.tmpl".

Можно вместо знака "=" использовать "+=" для добавления указанного значения к существующему в конец и "-=" для вставки в начало. В значениях "\n" заменяется на символ возврата каретки (полезно, если хочется установить многострочное значение).

Строка, начинающаяся с "#" считается коментарием.

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

This is page title
# some metainformation for this page
template=other.tmpl
css=special.css
# append this line in html head
head+=\n<link rel='stylesheet' type='text/css' href='my_style.css' />
# append other line in front of previous value
head-=\n<link rel='stylesheet' type='text/css' href='other.css' />
# change img borders to 5px
plugin.img.border=5

here is page text beginning...
...

Метаинформация для директорий задаётся точно также в файле !dirinfo (при желании можно изменить в настройках движка). При этом первой строкой в этом файле идёт также название (в данном случае раздела).

Некоторые полезные параметры:

  • template задаёт шаблон
  • css устанавливает каскадные стили
  • codepage задаёт кодировку
  • head значение добавляется в автоматически сгенерированную секцию <head>

Остальное — в коментариях файла настройки движка.

Установка и конфигурирование

Установка Simple HTML Engine довольно простая.

  1. Развернуть движок в какой-либо каталог на сервере (например, /engine/).
  2. Отредактировать config.php, задать параметры, поправить пути, прописать шаблон и каскадные стили по-умолчанию.
  3. Отредактировать шаблон и CSS под свои нужды. Это творческий процесс.
  4. Добавить обработчик в .htaccess или httpd.conf сервера аналогично прилагаемому .htaccess, рекомендуемое (но совсем не обязательное) расширение для файлов .shtm.
  5. Создать структуру директорий, заполнить для них метаинформацию, разложить файлы. NB: для отдельных разделов (директорий) никто не мешает создавать свои шаблоны!

и всё!

Крайне не рекомендуется отключать плагины include, a, img, pre, navpath, menu, files. В частности с отключенным include перестанут работать шаблоны, а без a, img и pre просто неудобно.

Ту Ду и прочие соображения

Открытые вопросы:

  • стоит ли поменять [[ и ]] на << и >>? Первые более привычны для Wiki, вторые не должны встречаться в html-е, то есть точно никому не помешают. В то же время [[ и ]] весьма экзотическая комбинация, встречается в реальных текстах куда как реже. Или может взять {{ и }}?
  • стоит ли поменять ":" на "|" в синтаксисе? Может ли реально встретиться двоеточие в списке атрибутов? Кажется может. style. Пока можно обходиться html-разметкой. И вообще не стоит лишний раз явно указывать стили, так что пока пусть будет как есть.
  • нужно ли отключать автоматическую расстановку тегов h, p, ol, ul внутри [[ и ]]? Предусмотреть специальное экранирование? Как? Может директивами движка (см. ниже) типа [[engine(markup=on/off]]?
  • не стоит ли делать передачу параметров движку с помощью специального тега, например, [[engine(parameter=value)]]?
  • как хранить метаинформацию для каталогов, файлов: права доступа и так далее?
  • стоит ли отказаться от построчной обработки файла? про: более мощные плагины; контра: расходы памяти на хранение текста во время обработки.
  • в каком порядке делать обработку: сначала плагины, потом отбивка абзацев, списков и т.п. или наоборот?

Почему [[ и ]]? Эта комбинация уже используется в Wiki и весьма экзотична в текстах (потому видать и была взята) и позволяет использовать такие скобки сами по себе, а не отлавливая индивидуально теги по комбинации, например, [tag: ... ]. Что позволило использовать такие скобки для задания любых тегов.

О текущих ограничениях. Сейчас идёт построчная обработка входного файла. Это несомненно хорошо в том смысле, что файл не грузится в память целиком. Ведь он может быть изрядно большой. Но это ведёт к некоторым ограничениям. Например, механизм плагинов не позоляет обработать весь текст, заключённый в теге. Только до конца строки или до начала следующего тега. Частично проблема снята использованием обратного слеша в конце строки — при этом происходит склейка строк, как это делается в юниксе... Пока хватает. Стоит ли делать механизм плагинов мощнее — пока в процессе обдумывания.

Куда двигаться дальше? Ну в целом направление понятно. Сделать аутентификацию (скажем, на куках) и систему раздачи прав (просмотр, редактирование, что ещё?). Тогда тут же можно сделать редактирование в on-line. Дальше можно будет написать небольшое междумордие для администрирования: создание новых каталогов, удаление, переименование и т.п. После появления аутентификации можно также без особого труда добавить возможность вставлять ленты коментариев (плагином). Можно ещё наделать интересных и полезных плагинов — например, для новостных лент.

В заключение, вот исходный текст этой страницы, можно сравнить с тем, что получилось в броузере. Это-то и интересно в первую очередь. И очень поучительно. Собственно на этом примере и отлаживался сам движок. Что, с этого и надо было начинать? А кто бы иначе дочитал до конца?

Конечно эта страничка специально перегружена чем ни попадя, а простой текст не будет содержать всех этих наворотов и будет движком представлен в виде простого же html, чего собственно и добивались большевики. Вот этот раздел как раз даёт хорошее представление о том, как должен выглядеть обычно текст для публикации — никакой лишней разметки. Ведь нужна в 99% случаев разбивка на абзацы, элементарные списки, возможность вставлять картинки и ссылки. Вот для таких случаев этот движок и подходит лучше всего. А для сложной вёрстки Оккам не велел.

Принципы построения:

  • файловая система — отличная база данных, не без своих особенностей (а внешняя база данных, если она не нужна, — это лишний геморрой)
  • лучшая навигация по сайту — это дерево каталогов его файловой системы
  • лучший способ упростить процесс публикации — выкинуть из него всё лишнее. А именно:
    • рутину отбивки стандартных элементов в html (абзацы, списки, простые таблицы)
    • сделать автоматическое добавление всего служебного сайтозависимого (стандартное оформление, стили, навигация)
  • неплохо бы иметь возможность автоматизировать нестандартные действия
  • нельзя объять необъятное: не стоит делать монстра, который будет уметь всё, лучше сделать необходимо достаточный минимум, оставив возможность докручивать недостающее руками.
  • KISS
    • ничего лишнего буть не должно, лишнее — это то, без чего можно обойтись
    • решение должно быть изящным

Дальнейшие пути развития:

  • переписать логику работы движка для более полного и мощного механизма плагинов (сразу после нахождения пути увязки такого механизма с форматированием на лету)
  • авторизация пользователей (как и зачем? есть идеологические непонятки)
  • интерактивность: рейтинги, ленты коментариев, голосования (возможно и без авторизации)
  • CMS (Content Management System) для всего этого. Собственно нужна только авторизация и понять, как это должно выглядеть. Пока работает на уровне файлового доступа к серверу.

История версий

0.0.8 23/05/2007

  • Обработка !header.html и !footer.html заменена на механизм шаблонов (template). Соответствующим образом доработан плагин include. Надо бы ещё побеспокоиться о невозможности рекурсивного включения...
  • Глобальные стили css для полноты шаблонов.
  • Метаинформация для каталогов и файлов.
  • Дописаны плагины navpath, menu и files для автоматического построения навигации по сайту.
  • Обновлена документация.

0.0.7 22/04/2007

  • Если существуют файлы !header.html и !footer.html, то содержимое их подклеивается в начало и конец страницы соответственно (полезно для единообразия заголовков и подвалов в каталоге).
  • 21.03.2007 Сделан плагин [[include(file_to_include)]] с очевидным поведением.
  • 07.04.2007 Прототип авторизации по кукам (будет переделываться по мере надобности в идеологичеки более правильный).
  • 07.04.2007 На основе слепленной на скорую руку авторизации сделан плагин [[comments]] для лент коментариев. Прикольно получилось, работает сносно.
  • 19.04.2007 Немножко более умные таблицы: выделяются заголовки по "^" в начале ячейки, экранирование палочки с помощью "\|".

0.0.5 02/02/2007

  • Заголовки теперь нужно выделять с помощью знаков "=" справа и слева: "==заголовок==" вместо восклицательных знаков.
  • Списки теперь могут быть многоуровневыми, уровень вложенности определяется отступом слева
  • Поддержка плагинов. В частности специальная обработка тегов [[img]] и [[a]] вынесена в плагины. Теперь на любой тег можно зарегистрировать свой обработчик. Планируется сделать несколько тегов-плагинов для автоматизации навигации по сайту
  • Поддержка (очень) простых таблиц вида "|а|б|в|"
  • Тег [[pre]] тоже вынесен в плагины, добавлено экранирование разметки абзацев, списков, таблиц внутри [[pre]]
  • Подчистки кода, оптимизация
  • Соответствующим образом подправлена документация
  • Раздумья на тему превращения этого в полноценный движок сайта: авторизация, CMS, навигация, как это должно настраиваться и т.п. Пора, пора...

0.0.4 08/01/2007

  • Заработали как полагается атрибуты, включая атрибуты [[img]]
  • Заработали пустые элементы (теги вида [[tag]] преобразуются в <tag />)
  • Экранирование с помощью пустого тега [[ ]]
  • Запустив с ?donotprocess можно получить исходный код страницы
  • Теперь если в первой строке идёт тег [[head, то именно он будет описывать заголовок страницы; в противном случае первая строка считается заголовком страницы (html/head/title) и заголовок формируется автоматически. Это нужно для того, чтобы дать возможность сформировать свой хитрый заголовок страницы самому.
  • img теперь содержит атрибут alt с именем самого файла, это нужно для успешной валидации страниц (тег alt является обязательным в xhtml)

0.0.3 06/01/2007

Первая работоспособная версия текущего дизайна. Сделана выделение абзацев и списков, интегрирована поддержка тегов вида [[tag...]]. В общем вот это самое — то что тут и представлено — впервые заработало.

0.0.2

Доисторическая эпоха, использовалось в основном как помощник для формирования html-кода картинок (не самому же все эти width и height вычислять) и прочих специфических нужд типа автоматической генерации единообразных блоков на странице. Предыдущая история канула в Лету.

Simple HTML engine (c) 2005-2007, bz