Инструменты пользователя

Инструменты сайта


wiki:devel:syntax_plugins

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Следующая версия
Предыдущая версия
wiki:devel:syntax_plugins [2025/01/09 13:32] – создано vladpolskiywiki:devel:syntax_plugins [2025/01/09 22:44] (текущий) – [Написание своего собственного плагина] vladpolskiy
Строка 1: Строка 1:
 ====== Синтаксические плагины ====== ====== Синтаксические плагины ======
-[[plugintype>1#extension__table|Syntax Plugins]] are [[:devel:plugins]] to extend DokuWiki's [[wiki:syntax]]. To be able to understand what is needed to register new Syntax within DokuWiki you should read [[parser | how the Parser works]]. 
  
-===== Synopsis =====+Синтаксические плагины --- это плагины расширения синтаксиса «[[wiki:dokuwiki|ДокуВики]]». Чтобы понять, что необходимо для регистрации нового синтаксиса в «ДокуВики», вы должны прочитать, как работает [[parser|парсер]].
  
-A Syntax Plugin //Example// needs: +===== Краткий обзор =====
-  * class name  ''syntax_plugin_example'' +
-  * which extends [[xref>SyntaxPlugin]]((defined in ''lib/Extension/SyntaxPlugin.php'', before called ''DokuWiki_Syntax_Plugin'' which is still available as alias)).  +
-  * to be stored in a file ''lib/plugins/example/syntax.php''+
-Moreover, a [[plugin_info|plugin.info.txt]] file is needed. For full details of plugins and their files and how to create more syntax components refer to [[plugin file structure]].+
  
-The class needs to implement at least the following functions: +Для синтаксического плагина //example// требуется объявить имя класса как ''syntax_plugin_<example>'', который расширяет класс ''DokuWiki_Syntax_Plugin'', определённый в файле ''lib/plugins/syntax.php''. Класс необходимо сохранить в файле с названием ''lib/plugins/example/syntax.php''. Для более подробной информации можно обратиться к статье о [[plugin file structure|структуре файлов плагина]].
  
-  * **''getType()''** Should return the type of syntax this plugin defines ([[#syntax_types|see below]]) +Класс должен содержать как минимум следующие функции:
-  * **''getSort()''** Returns a number used to determine in which order modes are added, also see [[parser#order_of_adding_modes_important|parser, order of adding modes]] and [[devel:parser:getSort list]]. +
-  * **''connectTo($mode)''** This function is inherited from dokuwiki\Parsing\ParserMode\AbstractMode ((defined in ''inc/Parsing/ParserMode/AbstractMode.php'', inherited via dokuwiki\Parsing\ParserMode\Plugin)). Here is the place to register the regular expressions needed to match your syntax. +
-  * **''handle($match, $state, $pos, Doku_Handler $handler)''** to prepare the matched syntax for use in the renderer +
-  * **''render($format, Doku_Renderer $renderer, $data)''** to render the content +
-\\ +
  
-The following additional methods can be overridden when required:+  * <del>''getInfo()'' --- возвращает хэш с информацией о плагинеавтор, электропочта, дата, название, описание, ссылки.</del>\\ **Теперь вместо неё прилагается отдельный файл plugin.info.txt** 
 +  * ''getType()'' --- должен возвращать тип синтаксиса (см. [[#синтаксические типы|ниже]]). 
 +  * ''getSort()'' --- возвращает число, по которому определяется, в каком порядке должны добавляться состояния, см. также  [[wiki:devel:parser#order_of_adding_modes_important|parser, order of adding modes]] и [[wiki:devel:parser:getSort list]]. 
 +  * ''connectTo($mode)'' --- эта функция наследуется от класса Doku_Parser_Mode, определённого в ''inc/parser/parser.php''. Это место, где регистрируется регулярные выражения, необходимые для опознания вашего синтаксиса. 
 +  * ''handle($match, $state, $pos, Doku_Handler $handler)'' --- функция для подготовки совпавшего синтаксиса для использования рендером. 
 +  * ''render($mode, Doku_Renderer $renderer, $data)'' --- функция для отображения контента. 
 +\\ 
  
-  * **''getPType()''** Defines how this syntax is handled regarding paragraphs((See ''Doku_Handler_Block'')). Return: +Следующие дополнительные методы могут быть переопределены при необходимости:
-    * ''normal'' --- (default value, will be used if the method is not overridden) The plugin output will be inside a paragraph (or another block element), no paragraphs will be inside +
-    * ''block'' --- Open paragraphs will be closed before plugin output, the plugin output will not start with a paragraph +
-    * ''stack'' --- Open paragraphs will be closed before plugin output, the plugin output wraps other paragraphs +
-  * **''getAllowedTypes()''** (default value: ''array()'') Should return an array of [[#syntax_types|mode types]] that may be nested within the plugin's own markup. +
-  * **''accepts($mode)''** This function is used to tell the parser if the plugin accepts syntax mode $mode within its own markup. The default behaviour is to test $mode against the array of modes held by the inherited property ''allowedModes''. This array is also filled with modes from the mode types given in ''getAllowedTypes()''.+
  
-Additional functions can be defined as needed+  * ''getPType()'' --- определяет, как данный синтаксис размещается относительно параграфов((См. Doku_Handler_Block)). Возвращает: 
 +    *  ''normal'' --- (значение по умолчанию, используется, если метод не переопределяется) Плагин может использоваться внутри параграфов, 
 +    * ''block'' --- Открытые параграфы должны быть закрыты до вывода плагина или  
 +    * ''stack'' --- Специальный случай. Плагин обёртывает другие параграфы 
 +  * ''getAllowedTypes()'' (значение по умолчанию: ''array()'') Должен вернуть массив [[#синтаксические типы|типов состояний]], которые могут быть включены в собственную разметку плагина. 
 +  * ''accepts($mode)'' --- Эта функция говорит парсеру, допускает ли плагин синтаксическое состояние $mode в своей разметке. Поведение по умолчанию заключается в проверке наличия $mode в массиве состояний, хранящемся в унаследованном свойстве ''allowedModes''
  
 +При необходимости могут быть определены дополнительные функции. Рекомендуется добавлять впереди символ подчерка к названиям самостоятельно определённых функций для того, чтобы избежать возможных пересечений имён при дальнейшем развитии спецификации плагинов.   
 \\  \\ 
-Inherited Properties 
  
-  * **''allowedModes''** --- initial value, an empty array, inherited from AbstractMode ((defined in ''inc/Parsing/ParserMode/AbstractMode.php'')). Contains a list of other syntax modes which are allowed to occur within the plugin's own syntax mode (ie. the modes which belong to any other DokuWiki markup that can be nested inside the plugin's own markup).  Normally, it is automatically populated by the ''accepts()'' function using the results of ''getAllowedTypes()''.+Унаследованные свойства
  
-Inherited Functions+  * ''allowedModes'' --- начальное значение: пустой массив, унаследованный от  класса ''Doku_Parser_Mode'', определённого в ''inc/parser/parser.php''. Содержит список других синтаксических состояний, появление которых допустимо внутри собственного синтаксического состояния плагина (т. е. состояния, которые относятся к любым другим элементам разметки «ДокуВики», которые могут быть включены внутрь собственной разметки плагина). Обычно он автоматически заполняется функцией ''accepts()'', используя результаты ''getAllowedTypes()''.
  
-  * See [[common plugin functions]] for inherited functions available to all plugins. e.g. localisation, configuration and introspection.+===== Синтаксические типы =====
  
-===== Syntax Types =====+«ДокуВики» использует различные синтаксические типы для того, чтобы определить, какие синтаксические конструкции могут быть вставлены внутрь другой. Например, вы можете вставить текстовое форматирование внутрь таблицы. 
  
-DokuWiki uses different syntax types to determine which syntax may be nestedEg. you can have text formatting inside of tables. To integrate your plugin into this system it needs to specify which type it is and which types can be nested within it. The following types are currently available:+Для того, чтобы интегрировать свой плагин в эту систему, нужно указать, какой тип он имеет и какие типы могут вставляться в негоВ настоящий момент доступны следующие типы
  
-Modetype                                                                                                                                                                                Used in mode...                                                                                                                                                                                                        Description                                                                                                                                                  +Тип  Используется в...   Описание  
-| container                                                                                                                                                                               | listblock, table, quote, hr                                                                                                                                                                                            containers are complex modes that can contain many other modes -- hr breaks the principle but they shouldn't be used in tables / lists so they are put here  +| container | listblock, table, quote, hr | Контейнеры --- это сложные состояния, которые могут содержать много других состояний, но они не должны использоваться в таблицах и списках (состояние ''hr'' нарушает общий принцип), поэтому они отнесены к этому типу. 
-| baseonly                                                                                                                                                                                | header                                                                                                                                                                                                                 some modes are allowed inside the base mode only                                                                                                             +| baseonly | header | Некоторые состояния допустимы только внутри базового состояния. 
-| formatting                                                                                                                                                                              | strong, emphasis, underline, monospace, subscript, superscript, deleted, footnote                                                                                                                                      modes for styling text -- footnote behaves similar to styling                                                                                                +| formatting | strong, emphasis, underline, monospace, subscript, superscript, deleted, footnote | Состояния для изменения стиля текста (сноски (footnote) также можно рассматривать как стиль). 
-| substition((Yes this is spelled wrongbut we won't change it to avoid breaking existing pluginsSometimes a typo becomes a standard see the HTTP "referer" header for an example))  'acronym''smiley''wordblock''entity''camelcaselink''internallink''media''externallink''linebreak''emaillink''windowssharelink''filelink''notoc''nocache''multiplyentity''quotes''rss'  modes where the token is simply replaced -- they can not contain any other modes                                                                             +| substition((Даэто неправильное написание, но мы не хотели бы его менять, чтобы избежать нарушения существующих плагиновИногда опечатки становятся стандартами, возьмите к примеру HTTP-заголовок «referer»)) | acronym, smiley, wordblock, entity, camelcaselink, internallink, media, externallink, linebreak, emaillink, windowssharelink, filelink, notoc, nocache, multiplyentity, quotes, rss | Состояния, в которых токен просто меняется на что-то; не могут содержать в себе другие состояния. |  
-| protected                                                                                                                                                                               'preformatted''code''file''php''html                                                                                                                                                                         modes which have a start and end token but inside which no other modes should be applied                                                                     +| protected | preformatted, code, file, php, html |Состояния, имеющие начальный и конечный токены, но внутри которых не допустимы никакие другие состояния. 
-| disabled                                                                                                                                                                                | unformatted                                                                                                                                                                                                            inside this mode no wiki markup should be applied but lineendings and whitespace isn't preserved                                                             +| disabled | unformatted | Внутри этого состояния вики-разметка не отрабатывается, переносы строки и пробелы не сохраняются. 
-| paragraphs                                                                                                                                                                              | eol((This is actually a class, it does not mean "end of life", but "end of line".))                                                                                                                                    | used to mark paragraph boundaries                                                                                                                            |+| paragraphs | eol | Используется для отметки границ параграфов. |
  
-For a description what each type means and which other formatting classes are registered in them read the comments in ''[[xref>inc/parser/parser.php]]''.+Для описания того, что каждый из типов значит и какие другие классы форматирования зарегистрированы в них, читайте комментарии в файле  ''inc/parser/parser.php''.
  
-====== TutorialSyntax Plugins Explained ======+====== Руководстворазбор синтаксического плагина ======
  
-The goal of this tutorial is to explain the concepts involved in a DokuWiki [[devel:Syntax Plugins|syntax plugin]] and to go through the steps involved in writing your own plugin.+Цель данного руководства --- разобрать концепции, касающиеся [[syntax_plugins|синтаксических плагинов]] «[[wiki:dokuwiki|ДокуВики]]» и пройти шаги, связанные с написанием своего собственного плагина.
  
-For those who are really impatient to get startedgrab a copy of the [[devel:syntax_plugin_skeleton|syntax plugin skeleton]].  It's a bare bones plugin which outputs "//Hello World!//" when it encounters "''%%<TEST>%%''" on a wiki page.+Для техкто с особым нетерпением жаждет начать: возьмите копию плагина [[syntax_plugin_skeleton|syntax plugin skeleton]]. Это своего рода костяк --- плагин, который выводит «Hello World!», когда встречает токен «''%%<TEST>%%''» в статье вики. Начните наращивать на него «мясо».
  
-===== Quick Summary =====+===== Краткая выжимка =====
  
-**modes**+состояния --- modes
  
-  * each individual piece of DokuWiki syntaxincluding your pluginhas its own mode+  * Каждый отдельный элемент синтаксиса «ДокуВики»включая и ваш собственный плагинимеет своё собственное состояние
-  * similar modes are grouped together into [[#mode types]]. +  * Похожие состояния группируются в [[#типы состояний]]. 
-  * a mode's "allowedTypes" govern which other DokuWiki syntax is recognised when nested within the mode's own syntaxAll the modes which belong to the allowedTypes will be permitted+  * «allowedTypes» каждого состояния определяет, какие другие синтаксические конструкции «ДокуВики» опознаются внутри собственной синтаксической конструкции этого состоянияВсе состояния из «allowedTypes» допустимы
-  * a mode's "type" lets other modes know if they can permit this mode within their syntax.+  * «Тип» состояния даёт понять другим состояниям, могут ли они допустить использование данного состояния внутри своего синтаксиса.
  
-** handle ** +**handle** 
-  * the ''[[#handle_method|handle()]]'' method is called when the parser encounters wiki page content that it decides belongs to your syntax mode  +  * Метод ''[[#метод handle|handle()]]'' вызывается, когда парсер решит, что столкнулся в содержимом статьи вики с куском, относящимся к синтаксису вашего состояния
-  * the ''$state'' parameter says which type of pattern registered to your mode was triggered If it's just ordinary text the state parameter will be set to ''DOKU_LEXER_UNMATCHED'' +  * Параметр ''$state'' говорит, какой тип шаблона из приписанных к вашему состоянию сработалЕсли это просто обычный текст, то параметр ''state'' будет установлен в ''DOKU_LEXER_UNMATCHED''. 
-  * do as much processing and decision making as possible hereleaving as little as possible to be carried out in the ''[[#render_method|render()]]'' method because the output of handle is cached. This also means that you shouldn't do any stuff here that mustn't be cached.+  * Производите как можно больше обработки и принятия решений именно тутоставляя как можно меньше на обработку методу ''[[#метод render|render()]]'', потому что выдача метода handle кэшируется. This also means that you shouldn't do any stuff here that mustn't be cached.
  
-** render ** +**render** 
-  * The ''[[#render_method|render()]]'' method processes the renderer instructions that apply to the plugin's syntax mode - and which were created by the plugin'''[[#handle_method|handle()]]'' method+  * Метод ''render()'' выполняет инструкции отображения, которые применимы к синтаксическому состоянию плагина (и которые были созданы методом ''handle()'' плагина
-  * add content to the output document with ''%%$renderer->doc .= 'content';%%'' +  * Добавляйте содержание к выходному документу с помощью ''%%$renderer->doc .= 'content';%%'' 
-  * access the return value of handle() using the //$data// parameter of render($formatDoku_Renderer $renderer, $data). +  * Убедитесьчто любая выдача вашего плагина **безопасна** (run raw wiki data through an entity conversion function).  
-  ensure any content output by the plugin is **safe** - run raw wiki data through an entity conversion function.  +  * Совершайте как можно меньше операций по обработке и принятию решений здесьэто всё следует делать в методе ''handle()''.
-  * do the minimum possible processing and decision making hereit should all have been done in the ''[[#handle_method|handle()]]'' method.+
  
-:!: There is no guarantee the ''[[#render_method|render()]]'' method will be called at the same time as the ''[[#handle_method|handle()]]'' method The instructions generated by the handler are cached and can be used by the renderer at a future timeThe only sure way to pass data from ''[[#handle_method|handle()]]'' to ''[[#render_method|render()]]'' is using the array it returns which is passed to ''[[#render_method|render()]]'' as the ''$data'' parameter.+:!: Нет никакой гарантии, что метод ''render()'' будет вызван в то же время, что и метод ''handle()''Инструкции, произведённые хэндлером, кэшируются и могут использоваться рендером в более позднее времяЕдинственный надёжный способ передать данные от ''handle()'' к ''render()'' --- это использовать возвращаемый методом ''handle()'' массив, который передаётся методу ''render()'' в качестве параметра ''$data''
  
-===== Key Concepts ===== +===== Ключевые концепции =====
-==== modes ====+
  
-Modes (or more properly syntax modes) are the foundation on which the DokuWiki parser is based.  Every different bit of DokuWiki markup has its own syntax mode. E.g. there is a strong mode for handling **strong**, a superscript mode for handling <sup>superscript</sup>, a table mode for processing tables and many more.+==== Состояния ====
  
-When the parser encounters some markup it enters the syntax mode for that markup The properties and methods of that particular syntax mode govern how the parser behaves while it is within that modeincluding: +Состояния (более точно синтаксические состояния) --- это основа, на которой базируется парсер «ДокуВики»Каждый отдельный элемент разметки «ДокуВики» имеет своё синтаксическое состояние. Напримерсуществует состояние ''strong'' для работы со **strong**, состояние ''superscript'' для работы с <sup>superscript</sup>, состояние ''table'' для работы таблицами и многие другие.
-  what other syntax modes are allowed to occur +
-  what instructions to prepare for the renderer+
  
-Your plugin will add its own syntax mode to the parser - that is automatically handled by DokuWiki when the plugin is first loadedthe name assigned is ''plugin_''+ the name of the plugin's directory (which must also be the plugin's class name without the prefix "''syntax_''")Thenwhen the parser encounters the markup used for your pluginthe parser will enter into that syntax mode.  While it is in that mode your plugin controls what the parser can do.+Когда парсер сталкивается с разметкойон попадает в соответствующее этой разметке синтаксическое состояниеСвойства и методы конкретного синтаксического состояния управляют темкак ведёт себя парсерпока он в этом состоянии, включая:  
 +  * какие другие состояния могут произойти; 
 +  * какие инструкции подготовить для рендера.
  
-==== mode types ====+Ваш плагин добавит своё синтаксическое состояние к парсеру --- это автоматически производится «ДокуВики», когда впервые загружает плагин, назначаемое имя --- ''plugin_''+ имя директории плагина (которое является также именем класса плагина без префикса «''syntax_''»). Затем, когда парсер сталкивается с разметкой, используемой вашим плагином, он (парсер) войдёт в это синтаксическое состояние. Пока он находится в этом состоянии, ваш плагин управляет тем, что может делать парсер.   
  
-To simplify things, syntax modes which behave in a similar manner have been grouped together into several mode types - a complete list can be found on the [[devel:Syntax Plugins#syntax_types|syntax plugin]] page.+==== Типы состояний ====
  
-Each mode type corresponds to a key in the ''$PARSER_MODES'' array. The entry for each mode type is itself an array which holds all the syntax modes which belong to that type. e.g. In vanilla DokuWiki with no plugins installed''$PARSER_MODES['formatting']'' holds an array containing: 'strong', 'emphasis', 'underline', 'superscript', 'subscript', 'monospace', 'deleted' & 'footnote'.+Для упрощения синтаксические состояниякоторые ведут себя одинаковым образом, были сгруппированы в несколько типов состояний --- полный список может быть найден в разделе «[[#синтаксические типы|Синтаксические плагины].
  
-When each plugin is loaded into the parser it is queried, via ''getType()'', to discover which mode type it will belong to The syntax mode associated with the plugin is then added to the appropriate ''$PARSER_MODES'' array.+Каждый тип состояний соотносится с ключом в массиве ''$PARSER_MODES''. Элемент этого массива, соответствующий каждому типу состояний, сам является массивом, который содержит все синтаксические состоянияотносящиеся к этому типуНапример, в «чистой» «ДокуВики» без установленных плагинов элемент массива ''$PARSER_MODES['formatting']'' содержит: strong, emphasis, underline, superscript, subscript, monospace, deleted и footnote.
  
-:!: The mode type your plugin reports governs where in a DokuWiki page the parser will recognise your plugin's markup.  Other DokuWiki (and pluginsyntax modes won't know about your pluginbut they do know about the different mode typesIf they allow a particular mode typethey will allow all the modes which belong to that typeincluding any plugins that have returned that mode type.+Когда плагин загружается в парсер, то через ''getType()'' он запрашивается о типе состоянияк которому относитсяЗатем синтаксические состоянияотносящиеся к плагинудобавляются в соответствующий массив ''$PARSER_MODES''  
  
-Select the mode type for your plugin by comparing the behaviour of your plugin to that of the standard DokuWiki syntax modes Choose the type that the most similar modes belong to+:!: Указанный вашим плагином тип состояний определяет, где в статье «ДокуВики» парсер будет опознавать разметку вашего плагинДругие синтаксические состояния «ДокуВики» (также, как и плагины) не будут знать о вашем плагине, но они знают о различных типах состояний.
  
-==== allowed modes ====+Если они допускают конкретный тип состояний, он допускают все состояния этого типа, включая любые плагины, которые заявили этот тип состояний. 
 +  
 +Выберите тип состояний для своего плагина, сравнивая поведение своего плагина с поведением стандартных состояний «ДокуВики». Выберите тип, к которому относятся наиболее похожие состояния.
  
-These are the other modes that can occur nested within the current mode's own markup.+==== Допустимые состояния ====
  
-Each syntax mode has its own array of allowed modes which tells the parser what other syntax modes will be recognised whilst it is processing the mode.  That isif you want your plugin to be able to occur nested within "%%**strong**%%" markup, then the strong mode must include your plugin's mode in its allowedModes array.  And if you want to allow strong markup nested within your plugin's markup then your plugin must have ''%%'strong'%%'' in its allowModes array.+Есть другие состояниякоторые могут возникнуть внутри разметки вашего собственного состояния.
  
-:!: Your plugin gets in the allowedModes array of other syntax modes through the mode type it reports using the ''getType()'' method.+Каждое синтаксическое состояние имеет собственный массив допустимых состояний, который говорит парсеру, какие именно другие синтаксические состояния будут опознаваться во время обработки состояния. То есть, если вы хотите, чтобы ваш плагин мог оказаться внутри разметки «%%**strong**%%», тогда состояние ''strong'' должен включить состояние вашего плагина в свой массив «allowedModes». И если вы хотите позволить разметке ''strong'' включаться внутрь разметки вашего плагина, то ваш плагин должен содержать ''%%'strong'%%'' в своём массиве «allowModes». 
 +  
 +:!: Ваш плагин собирает в массив «allowedModes» другие синтаксические состояния посредством типа состояний, объявляемого методом ''getType()''. 
 + 
 +:!: Ваш плагин сообщает парсеру, какие другие синтаксические состояния он допускает, декларируя (объявляя) их через метод ''getAllowedTypes()''.  
  
-:!: Your plugin tells the parser which other syntax modes it permits by reporting the mode types it allows via the ''getAllowedTypes()'' method.  
 ==== PType ==== ==== PType ====
  
-PType governs how the parser handles html %%<p>%% elements when dealing with your syntax mode.+PType определяет, как парсеру работать с HTML-элементами %%<p>%%, когда он имеет дело с вашим синтаксическим состоянием. 
 + 
 +Обычно в тот момент, когда парсер сталкивается с некоторой разметкой, имеется открытый HTML-тэг параграфа. Парсеру необходимо знать, должен ли он закрыть этот тэг перед входом в ваше синтаксическое состояние и затем открыть другой параграф на выходе (''%%PType='block'%%'' или ''%%PType='stack'%%'') или парсер должен оставить параграф в покое (''%%PType='normal'%%''). 
 + 
 +PType также определяет будет ли параграф создаваться внутри вашего синтаксического состояния. И если будет - то как. 
 + 
 +Если ''%%PType='normal'%%'', то параграф не будет создаваться вовсе
  
-Generally, when the parser encounters some markup, there will be a currently open HTML paragraph tag.  The parser needs to know if it should close that tag before entering your syntax mode and then open another paragraph when exiting, that is ''%%PType='block'%%'' and ''%%PType='stack'%%'', or whether it should leave the paragraphs alone''%%PType='normal'%%''.+Если ''%%PType='block'%%'', то парсер закроет параграф перед входом в ваше синтаксическое состояниеи откроет новый параграф после выходы из вашего синтаксического состояния. Внутри вашего синтаксического состояния создание параграфов должно быть запрещено (см. [[#допустимые_состояния|"Допустимые состояния"]]), иначе открытый параграф закроется как обычно (как только встретятся два подряд или более newlines), и откроется новый. В результате, например, открывающий TAG <DIV> может оказаться внутри одного параграфа, а закрывающий </DIV> внутри другого. Или ещё что-то.
  
-The PType also decides how and if paragraphs are created **inside** the syntax mode. With ''%%PType='normal'%%'' no paragraphs are created at all. ''%%PType='stack'%%'' opens a paragraph when inside the syntax mode (and closes it laterparsing paragraphs like usual). And ''%%PType='block'%%'' starts with no paragraphbut creates them as usual as soon as there are more than two newlines.+Если ''%%PType='stack'%%'', то парсер: 
 +  - закроет параграф перед входом в ваше синтаксическое состояние; 
 +  - откроет параграф после входа в ваше синтаксическое состояние; 
 +  - если внутри вашего синтаксического состояния разрешёно создавать параграфы (см. [[#допустимые_состояния|"Допустимые состояния"]])то параграфы внутри вашего синтаксического состояния будут создаваться как обычно (как только встретятся два подряд или более newlines). Если не разрешеното параграф так и останется открытым до выхода из вашего синтаксического состояния; 
 +  - перед выходом из вашего синтаксического состояния парсер закроет параграф (в этом месте он должен быть открыт, не зависимо от того, разрешено ли создавать параграфы внутри или нет); 
 +  - после выходы из вашего синтаксического состояния парсер откроет новый параграф.
  
-For those that know CSS, returning ''%%PType='block'%%'' and ''%%PType='stack'%%'' means the html generated by your plugin will be similar to ''display:block'' and returning ''%%PType='normal'%%''means the HTML generated will be similar to ''display:inline''.+Для тех, кто знает CSS, возвращение ''%%PType='block'%%'' означает, что html, произведённый вашим плагином, будет похож на ''display:block'', а возвращение ''%%PType='normal'%%'' означает html, похожий на ''display:inline''.
  
-=== Example ===+=== Пример ===
  
-Suppose we have a fairly standard syntax plugin with the ENTRY => UNMATCHED => EXIT patternDepending on the PType setting, ''<p>'' and ''</p>'' will be inserted by the renderer automatically at various points outside, or even interspersed, with the plugin textThat means your plugin doesn't need to take care of those tags.+Предполагается, что вы хорошо знакомы со стандартным шаблоном syntax plugin ENTRY => UNMATCHED => EXIT. В зависимости от значения PType ''<p>'' и ''</p>'' будут расставляться автоматически рендером в разных точках снаружи и внутри текста плагинаПоэтому вашему плагину не нужно заботиться об этих тэгах.
  
 ^wikisyntax ^PType=normal ^PType=block ^PType=stack ^ ^wikisyntax ^PType=normal ^PType=block ^PType=stack ^
Строка 156: Строка 166:
 </code> | </code> |
  
-==== Sort Number ====+==== Порядковый номер ====
  
-This number is used by the lexer((the part of the parser which analyses the raw wiki page)) to control the order it tests the syntax mode patterns against raw wiki data It is only important if the patterns belonging to two or more modes match the same raw data - where the pattern belonging to the mode with the lowest sort number will win out.+Этот номер используется лексером((Lexer --- часть парсера, анализируящая «сырую» (исходнуюстатью вики.)) для управления порядком, в котором он проверяет шаблоны синтаксических состояний на «сырых» (исходных) данных викиЭто важно только в том случае, если один и тот же участок данных попадает в шаблоны, относящиеся к двум или более состояниям. После проверки будет выбран шаблон, относящийся к состоянию с наименьшим порядковым номером.
  
-You can make use of this behaviour to write a plugin which will replace or extend a native DokuWiki handler for the same syntax An example is the [[plugin:code]] plugin.+Вы можете использовать это свойство для написания плагина, который заменяет или расширяет «родной» хендлер «ДокуВики» для той же синтаксической конструкцииПримером является плагин «[[wiki:plugin:Code]]».
  
-Details of existing sort numbers are available for both the [[parser]] ([[devel:parser:getsort_list|sort list]]).+Подробности о существующих порядковых номерах доступны для обоих [[parser]] ([[wiki:devel:parser:getsort_list|sort list]]). 
 +:?:
  
-==== Patterns ====+==== Шаблоны ====
  
-The parser uses PHP's preg((perl compatible regular expressions \\ ref: www.php.net/manual/en/ref.pcre.php)) compatible functionsA detailed explanation of regular expressions and their syntax is beyond the scope of this tutorial There are many good sources on the web+Парсер использует PHP-функции «preg»((Совместимые с Perl регулярные выражения. Ссылка: www.php.net/manual/en/ref.pcre.php.)). Детальное объяснения регулярных выражений и их синтаксиса выходит за пределы этого руководстваСуществует много хороших источников в интернете.
  
-The complete preg syntax is not available for use in constructing syntax plugin patternsBelow is a list of the known differences: +Полный синтаксис «preg» не доступен для использования в конструировании шаблонов синтаксических плагиновНиже приведён список известных различий:
- +
-  * don't surround the pattern with delimiters +
-  * to use a pipe "''|''" for multiple alternatives, make them a non-captured group, e.g. "''(?:cat|dog)''" +
-  * be very wary of look behind assertions. The parser only attempts to match patterns on the next piece of "not yet matched" data.  If you need to look behind to characters that have been involved in a previous pattern match, those characters will never be there. +
-  * option flags can only be included as inline options, e.g. ''(?i)'', ''(?-i)'' +
-  * back references do not work, e.g. "''(\w)\1\w+''" (finding a word with a doubled first characters), due to the way the lexer functions internally.+
  
 +  * Шаблоны не окружаются разделителями.
 +  * Для использования вертикальной черты «|» при множественных альтернативах, сделайте их non-captured-группами, т. е. «(?:cat|dog)».
 +  * Будьте очень осторожны с «заглядыванием назад». Парсер только пытается сравнить шаблон со следующим куском «ещё не проверенных» данных. Если вам нужно заглянуть в символы, которые уже участвовали в предыдущем сравнении с шаблоном, то этих символов там на самом деле не будет.
 +  * Флаги опций могут быть включены только как встроенные опции, т. е. ''(?i)'', ''(?-i)''.
 \\ \\
  
-The parser provides four functions for a plugin to register the patterns it needs Each function corresponds to a pattern with a different meaning.+Парсер предоставляет плагину четыре функции для регистрации необходимых шаблоновКаждая функция относится к шаблонам с разными смыслами.
  
-  * **special patterns** --- ''addSpecialPattern()'' --- these are the patterns used when one pattern is all that is requiredIn the parser's termsthese patterns represent entry in the the plugin's syntax mode and exit from that syntax mode all in the one matchTypically these are used by ''substition'' plugins+  * **специальные шаблоны** --- ''addSpecialPattern()'' --- это шаблоны, которые используются, когда один шаблон --- это всё, что нужноВ терминах парсера эти шаблоны представляют и вход в синтаксическое состояние плагинаи выход из этого синтаксического состояния, всё в одно сравнениеОбычно они используются в плагинах ''substition''
-  * **entry patterns** --- ''addEntryPattern()'' --- the pattern which indicates the start of data to be handled by the pluginTypically these patterns should include a look-ahead to ensure there is also an exit pattern Any plugin which registers an entry pattern should also register an exit pattern+  * **входные шаблоны** --- ''addEntryPattern()'' --- шаблон, указывающий на начало данных, которые должны быть обработаны плагиномОбычно эти шаблоны должны включать в себя заглядывание вперёд для проверки существования выходного шаблонаЛюбой плагин, который регистрирует входной шаблон, также должен зарегистрировать выходной шаблон
-  * **exit patterns** --- ''addExitPattern()'' --- the pattern which indicates the end of the data to be handled by the pluginThis pattern can only be matched if text matching the entry pattern has been found+  * **выходные шаблоны** --- ''addExitPattern()'' --- шаблон, указывающий на конец данных, которые должны быть обработаны плагиномЭтот совпадение с этим шаблоном может произойти, только если было найдено совпадение с входным шаблоном((Криво переведено с англ.))
-  * **internal patterns** --- ''addPattern()'' --- these represent special syntax applicable to the plugin that may occur between the entry and exit patterns. Generally these are only required by the more complex structurese.g. lists and tables.+  * **внутренние шаблоны** --- ''addPattern()'' --- представляют специальный синтаксисприменимый к плагину, который может встретиться между входным и выходным шаблонамиОбычно это нужно только для достаточно сложных структур, например, таблиц и списков.
 \\ \\
  
-One plugin may add several patterns to the parserincluding more than one pattern of the same type.+Один плагин может добавить несколько шаблонов в парсервключая более чем один шаблон одного типа.
  
-**Tips**+**Советы**
  
-  * use non-greedy quantifierse.g. ''+?'' or ''*?'' instead of ''+'' or ''*''+  * Используйте «нежадные» идентификаторыте. ''+?'' или ''*?'' вместо ''+'' или ''*''
-  * be wary of using multiple exit patternsThe first exit pattern encountered will most likely trigger the parser to exit your syntax mode - even if that wasn't the pattern the entry pattern looked ahead forNeeding multiple exit patterns probably indicates a need for multiple plugins+  * Будьте осторожны с использованием нескольких выходных шаблоновСкорее всего сработает выход из состояния по первому встреченному выходному шаблону, даже если это будет не тот шаблон, который «увидел при заглядывании вперёд» входной шаблонНеобходимость нескольких выходных шаблонов может означать, что на самом деле вам нужны несколько плагинов
-  * In the [[devel:plugin_survey:compatibility#syntax|Plugin Survey]] of 2011 it looks like a majority of special patterns are either ''%%{{…}}%%'' (160 cases) or ''%%~~…~~%%'' (80 cases). A very common entry/exit pattern (231 plugins) is something like an XML tag even if some use upper case letters. +  * В ранних версиях «ДокуВики» лексер имел баг, не дававший использовать угловые скобки «<» или «>» в «заглядывающих вперёд» шаблонахЭтот баг был исправлен и угловые скобки теперь допустимыНекоторые плагины всё ещё содержат шестнадцатеричные обозначения для угловых скобкок («\x3C»«\x3E»--- такой приём позволял обойти баг
-  * early versions of the DokuWiki lexer had a bug which prevented use of "<" or ">" in look ahead patterns This bug has been fixed and angle brackets can now be used Some plugins will still contain the hex codes for angle brackets ("\x3C""\x3E"which was the workaround to overcome the effects of this bug. +
-  * Use this for a example of correct regular expression: [[devel:plugin_programming_tips#use_correct_regular_expressions|Use correct regular expressions]] +
-==== handle() method ====+
  
-This is the part of your plugin which should do all the work.  Before DokuWiki renders the wiki page it creates a list of instructions for the renderer.  The plugin's ''handle()'' method generates the render instructions for the plugin's own syntax mode.  At some later time, these will be interpreted by the plugin's ''render()'' method.  The instruction list is cached and can be used many times, making it sensible to maximize the work done once by this function and minimize the work done many times by ''render()''.+==== Метод handle() ====
  
-The complete signature is: ''public function handle($match$state$posDoku_Handler $handler)'' with the arguments:+Это часть вашего плагина, которая должна совершать всю работу. До того как «ДокуВики» выведет статью вики, он создаёт список инструкций для рендера. Метод ''handle()'' плагина создаёт инструкции отображения для собственного синтаксического состояния. В некий более поздний момент они будут интерпретированы методом ''render()'' плагина. Список инструкций кэшируется и может быть использован много разразумно максимально увеличить объём работысовершаемой один раз этой функцией и максимально уменьшить объём работысовершаемый много раз функцией ''render()''.
  
-**$match** parameter --- The text matched by the patternsor in the case of **''DOKU_LEXER_UNMATCHED''** the contiguous piece of ordinary text which didn't match any pattern.+Параметр ''$match'' --- тексткоторый совпадает с шаблоном, или, в случае ''DOKU_LEXER_UNMATCHED'', непрерывный кусок обычного текста, который не совпал с каким-либо шаблоном.
  
-**$state** parameter --- The lexer state for the matchrepresenting the type of pattern which triggered this call to handle(): +Параметр ''$state'' --- тип шаблонаиз-за которого запустился вызов handle(). 
-  * **''DOKU_LEXER_ENTER''** --- a pattern set by addEntryPattern() +  * ''DOKU_LEXER_ENTER'' --- шаблон установлен функцией addEntryPattern(); 
-  * **''DOKU_LEXER_MATCHED''** --- a pattern set by addPattern() +  * ''DOKU_LEXER_MATCHED'' --- шаблон установлен функцией addPattern(); 
-  * **''DOKU_LEXER_EXIT''** --- a pattern set by addExitPattern() +  * ''DOKU_LEXER_EXIT'' --- шаблон установлен функцией addExitPattern(); 
-  * **''DOKU_LEXER_SPECIAL''** --- a pattern set by addSpecialPattern() +  * ''DOKU_LEXER_SPECIAL'' --- шаблон установлен функцией addSpecialPattern(); 
-  * **''DOKU_LEXER_UNMATCHED''** --- ordinary text encountered within the plugin's syntax mode which doesn't match any pattern.+  * ''DOKU_LEXER_UNMATCHED'' --- обычный текст, встреченный внутри синтаксического состояния плагина, который не совпал ни с одним шаблоном.
  
-**$pos** parameter --- The character position of the matched text.+Параметр ''$pos'' --- позиция первого символа найденного текста.
  
-**$handler** parameter --- Object Reference to the [[devel:parser#handler|Doku_Handler]] object.+Параметр ''&$handler'' --- ссылка на объект [[ru:devel:parser#обработчик|Doku_Handler]].
  
-**return** --- The instructions for the ''render()'' method. These instructions are cached. The return value can be everything you require for your needs. Often, it is an array in which the different values are collected that are founded or determined in handle() and which are useful in ''render()''.+==== Метод render() ====
  
-==== render() method ==== +Часть плагина, которая производит вывод окончательной веб-страницы или какой-либо другой поддерживаемый форматИменно здесь плагин добавляет собственный вывод к уже созданным другими частями рендерера путём склейки со свойством ''doc'' рендераТ. е.: 
- +<code> 
-The part of the plugin that provides the output for the final web page or whatever other output format is supported. It is here that the plugin adds its output to that already generated by other parts of the renderer e.g. by concatenating its output to the renderer'''doc'' property. +$renderer->doc .= "некий вывод плагина...";
- +
-<code php+
-$renderer->doc .= "some plugin output...";+
 </code> </code>
  
-:!: Any raw wiki data that passes through ''render()'' should have all special characters converted to HTML entitiesYou can use DokuWiki'[[xref>hsc()]] or the PHP functions, [[phpfn>htmlspecialchars()]], [[phpfn>htmlentities()]] or the renderer's own [[xref>_xmlEntities()]] methode.g.<code php>$renderer->doc .= $renderer->_xmlEntities($text);</code>  +:!: В любых сырых данных вики, которые передаются ''render()'', все спецсимволы должны быть преобразованы в элементы HTML. Вы можете использовать PHP-функции ''[[http://uk.php.net/manual/en/function.htmlspecialchars.php|htmlspecialchars()]]''''[[http://uk.php.net/manual/en/function.htmlentities.php|htmlentities()]]'' или собственный метод ''xmlEntities()'' рендераТе.
 +<code> 
 +$renderer->doc .= $renderer->_xmlEntities($text); 
 +</code>  
  
-The complete signature is: ''public function render($formatDoku_Renderer $renderer$data)'' with the arguments:+Параметр ''$mode'' --- имя формата состояния финального вывода произведённого рендером. В настоящее время «ДокуВики» поддерживает только один формат вывода --- ''XHTML'' ((Существует ещё специальное состояние ''metadata''которое ничего не выводиттолько собирает метаданные для страницы. Используйте его для вставки значений в массив метаданных.)).
  
-**$format** parameter --- Name for the format mode of the final output produced by the renderer.  At present DokuWiki only supports one output format ''XHTML'' and a special (internal) format ''metadata'' ((The special mode ''metadata'' does not output anything but collects metadata for the page. Plugin can add other formats such as the ODT format. Use it to insert values into the metadata array. See the translation plugin for an example.)). New modes can be introduced by [[devel:renderer plugins]].  The plugin should only produce output for those formats which it supports - which means this function should be structured ... +Новые состояния могут быть представлены в [[wiki:devel:renderer_plugins|плагинах рендера]]. Плагины должны производить вывод только для тех форматов, которые они поддерживают, это значит, что эта функция должна быть структурирована... 
-<code php+<code> 
-if ($format == 'xhtml') {  // supported mode+if ($mode == 'xhtml') {  // supported mode
   // code to generate XHTML output from instruction $data   // code to generate XHTML output from instruction $data
 } }
 </code> </code>
  
-**$renderer** parameter --- Give access to the object [[xref>inc::Doku_Renderer|Doku_Renderer]]which contains useful functions and values. Above you saw already the usage of ''$renderer%%->%%doc'' for storing the render output.+Параметр ''$data'' --- массивсодержащий инструкции, предварительно подготовленные собственным методом ''handle()'' плагина. Эта функция должна интерпретировать инструкции и выдавать соответствующий вывод.
  
-**$data** parameter --- An array containing the instructions previously prepared and returned by the plugin's own ''handle()'' method.  The ''render()'' must interpret the instruction and generate the appropriate output.+==== Безопасность ====
  
-===XHTML renderer === +Сырые данные викикоторые достигли вашего плагина, больше никогда не должны обрабатыватьсяНикакой дальнейшей обработки не производится над выводом после тогокак он покидает плагинКак минимум, плагин должен убедиться, что в выводе все спецсимволы HTML заменены на HTML-последовательности. Также к извлечённым и используемым внутри данным вики нужно относится с вниманием. Смтакже статью «[[security|Безопасность]]».
-When your plugin needs to extend the content of a wiki pageyou need the output format mode ''xhtml''Because ''render()'' is called for all the format modesyou need to filter by the desired modes. +
-<code php> +
-if ($format == 'xhtml') {  // when the format mode is xhtml +
-    /** @var Doku_Renderer_xhtml $renderer */    +
-    // code to generate XHTML output from instruction $data +
-    $renderer->doc .= '<div>Adds your div</div>';   +
-+
-</code> +
-Detail: the variable ''$renderer'' is now the [[xref>inc::Doku_Renderer_xhtml|Doku_Renderer_xhtml]] object.+
  
-=== Metadata renderer === +==== Локализация ==== 
-A special render format ''metadata'' is for rendering metadata. [[Metadata]] are the extra properties kept for your wiki page, which you can also extend or modify in your plugin.+FIXME 
 +Смотрите статьи «[[wiki:devel:common_plugin_functions#локализация|Локализация]]» и «[[plugin_file_structure|Структура файлов плагина]]».
  
-In the metadata rendering format you extracts metadata from the page. This is particularly important if you manually handle certain kinds of links. If you don't register these, they will not show up as backlinks on the pages that they refer to. Here is an example of how to register these backlinks:+==== Конфигурация ====
  
-<code php> +Смотрите статью «[[configuration|Конфигурация]]».
-public function render($format, Doku_Renderer $renderer, $data) { +
-    if($format == 'xhtml') { +
-        /** @var Doku_Renderer_xhtml $renderer */ +
-        // this is where you put all the rendering that will be displayed in the  +
-        // web browser +
- return true; +
-    } +
-    if($format == 'metadata') { +
-        /** @var Doku_Renderer_metadata $renderer */ +
-        $renderer->internallink($data[0]); +
-        // I am assuming that when processing in handle(), you have stored +
-        // the link destination in $data[0] +
-        return true; +
-    } +
-    return false; +
-+
-</code> +
-This example uses the [[xref>internallink()]] function from ''inc/parser/metadata.php''. You can also access the metadata directly in the renderer with ''%%$renderer->meta%%'' and ''%%$renderer->persistent%%'', because ''$renderer'' is now the [[xref>inc::Doku_Renderer_metadata|Doku_Renderer_metadata]] objectHere is a snippet from the tag plugin: +
-<code php> +
-public function render($format, Doku_Renderer $renderer, $data) { +
-    if ($data === false) return false;+
  
-    // XHTML output +==== Использование CSS и JavaScript ===
-    if ($format == 'xhtml') { +FIXME 
-        /** @var Doku_Renderer_xhtml $renderer */ +Смотрите статью «[[plugin_file_structure|Структура файлов плагина]]».
-        ... +
-     +
-    // for metadata renderer +
-    } elseif ($format == 'metadata') { +
-        /** @var Doku_Renderer_metadata $renderer */ +
-        // erase tags on persistent metadata no more used +
-        if (isset($renderer->persistent['subject'])) { +
-            unset($renderer->persistent['subject']); +
-            $renderer->meta['subject'[]; +
-        } +
-         +
-        // merge with previous tags and make the values unique +
-        if (!isset($renderer->meta['subject'])) { +
-            $renderer->meta['subject'= []+
-        } +
-        $renderer->meta['subject'] = array_unique(array_merge($renderer->meta['subject'], $data)); +
-         +
-        // create raw text summary for the page abstract +
-        if ($renderer->capture) { +
-            $renderer->doc .= implode(' ', $data); +
-        } +
-         +
-        ... +
-        return true; +
-    } +
-    return false; +
-+
-</code> +
-First it handles old persistent metadata no longer used by this plugin. This persistent metadata is always kept, thus when you change your mind and use current metadata instead, you need to remove it explicitly+
  
-When handling persistent data in the metadata renderer, take care you update also the current metadata, when you update persistent metadata. +==== Добавление кнопок к панели инструментов ====
  
-The tag plugin stores here 'subject' data by ''$renderer%%->%%meta['subject'] = ...''. Be aware that when you use ''p_set_metadata'' to set current metadata somewherethat the next time the metadata is rendered it will overwrite this data. Using [[xref>p_get_metadata($ID$key)]] gives access to stored metadata. For details see [[devel:metadata]].+Для тогочтобы облегчить жизнь пользователям викикоторые установили ваш плагин, следует добавить кнопку в панель инструментов редактора.
  
-When some raw text from your syntax should be included in the abstract you can append it to ''$renderer%%->%%doc''When the abstract is long enough, ''$renderer%%->%%capture'' becomes false.+Смстатьи: 
 +  * [[action_plugins#sample_action_plugin_2|Плагины действий]]; 
 +  * [[toolbar|Панель инструментов]].
  
-The xhtml mode is called when DokuWiki is in need of a new xhtml version of the wikipage. The metadata is a bit different. In general, the metadata of the page is rendered on demand when [[xref>p_get_metadata()]] is called somewhere. +===== Написание своего собственного плагина =====
  
-When someone edit a page and use the preview functionthe metadata renderer is not calledSo the metadata is not yet updated! This is done when the page is saved.+Ну хорошовы решили расширить синтаксис «ДокуВики» своим собственным плагиномВам придётся разработать, каким будет ваша синтаксическая конструкция и как она будет отображаться в браузере пользователя. Теперь вам необходимо написать сам плагин.
  
-===== Safety & Security =====+  - Примите решение, как назвать плагин. Возможно вы захотите проверить список [[ru:plugins|доступных плагинов]], чтобы убедиться, что такое имя уже не используется. 
 +  - В своей собственной установке «ДокуВики» создайте собственную поддиректорию в директории ''lib/plugins/''. Эта директория должна называться также, как ваш плагин. 
 +  - Создайте в новой директории файл ''syntax.php''. В качестве отправной точки, можете использовать [[syntax_plugin_skeleton|скелет плагина]]. Скопируйте его в свою директорию. 
 +  - Отредактируйте этот файл под свои нужды: 
 +    * измените название класса, чтобы он был вида ''syntax_plugin_<название вашего плагина>''((Название не может содержать символов подчерка и должно совпадать с названием класса)); 
 +    * измените метод ''getInfo()'', чтобы он выдавал информацию о вашем плагине; 
 +    * измените метод ''getType()'', чтобы он выдавал тип состояний, к которому относится ваш плагин; 
 +    * добавьте метод ''getAllowedTypes()'' для сообщения всех типов состояний, которые ваш плагин может включать внутрь своей собственной синтаксической конструкции. Если ваш плагин не желает позволять какому-либо состоянию включаться в себя, он может быть выкинут; 
 +    * измените метод ''getPType()'', чтобы он выдавал PType, который относится к вашему плагин. Если это ''%%'normal'%%'', вы можете просто убрать этот метод; 
 +    * измените метод ''getSort()'', чтобы он выдавал уникальный номер, проверьте его в списке [[ru:plugins|плагинов]]; 
 +    * измените метод ''connectTo()'', чтобы зарегистрировать шаблон для опознавания вашего синтакиса; 
 +    * добавьте метод ''postConnect()'', если ваш синтаксис имеет второй шаблон, для того, чтобы указать, когда парсер должен покинуть ваше синтаксическое состояние. 
 +  - Ну вот, простая часть работы сделана, теперь у вас есть плагин, которой скажет «Hello World!», когда встретит шаблон вашего синтаксиса. Самое время проверить его и убедиться, что шаблон работает как надо --- посетите свою вики и создайте статью с синтаксической страницей своего плагина, сохраните её и убедитесь, что «Hello World!» действительно  показывается. 
 +  - Напишите свои собственные методы ''handle()'' и ''render()'': 
 +    * если у вас есть входной и выходной шаблоны, не забудьте обработать не совпавшие с шаблоном данные; 
 +    * относитесь к сырым данным вики с подозрением (вниманием) и убедитесь, что все спецсимволы прошли конвертор последовательностей. 
 +  - Протестируйте и добавьте плагин на [[wiki:plugins|страницу плагинов]] «ДокуВики».
  
-Raw wiki page data which reaches your plugin has not been processed at all. No further processing is done on the output after it leaves your plugin. At an absolute minimum the plugin should ensure any raw data output has all HTML special characters converted to HTML entities. Also any wiki data extracted and used internally should be treated with suspicion. See also [[devel:security]].+===== Пример 1-й плагина — Now =====
  
-===== Common plugin functions =====+Когда синтаксическая конструкция этого плагина ''%%[NOW]%%'' встречается в статье вики, текущая дата и время отображается в формате [[http://www.faqs.org/rfcs/rfc2822|RFC2822]].
  
-Some function are shared between the pluginsrefer to next sections for info: +  * Типом является ''%%'substition'%%''. Мы подставляем временую метку вместо токена ''%%[NOW]%%''аналогично смайлам и акронимами. Они также относятся к типу состояний  ''%%'substition'%%''. 
-  * [[devel:common_plugin_functions#Configuration|Plugin configuration settings]]  +  * Заполнять «allowedTypes» не требуется, т. к. никакие другие синтаксические конструкции не могут появиться в конструкции ''%%[NOW]%%''. Т. о. нам не нужен метод ''getAllowedTypes()''. 
-  * [[devel:common_plugin_functions#localization|Localization]] +  * PType --- ''normal'' --- это значение по умолчанию, поэтому нам не нужно определять  метод ''getPType()''. 
-  * [[devel:common_plugin_functions#styles and javascript|Using styles and javascript]] +  * Нет необходимости во входном и выходном шаблонами, только специальный шаблон, чтобы найти ''%%[NOW]%%''. Единственная вещь, с которой нужно быть осторожным, это то, что символы «[» и «]» имеют специальное значение в регулярных выражениях, поэтому нам нужно «выключить» (escape) их, создав шаблон ''%%'\[NOW\]'%%''
 +  * В нашем случае метод ''handler()'' не должен ничего делать. Нам не нужно заботиться о специальных состояниях или дополнительных параметрах в нашем синтаксисе. Мы просто вернём пустой массив в качестве инструкций для рендера. 
 +  * Всё, что нужно методу ''render()'' --- добавить штамп времени к текущей статье вики --- ''%%$renderer->doc .= date('r');%%''
  
- +И вот наш плагин завершён!
-==== Adding a Toolbar Button ==== +
- +
-To make it easy on the users of wikis which install your plugin, you should add a button for its syntax to the editor toolbar. +
- +
-  * The [[devel:toolbar#extending_the_toolbar|toolbar]] page explains how you can extend by PHP or javascript. +
-  * Another [[devel:action_plugins#Sample Action plugin 2|example]] is available at the Action Plugin page.  +
- +
-===== Writing Your Own Plugin ===== +
- +
-Ok, so you have decided you want to extend DokuWiki's syntax with your own plugin.  You have worked out what that syntax will be and how it should be rendered on the user's browser.  Now you need to write the plugin. +
- +
-  - Decide on a name for the plugin.  You may want to check the list of [[:plugins|available plugins]] to make sure you aren't choosing a name that is already in use. +
-  - In your own DokuWiki installation, create a new sub directory in the ''lib/plugins/'' directory. That directory will have the same name as your plugin. +
-  - Create the file ''syntax.php'' in the new directory.  As a starting point, use a copy of the [[devel:syntax plugin skeleton|skeleton plugin]]. +
-  - Edit that file to make it yours. +
-    * change the class name to be ''syntax_plugin_<your plugin name>''((The name may not contain underscores and needs to match your class name)). +
-    * change the ''getType()'' method to report the mode type your plugin will belong to. +
-    * add a ''getAllowedTypes()'' method to report any mode types your plugin will allow to be nested within its own syntax.  If your plugin won't allow any other mode then this can be left out. +
-    * change the ''getPType()'' method to report the PType that will apply for your plugin.  If its ''%%'normal'%%'' you can remove this method. +
-    * change the ''getSort()'' method to report a unique number after checking the [[:devel:parser:getsort_list|getsorted list]] and  +
-    * alter the ''connectTo()'' method to register the pattern to match your syntax. +
-    * add a ''postConnect()'' method if your syntax has an second pattern to say when the parser is leaving your syntax mode. +
-  - That's the easy part done, you now have a plugin that will say "Hello World!" when it encounters your syntax pattern.  Time to test it and make sure the pattern works as expected - visit your wiki and make up a page with the syntax for your plugin, save it and make sure "Hello World!" shows up. +
-  - Write your ''handle()'' & ''render()'' methods. +
-    * if you have entry and exit patterns remember to handle the unmatched data. +
-    * treat raw wiki data with suspicion and remember to ensure all special characters go to an entity converter. +
-  - Add a [[plugin_info|plugin.info.txt]] file in your plugin directory (see for example, the sample plugin below) +
-  - Test and post your completed plugin on the DokuWiki [[:plugins|plugin page]]. +
- +
-===== Read also===== +
- +
-  * The [[http://pluginwizard.dokuwiki.org/|Plugin Wizard]] can create a basic skeleton or with the [[plugin:dev]] plugin. +
-  * [[Plugin file structure]] +
-  * [[Common plugin functions]] +
-  * [[Plugin programming tips]] +
-  * [[plugins|Plugin Development]] +
- +
-===== Sample Plugin 1 - Now ===== +
- +
-When its syntax, ''%%[NOW]%%'', is encountered in a wiki page the current date and time will be inserted in [[http://www.faqs.org/rfcs/rfc2822|RFC2822]] format. +
- +
-  * type is ''%%'substition'%%''. We are substituting a time stamp for the ''%%[NOW]%%'' token, similar to the way smileys and acronyms are handled.  They belong to the mode type ''%%'substition'%%'' so we will too.  +
-  * allowedTypes are not required, no other DokuWiki syntax can occur within our ''%%[NOW]%%'' syntax.  Therefore we don't need the ''getAllowedTypes()'' method. +
-  * PType is ''normal'', that's the default value, so we don't need the ''getPType()'' method. +
-  * there is no need for an entry and exit pattern, just a special pattern to detect ''%%[NOW]%%'' The only thing we need to be careful of is "[" and "]" have special meanings in regular expressions, so we will need to //escape// them, making our pattern - ''%%'\[NOW\]'%%''+
-  * in this case the ''handler()'' method doesn't need to do anything.  We have no special states to take care of or extra parameters in our syntax.  We just return an empty array to ensure a render instruction for our plugin is stored. +
-  * all the ''render()'' method needs to do is add the time stamp to the current wiki page --- ''%%$renderer->doc .= date('r');%%'' +
- +
-And that's our plugin finished.+
  
 <code php syntax.php> <code php syntax.php>
Строка 394: Строка 313:
 // must be run within DokuWiki // must be run within DokuWiki
 if(!defined('DOKU_INC')) die(); if(!defined('DOKU_INC')) die();
 +
 +if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
 +require_once(DOKU_PLUGIN.'syntax.php');
  
 /** /**
Строка 401: Строка 323:
 class syntax_plugin_now extends DokuWiki_Syntax_Plugin { class syntax_plugin_now extends DokuWiki_Syntax_Plugin {
  
-    public function getType() { return 'substition'; } +    function getInfo(){ 
-    public function getSort() { return 32; } +      return array( 
- +        'author=> 'me', 
-    public function connectTo($mode) { +        'email'  => 'me@someplace.com', 
-        $this->Lexer->addSpecialPattern('\[NOW\]',$mode,'plugin_now');+        'date'   ='2005-07-28', 
 +        'name'   => 'Now Plugin', 
 +        'desc'   => 'Include the current date and time', 
 +        'url   => 'http://www.dokuwiki.org/plugin:tutorial', 
 +      );
     }     }
  
-    public function handle($match, $state, $pos, Doku_Handler $handler) { +    function getType() { return 'substition'; } 
-        return array($match, $state, $pos);+    function getSort() { return 32; } 
 +    function connectTo($mode) {  
 +        $this->Lexer->addSpecialPattern('\[NOW\]',$mode,'plugin_now'); 
     }     }
- +    function handle($match, $state, $pos, &$handler) {  
-    public function render($formatDoku_Renderer $renderer, $data) { +        return array($match, $state, $pos);  
-    // $data is what the function handle return'ed. +    } 
-        if($format == 'xhtml'){ +    function render($mode&$renderer, $data) { 
-            /** @var Doku_Renderer_xhtml $renderer */ +     
-            $renderer->doc .= date('r'); +      if($mode == 'xhtml'){ 
-            return true; +          $renderer->doc .= date('r'); 
-        +          return true; 
-        return false;+      
 +      return false;
     }     }
 } }
-</code>+?></code>
  
-You also need the plugin.info.txt file: +Замечаниеиз-за способа, которым «ДокуВики» кэширует страницы, этот плагин будет отображать дату/время для момента, когда был создан кэш страницыВам нужно добавить на страницу макрос ''%%~~NOCACHE~~%%'',чтобы отображалось правильное время каждый раз, когда запрашивается страница.
-<code txt plugin.info.txt> +
-base now +
-author me +
-email me@someplace.com +
-date 2005-07-28 +
-name Now Plugin +
-desc Include the current date and time +
-url https://www.dokuwiki.org/devel:syntax_plugins +
-</code>+
  
-Note: due to the way DokuWiki caches pages this plugin will report the date/time at which the cached version was created.  You would need to add ''%%~~NOCACHE~~%%'' to the page to ensure the date was current every time the page was requested.+===== Пример 2-й плагина — Color =====
  
-===== Sample Plugin 2 Color =====+Когда встретится синтаксическая конструкция плагина ''%%<color somecolour/somebackgroundcolour>%%'' встречается в статье вики, цвет текста сменяется на «somecolour», а цвет фона --- на «somebackgroundcolour»; и оба остаются такими, пока не встретится ''%%</color>%%''.
  
-When its syntax, ''%%<color somecolour/somebackgroundcolour>%%'', is encountered in a wiki page the text colour will be changed to somecolour, the background will be changed to somebackgroundcolour and both will remain that way until ''%%</color>%%'' is encountered.+  * Точто мы делаем, подобно тому, что делает состояние ''strong'', его тип --- 'formatting', поэтому мы тоже должны использовать этот тип. 
 +  * «allowedTypes» должны быть inline состояния - ''substition'', ''formatting'' и ''disabled''
 +  * PType --- ''normal'' --- это значение по умолчанию, поэтому нам снова не нужен метод ''getPType()''
 +  * Нам нужны входные и выходные шаблоны. Входной шаблон должен проверять, что есть и выходной шаблон, т. е. ''%%'<color.*>(?=.*?</color>)'%%''. Выходной шаблон аналогично  ''%%</color>%%''
 +  * Метод ''handle()'' должен иметь дело с тремя состояниями: совпадающими с входным и выходным шаблонами и «несовпадающим» для промежуточного текста.  
 +    * Состояние ''DOKU_LEXER_ENTER'' требует некоторой обработки для извлечения значений цветов текста и фона, они войдут в инструкцию для нашего рендера. 
 +    * Состояние ''DOKU_LEXER_UNMATCHED'' не требует какой-либо обработки, но нам придётся передать «несовпадающий» текст (в параметре ''$match'') методу ''render()'', поэтому он войдёт в инструкцию для нашего рендера. 
 +    * Состояние ''DOKU_LEXER_EXIT'' не требует какой-либо обработки и не имеет никаких особых данных, мы просто должны сделать выходную инструкцию для ''render()''
 +  * Методу ''render()'' необходимо иметь дело с теми же тремя сотояниями, что и ''handle()''
 +    * ''DOKU_LEXER_ENTER'' --- отрыть тэг ''span'' с указанием стиля, использующего значения цветов текста и фона. 
 +    * ''DOKU_LEXER_UNMATCHED'' --- добавить «несовпавший» текст к выходному документу. 
 +    * ''DOKU_LEXER_EXIT'' --- закрыть тэг ''span''.
  
-  * what we are doing is similar to the strong modeits type is 'formatting' so we should use that type too. +Опять жевсё достаточно очевидноИ вотчто мы имеем:
-  * allowedTypes should be the inline modes - ''substition''''formatting'' & ''disabled''+
-  * PType is ''normal'', that's the default value, so again we don't need a ''getPType()'' method. +
-  * we need to use an entry and exit pattern.  The entry pattern should check to make sure there is an exit pattern, which means ''%%'<color.*>(?=.*?</color>)'%%''. The exit pattern is simpler, ''%%</color>%%''+
-  * the ''handle()'' method will need to deal with three states matching our entry and exit patterns and unmatched for the text which occurs between them. +
-    * ''DOKU_LEXER_ENTER'' state requires some processing to extract the colour and background colour values, they make up our render instruction. +
-    * ''DOKU_LEXER_UNMATCHED'' state doesn't require any processing, but we have to pass the unmatched text (in ''$match'') to ''render()'' so that goes into our render instruction. +
-    * ''DOKU_LEXER_EXIT'' state doesn't require any processing or have any special data, we simply need to generate an exit instruction for ''render()''+
-  * the ''render()'' method will need to deal with the same three states as ''handle()''+
-    * ''DOKU_LEXER_ENTER'', open a span with a style using the colour and/or background colour values. +
-    * ''DOKU_LEXER_UNMATCHED'', add the unmatched text to the output document. +
-    * ''DOKU_LEXER_EXIT'', close the span+
  
-Put the file syntax.php from below into a folder named "color" directly below your plugins folder, e.g. /srv/www/htdocs/dokuwiki/lib/plugins. If you do not name this folder "color", the plugin will not work: 
 <code php syntax.php> <code php syntax.php>
 <?php <?php
Строка 466: Строка 385:
 // must be run within Dokuwiki // must be run within Dokuwiki
 if(!defined('DOKU_INC')) die(); if(!defined('DOKU_INC')) die();
 +
 +if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
 +require_once(DOKU_PLUGIN.'syntax.php');
  
 /** /**
Строка 473: Строка 395:
 class syntax_plugin_color extends DokuWiki_Syntax_Plugin { class syntax_plugin_color extends DokuWiki_Syntax_Plugin {
  
-    public function getType(){ return 'formatting';+    /** 
-    public function getAllowedTypes() { return array('formatting', 'substition', 'disabled'); }    +     * return some info 
-    public function getSort(){ return 158; } +     */ 
-    public function connectTo($mode) { $this->Lexer->addEntryPattern('<color.*?>(?=.*?</color>)',$mode,'plugin_color');+    function getInfo(){ 
-    public function postConnect() { $this->Lexer->addExitPattern('</color>','plugin_color'); }+        return array( 
 +            'author' => 'Christopher Smith', 
 +            'email'  => 'chris@jalakai.co.uk', 
 +            'date'   => '2008-02-06', 
 +            'name'   => 'Color Plugin', 
 +            'desc'   => 'Changes text colour and background', 
 +            'url'    => 'http://www.dokuwiki.org/plugin:tutorial', 
 +        ); 
 +    } 
 + 
 +    function getType(){ return 'formatting';
 +    function getAllowedTypes() { return array('formatting', 'substition', 'disabled'); }    
 +    function getSort(){ return 158; } 
 +    function connectTo($mode) { $this->Lexer->addEntryPattern('<color.*?>(?=.*?</color>)',$mode,'plugin_color');
 +    function postConnect() { $this->Lexer->addExitPattern('</color>','plugin_color'); }
  
  
Строка 483: Строка 419:
      * Handle the match      * Handle the match
      */      */
-    public function handle($match, $state, $pos, Doku_Handler $handler){+    function handle($match, $state, $pos, &$handler){
         switch ($state) {         switch ($state) {
           case DOKU_LEXER_ENTER :           case DOKU_LEXER_ENTER :
Строка 500: Строка 436:
      * Create output      * Create output
      */      */
-    public function render($formatDoku_Renderer $renderer, $data) { +    function render($mode&$renderer, $data) { 
-        // $data is what the function handle() return'ed. +        if($mode == 'xhtml'){
-        if($format == 'xhtml'){ +
-            /** @var Doku_Renderer_xhtml $renderer */+
             list($state,$match) = $data;             list($state,$match) = $data;
             switch ($state) {             switch ($state) {
-                case DOKU_LEXER_ENTER :       +              case DOKU_LEXER_ENTER :       
-                    list($color, $background) = $match; +                list($color, $background) = $match; 
-                    $renderer->doc .= "<span style='$color $background'>";  +                $renderer->doc .= "<span style='$color $background'>";  
-                    break;+                break;
                                  
-                case DOKU_LEXER_UNMATCHED :   +              case DOKU_LEXER_UNMATCHED :  $renderer->doc .= $renderer->_xmlEntities($match); break; 
-                    $renderer->doc .= $renderer->_xmlEntities($match);  +              case DOKU_LEXER_EXIT :       $renderer->doc .= "</span>"; break;
-                    break; +
-                case DOKU_LEXER_EXIT :        +
-                    $renderer->doc .= "</span>";  +
-                    break;+
             }             }
             return true;             return true;
Строка 523: Строка 453:
     }     }
          
-    /** +    // validate color value $c 
-     * Validate color value $c +    // this is cut price validation - only to ensure the basic format is correct and there is nothing harmful 
-     * this is cut price validation - only to ensure the basic format is correct and there is nothing harmful +    // three basic formats  "colorname", "#fff[fff]", "rgb(255[%],255[%],255[%])" 
-     * three basic formats  "colorname", "#fff[fff]", "rgb(255[%],255[%],255[%])" +    function _isValid($c) {
-     */ +
-    private function _isValid($c) {+
         $c = trim($c);         $c = trim($c);
                  
Строка 542: Строка 470:
     }     }
 } }
 +?>
 </code> </code>
  
-NoteNo checking is done to ensure colour names are valid or RGB values are within correct ranges. +Замечаниеникаких проверок на корректность названий цветов или значения RGB не производилось.
- +
-===== Unit Testing Syntax Plugins ===== +
- +
-For a general introduction about Unit Testing in DokuWiki please see [[devel:unittesting]]. For a syntax plugin a common test goal will be to ensure that a certain wiki code produces the expected XHTML code or other destination language code. +
- +
-The following example function shows a simple way to do this: +
- +
-<code php> +
-    public function test_superscript() { +
-        $info = []; +
-        $expected = "\n<p>\nThis is <sup>superscripted</sup> text.<br />\n</p>\n"; +
- +
-        $instructions = p_get_instructions('This is ^^superscripted^^ text.'); +
-        $xhtml = p_render('xhtml', $instructions, $info); +
- +
-        $this->assertEquals($expected, $xhtml); +
-    } +
-</code> +
- +
-Here we strongly benefit from DokuWiki's good design. The two function calls to ''p_get_instructions()'' and ''p_render()'' are enough to render the example code ''%%//'This is ^^superscripted^^ text.'//%%'' and store the result in the variable **$xhtml**. Finally we only need a simple assert to check if the result is what we **$expected**.+
  
 =====Дополнения и Файлы===== =====Дополнения и Файлы=====
 [[https://www.dokuwiki.org/devel:syntax_plugins|Ссылка на оригинал статьи]] [[https://www.dokuwiki.org/devel:syntax_plugins|Ссылка на оригинал статьи]]
wiki/devel/syntax_plugins.1736418723.txt.gz · Последнее изменение: vladpolskiy