Создание плагина. От идеи до публикации. Часть 1.
Плагин, создание которого я опишу уже в каталоге и ссылка на него будет в самоом конце.
Идея плагина заключается в следующем: предоставить пользователю возможность добавлять в топик карусель, предоставляемую фреймворком Twitter Bootstrap. Добавление карусели будет осуществляться через встроенный редактор, для карусели будут доступны как изображения из сети, так и загруженные с компьютера пользователя.

Файл содержит шесть основных секций, носящих скорее описательный характер, эти секции:
1. name: наименование плагина (используется как поле для сортировки плагинов в полном их и в tpl );
2. author: имя автора плагина (используется только в tpl);
3. homepage: домашняя страница плагина (используется только в tpl);
4. version: версия плагина (используется только в tpl);
5. requires: требования, которым должна удовлетворять платформа для того, что бы плагин успешно мог функционировать, в нашем случае указываем только версию livestreet – 1.x. (используется при проверке возможности установки плагина, возможен доступ из tpl, хотя в стандартных шаблонах не используется);
6. description: описание плагина. Заметьте, что теги описания содержат атрибут lang, указывающий язык приведенных данных (используется только в tpl).
В приведенном примере не указана секция settings, которая определяет страницу настроек плагина, но она будет рассмотрена далее. Представленная структура файла является типовой и с небольшими изменениями используется во всех плагинах, но для более полного изучения структуры Вы можете посмотреть метод GetList класса ModulePlugin, реализованного в файле Plugin.class.php и plugin.tpl любого шаблона – отвечающий за вывод страницы админки со списком плагинов.
Вот теперь мы создали минимально-необходимый набор файлов (один), для того, что бы плагин отобразился в системе, однако для того, что бы была возможность его активировать и, собственно, полноценно работать нужно создать основной класс плагинов, от которого будут создаваться его экземпляры.
Перед объявлением класса запрещаем прямой доступ к файлу. В архитектуре LS, работа с плагинами реализуется через класс Plugin (еще раз скажу, что они от него наследуются) и поэтому логично сделать проверку на наличие родительского класса. И ниже – сам класс плагина, в теле метода инициализации плагина первой строкой указан вызов родительского метода инициализации, его можно не указывать поскольку родительский метод пуст, но для красоты кода и как задел на будущее (вдруг разработчики LS придумают инициализацию родителя, или Ваш проект этого потребует) — оставим.
Теперь плагин можно активировать/деактивировать!
Для того, что бы добавлять слайдер-карусель в текст создаваемого топика необходимо добавить кнопку в редакторе и… навязать на нее соответствующий функционал. Настройки самого редактора хранятся в файле, находящимся тут: engine/lib/internal/template/js/settings.js. В этом файле создается объект ls.settings, который имеет метод получения натроек – getMarkitup(). Разумеется, мы не станем трогать файлы движка и реализуем добавление кнопки в плагине. Делается это так:
Объект ls.settings, уже существует до инициализации плагина, поэтому мы можем переопределить его родной метод получения настроек на необходимый нам, тот, который будет добавлять заветную кнопочку. В корневой папке плагина создадим папку js с файлом carouselScript.js, содержащий следующий код:
Подход, который здесь использован довольно простой: во временную переменную newMarkitupSettings мы сохраняем текущие настройки редактора, а затем переопределяем функцию получения настроек ls.settings.getMarkitup() собственной, в которой мы добавляем разделитель и новую кнопку. Если с разделителем все ясно, то новая кнопка задается объектом, свойства которого и определяют параметры создаваемой кнопки:
— className: класс CSS для текущей кнопки;
— key: Горячая клавиша, используется в комбинации с Ctrl;
— openWith: открывающий тег;
— closeWith: закрывающий тег;
— beforeInsert: функция, выполняющаяся до окружения выделенного текста указанными выше тегами openWith и closeWith.
И на последок, для того, что бы все заработало, необходимо подключить созданные файлы скриптов к LS. Сделаем это в методе init нашего плагина как указано в коде ниже.
С помощью метода AppendScript файлы скрипта, переданные в параметре метода, добавляются в очередь на подключение инструментами движка LS. Каждый раз при инициализации плагина будет выполняться подключение созданных скриптов которые, в свою очередь, будут расширять настройки редактора. Если в Вашем проекте используется TinyMCE, то указанные действия необходимо будет осуществить для метода получения настроек TinyMCE – getTinymce(), расположенном в том же файле: engine/lib/internal/template/js/settings.js.

После всех вышеприведенных действий получим следующую структуру каталогов и файлы в них. Кнопка в редакторе появилась, но на ней нет картинки и она сразу не заметна, поищите ее)
В настройках добавляемой кнопки мы определили ее класс, теперь, создадим файл style.css в каталоге styles, находящегося в корне плагина со следующим содержанием:
Для того, что бы файл каскадных стилей был доступен его необходимо подключить. Опять же, в методе init нашего плагина добавим следующую строчку кода ниже строк подключения скриптов:

Первый этап создания плагина пройден. Вспомним еще раз, что было сделано:
1. Создана структура каталогов плагина;
2. Создан файл plugin.xml с описанием создаваемого плагина;
3. На панель редактора добавлена кнопка, создающая в тексте тег пару тегов «carousel».
Идея плагина заключается в следующем: предоставить пользователю возможность добавлять в топик карусель, предоставляемую фреймворком Twitter Bootstrap. Добавление карусели будет осуществляться через встроенный редактор, для карусели будут доступны как изображения из сети, так и загруженные с компьютера пользователя.
Приступим
В начале создадим в папке plugins папку для нашего плагина с именем carousel и в нем файл plugin.xml c описанием создаваемого плагина (см. картинку ниже).
Файл содержит шесть основных секций, носящих скорее описательный характер, эти секции:
1. name: наименование плагина (используется как поле для сортировки плагинов в полном их и в tpl );
2. author: имя автора плагина (используется только в tpl);
3. homepage: домашняя страница плагина (используется только в tpl);
4. version: версия плагина (используется только в tpl);
5. requires: требования, которым должна удовлетворять платформа для того, что бы плагин успешно мог функционировать, в нашем случае указываем только версию livestreet – 1.x. (используется при проверке возможности установки плагина, возможен доступ из tpl, хотя в стандартных шаблонах не используется);
6. description: описание плагина. Заметьте, что теги описания содержат атрибут lang, указывающий язык приведенных данных (используется только в tpl).
В приведенном примере не указана секция settings, которая определяет страницу настроек плагина, но она будет рассмотрена далее. Представленная структура файла является типовой и с небольшими изменениями используется во всех плагинах, но для более полного изучения структуры Вы можете посмотреть метод GetList класса ModulePlugin, реализованного в файле Plugin.class.php и plugin.tpl любого шаблона – отвечающий за вывод страницы админки со списком плагинов.
Вот теперь мы создали минимально-необходимый набор файлов (один), для того, что бы плагин отобразился в системе, однако для того, что бы была возможность его активировать и, собственно, полноценно работать нужно создать основной класс плагинов, от которого будут создаваться его экземпляры.
Создание основного класса плагина
Основным классом плагина является файл с именем [PluginName]Plugin.class.php, в нашем случае CarouselPlugin.class.php, унаследованный от общего для всех плагинов класса Plugin, и содержащий один единственный (пока единственный) метод Init.<?php
if (!class_exists('Plugin')) {
die('You are bad hacker, try again, baby!');
}
class PluginCarousel extends Plugin {
/** Инициализация плагина */
public function Init() {
parent::Init();
}
}
Перед объявлением класса запрещаем прямой доступ к файлу. В архитектуре LS, работа с плагинами реализуется через класс Plugin (еще раз скажу, что они от него наследуются) и поэтому логично сделать проверку на наличие родительского класса. И ниже – сам класс плагина, в теле метода инициализации плагина первой строкой указан вызов родительского метода инициализации, его можно не указывать поскольку родительский метод пуст, но для красоты кода и как задел на будущее (вдруг разработчики LS придумают инициализацию родителя, или Ваш проект этого потребует) — оставим.
Теперь плагин можно активировать/деактивировать!
Добавление кнопки в редактор
Здесь и далее подразумевается, что в LS используется редактор Markitup!Для того, что бы добавлять слайдер-карусель в текст создаваемого топика необходимо добавить кнопку в редакторе и… навязать на нее соответствующий функционал. Настройки самого редактора хранятся в файле, находящимся тут: engine/lib/internal/template/js/settings.js. В этом файле создается объект ls.settings, который имеет метод получения натроек – getMarkitup(). Разумеется, мы не станем трогать файлы движка и реализуем добавление кнопки в плагине. Делается это так:
Объект ls.settings, уже существует до инициализации плагина, поэтому мы можем переопределить его родной метод получения настроек на необходимый нам, тот, который будет добавлять заветную кнопочку. В корневой папке плагина создадим папку js с файлом carouselScript.js, содержащий следующий код:
/** Получим текущие настройки редактора */
var newMarkitupSettings = ls.settings.getMarkitup();
ls.settings.getMarkitup = function() {
/** В текущий набор кнопок добавим еще одну, окружающую картинки тегом "<carousel>" */
newMarkitupSettings.markupSet = newMarkitupSettings.markupSet.concat([
{separator: '---------------'},
{
className : 'editor-carousel',
key : 'G',
openWith : '<carousel>',
closeWith : '</carousel>',
beforeInsert: function() {
}
}
]);
return newMarkitupSettings;
};
Подход, который здесь использован довольно простой: во временную переменную newMarkitupSettings мы сохраняем текущие настройки редактора, а затем переопределяем функцию получения настроек ls.settings.getMarkitup() собственной, в которой мы добавляем разделитель и новую кнопку. Если с разделителем все ясно, то новая кнопка задается объектом, свойства которого и определяют параметры создаваемой кнопки:
— className: класс CSS для текущей кнопки;
— key: Горячая клавиша, используется в комбинации с Ctrl;
— openWith: открывающий тег;
— closeWith: закрывающий тег;
— beforeInsert: функция, выполняющаяся до окружения выделенного текста указанными выше тегами openWith и closeWith.
И на последок, для того, что бы все заработало, необходимо подключить созданные файлы скриптов к LS. Сделаем это в методе init нашего плагина как указано в коде ниже.
class PluginCarousel extends Plugin {
/** Инициализация плагина */
public function Init() {
parent::Init();
/** Для добавления кнопки в редатктор запустим скрипт, корректирующий markitup */
$this->Viewer_AppendScript(dirname(__FILE__) . "/js/carouselScript.js");
}
}
С помощью метода AppendScript файлы скрипта, переданные в параметре метода, добавляются в очередь на подключение инструментами движка LS. Каждый раз при инициализации плагина будет выполняться подключение созданных скриптов которые, в свою очередь, будут расширять настройки редактора. Если в Вашем проекте используется TinyMCE, то указанные действия необходимо будет осуществить для метода получения настроек TinyMCE – getTinymce(), расположенном в том же файле: engine/lib/internal/template/js/settings.js.

После всех вышеприведенных действий получим следующую структуру каталогов и файлы в них. Кнопка в редакторе появилась, но на ней нет картинки и она сразу не заметна, поищите ее)
Стилизация кнопки
Добавим несколько штрихов к внешнему виду кнопки – добавим на нее изображение. Для этого изображение нужно найти и вопрос где? Я использую сервис Iconizer. Изображение должно быть 16px на 16px и после того как мы найдем нужное, скопируем его в созданную в корне плагина папку images.В настройках добавляемой кнопки мы определили ее класс, теперь, создадим файл style.css в каталоге styles, находящегося в корне плагина со следующим содержанием:
.editor-carousel {
background: url('../images/layers.png') no-repeat;
}
Для того, что бы файл каскадных стилей был доступен его необходимо подключить. Опять же, в методе init нашего плагина добавим следующую строчку кода ниже строк подключения скриптов:
/** Добавление стилей */
$this->Viewer_AppendStyle(dirname(__FILE__) ."/css/style.css");
Итоги

Первый этап создания плагина пройден. Вспомним еще раз, что было сделано:
1. Создана структура каталогов плагина;
2. Создан файл plugin.xml с описанием создаваемого плагина;
3. На панель редактора добавлена кнопка, создающая в тексте тег пару тегов «carousel».
21 комментарий
Добавление кнопки через плагин реализовано подменой функции getMarkitup так:
, потом к переменной newMarkitupSettings добавляются настройки новой кнопки. Как указано здесь, в этой статье. Но, так как переопределяемая getMarkitup — это именно функция, а не объект и возвращает рассчитанное значение. То есть без плагина getMarkitup срабатывает в момент вывода редактора и имеет доступ к массиву надписей, а с плагином — функция вызывается до загрузки надписей и, соответственно, доступа к ним не имеет. Для того что бы исправить ситуацию необходимо фрагмент кода, который указан выше:
Заменить на полный набор кнопок редактора, взятый из settings.js с добавлением кнопки карусели:
Такой подход мне кажется не очень правильным, поскольку мы убиваем исходную функцию, а в ней могут быть изменения. При использовании такого подхода следует учитывать особенности других плагинов и ранее внесенных в движок изменений. Более правильной реализации я пока не вижу, но и эта мне не нравиться, поэтому решил пожертвовать надписями.
Добавил две кнопки в начало таким способом.
смотрите код панели на странице
решение я предложил ниже
при этом еще myplug заменил на название плагина (хотя насколько понимаю это не обязательно). Кнопка не появляется.
Выводился он и при первоначальном виде добавления кнопки
когда иконка вставлена через ксс, выглядит так:
комментирую строку в ксс со вставкой иконки (т.е. в теории кнопка толжна быть невидима), кнопка работает, но дефект остается:
А в этом «правильном классе» поиграйте со значением css: background-position;
Эта точка — часть картинки, которую нужно сдвинуть в сторону или совсем убрать