В Atlassian Confluence есть замечательный функционал сравнения версий страницы. Им удобно пользоваться, но выйти за пределы истории изменений не удастся. Как же быть? Поиск готового плагина в Marketplace результатов не дал и было принято решение написать свой.
Нам понадобятся:
Установим SDK и выполним скрипт
Вводим:
Для сборки можно воспользоваться maven-ом и зависимостями из SDK, но проще подключить дополнительные репозитории в своем settings.xml.
Откроем получившийся проект в IDE, запустим Confluence в режиме отладки
и проверим работу локальной установки по адресу http://localhost:1990/confluence/. Логин admin, пароль admin. В базе уже создано демонстрационное пространство и несколько статей.
Начнем с меню. Добавим в дескриптор плагина atlassian-plugin.xml модуль web-item.
Где:
Добавляем в diff-page.properties строку:
Если нужна поддержка переводов — создадим дополнительные property, например, для русской локализации файл будет называться diff-page_ru_RU.properties.
Выполним
Для выбора страницы удобно использовать модальное окно. Продолжим править atlassian-plugin.xml
Добавим немного ресурсов:
Где:
Определим обработчики наших url-ов:
Где:
Создадим новый пакет com.kshch.confluence.plugins.diff.page.action и добавим в него класс DiffPagePopupAction, расширяющий ConfluenceActionSupport с 2-мя полями.
Сгенерируем к ним геттеры и сеттеры. В поле spaceKey будет содержаться ключ текущего пространства, а в sourcePageId — id текущей страницы.
Займемся фронтом. Для создания всплывающего окна воспользуемся элементом dialog2 из фреймворка AUI.
Добавим в диалог форму, кнопку submit и input-ы с css классами autocomplete-space и autocomplete-page, что позволит без дополнительных усилий организовать выбор пространства и страницы. Сохраним полученный результат в /templates/diff-page-popup.vm.
Для отображения окна создадим в ресурсах /js/diff-page-popup.js со следующим содержимым:
Его задача переопределить стандартное событие click и показать нам всплывающее окно, а не осуществить переход по ссылке.
Выполним
Приступим к реализации основного функционала. Добавим в пакет com.kshch.confluence.plugins.diff.page.action еще один класс DiffPageAction, расширяющий ConfluenceActionSupport и реализующий интерфейс PageAware со следующими полями.
Где:
Сгенерируем геттеры и сеттеры, реализуем все методы, кроме getPage, как предлагает IDE по умолчанию. В полях sourcePageId, spaceKey и destinationPageName будут содержаться данные, которые пришли из формы внутри dialog2.
Переопределим метод execute своим. Именно в нем и заключена основная логика работы плагина.
Остается реализовать frontend сравнения 2-х страниц. Он гораздо проще всплывающего окна.
Создадим в ресурсах /templates/diff-page.vm. В нем, кроме верстки, реализуем простейшую проверку на ошибки.
Написание плагина закончено. Еще раз выполним
Полный код проекта доступен на GitHub.
Инструменты
Нам понадобятся:
- Oracle JDK или AdoptOpenJDK 1.8, работа с OpenJDK официально не поддерживается;
- Atlassian SDK — можно скачать с официального сайта для Windows и Linux/Mac без СМС и регистрации;
- Apache Maven;
- Любимая среда разработки, у меня IntelliJ IDEA.
Создадим проект
Установим SDK и выполним скрипт
atlas-create-confluence-plugin
.Вводим:
- group-id: com.kshch.confluence.plugins
- artifact-id: diff-page
- version: 1.0.0-SNAPSHOT
- package: com.kshch.confluence.plugins.diff.page
Для сборки можно воспользоваться maven-ом и зависимостями из SDK, но проще подключить дополнительные репозитории в своем settings.xml.
<repository>
<id>atlassian-public</id>
<url>https://packages.atlassian.com/maven/repository/public</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
</repository>
<pluginRepository>
<id>atlassian-public</id>
<url>https://maven.atlassian.com/repository/public</url>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<updatePolicy>never</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</pluginRepository>
Откроем получившийся проект в IDE, запустим Confluence в режиме отладки
confluence:debug
и проверим работу локальной установки по адресу http://localhost:1990/confluence/. Логин admin, пароль admin. В базе уже создано демонстрационное пространство и несколько статей.
Немного функционала
Начнем с меню. Добавим в дескриптор плагина atlassian-plugin.xml модуль web-item.
<web-item key="diff-page-menu" name="Diff Page" section="system.content.action/secondary" weight="300">
<description>Add diff item to drop-down menu</description>
<label key="diff.page.menu.name"/>
<link linkId="diff-page">/plugins/diffPage/diffPagePopup.action?spaceKey=${space.key}&sourcePageId=${page.id}</link>
<condition class="com.atlassian.confluence.plugin.descriptor.web.conditions.HasPageCondition"/>
</web-item>
Где:
- атрибут section — определяет место появления пункта меню;
- атрибут weight — отвечает за порядок сортировки;
- атрибут key тега label — ключ, по которому в файлах ресурсов находится название отображаемого пункта меню;
- тег link — содержит ссылку, а атрибут linkId ее id;
- condition — определяет условие появления, в нашем случае только на страницах.
Добавляем в diff-page.properties строку:
diff.page.menu.name=Diff page
Если нужна поддержка переводов — создадим дополнительные property, например, для русской локализации файл будет называться diff-page_ru_RU.properties.
Выполним
maven package
. Плагин будет автоматически перезагружен и появится наш пункт меню.Модальное окно
Для выбора страницы удобно использовать модальное окно. Продолжим править atlassian-plugin.xml
Добавим немного ресурсов:
<web-resource key="diff-page-popup-resources" name="diff-page Popup Web Resources">
<dependency>com.atlassian.auiplugin:ajs</dependency>
<dependency>com.atlassian.auiplugin:dialog2</dependency>
<resource type="download" name="diff-page-popup.js" location="/js/diff-page-popup.js"/>
<context>page</context>
</web-resource>
Где:
- тег dependency — зависимость;
- в атрибутах resource указаны тип ресурса, имя и расположение на файловой системе;
- тег context — определяет видимость в зависимости от контекста.
Определим обработчики наших url-ов:
<xwork name="Diff Page Action" key="diff-page-action">
<description>Diff page action</description>
<package name="diff-page-package" extends="default" namespace="/plugins/diffPage">
<default-interceptor-ref name="defaultStack"/>
<action name="diffPage"
class="com.kshch.confluence.plugins.diff.page.action.DiffPageAction">
<result name="success" type="velocity">/templates/diff-page.vm</result>
</action>
<action name="diffPagePopup"
class="com.kshch.confluence.plugins.diff.page.action.DiffPagePopupAction">
<result name="success" type="velocity">/templates/diff-page-popup.vm</result>
</action>
</package>
</xwork>
Где:
- атрибут name тега action — определяет название ссылки, а class — java class для ее обработки;
- тег result — содержит ссылку на шаблон, в нашем случае velocity.
Создадим новый пакет com.kshch.confluence.plugins.diff.page.action и добавим в него класс DiffPagePopupAction, расширяющий ConfluenceActionSupport с 2-мя полями.
private String spaceKey;
private Long sourcePageId;
Сгенерируем к ним геттеры и сеттеры. В поле spaceKey будет содержаться ключ текущего пространства, а в sourcePageId — id текущей страницы.
Займемся фронтом. Для создания всплывающего окна воспользуемся элементом dialog2 из фреймворка AUI.
Добавим в диалог форму, кнопку submit и input-ы с css классами autocomplete-space и autocomplete-page, что позволит без дополнительных усилий организовать выбор пространства и страницы. Сохраним полученный результат в /templates/diff-page-popup.vm.
<section role="dialog" id="diff-page-popup" class="aui-layer aui-dialog2 aui-dialog2-medium" aria-hidden="true"
data-aui-remove-on-hide="true">
<form action="$action.getBootstrapManager().getWebAppContextPath()/plugins/diffPage/diffPage.action" method="get" class="aui">
...
<input type="hidden" name="sourcePageId" value="$action.getSourcePageId()">
<input class="text autocomplete-space" type="text" id="diff-page-space"
name="spaceKey" data-max="10" data-none-message="$action.getText("diff.page.popup.no.result")"
placeholder="$action.getText("diff.page.popup.select.space")" value="$action.getSpaceKey()" data-template="{key}">
<input type="text" class="text autocomplete-page" name="destinationPageName" data-max="10"
placeholder="$action.getText("diff.page.popup.select.page")" data-none-message="$action.getText("diff.page.popup.no.result")">
<button id="dialog-diff-button" class="aui-button aui-button-primary">$action.getText("diff.page.popup.diff")</button>
...
</form>
</section>
Для отображения окна создадим в ресурсах /js/diff-page-popup.js со следующим содержимым:
(function ($) {
$(function () {
AJS.$('#diff-page').unbind('click');
AJS.$('#diff-page').bind("click", function (e) {
e.preventDefault();
var link = AJS.$(this);
AJS.$.get(link.attr('href'), function (response) {
AJS.$('.aui-page-panel').after(response);
AJS.dialog2("#diff-page-popup").show();
Confluence.Binder.autocompletePage(AJS.$("#diff-page-popup-binder"));
});
return false;
});
});
})(AJS.$);
Его задача переопределить стандартное событие click и показать нам всплывающее окно, а не осуществить переход по ссылке.
Выполним
maven package
и попробуем выбрать страницу и пространство. Подсказчик активируется после набора 2-х символов.Основной функционал
Приступим к реализации основного функционала. Добавим в пакет com.kshch.confluence.plugins.diff.page.action еще один класс DiffPageAction, расширяющий ConfluenceActionSupport и реализующий интерфейс PageAware со следующими полями.
private Long sourcePageId;
private Long destinationPageId;
private String spaceKey;
private String destinationPageName;
private String sourcePageTitle;
private String destinationPageTitle;
private String diff;
private Page sourcePage;
private Differ differ;
private final PageManager pageManager;
Где:
- sourcePageId — id исходной страницы;
- destinationPageId — id сравниваемой страницы;
- spaceKey — ключ пространства;
- destinationPageName — имя сравниваемой страницы;
- sourcePageTitle — заголовок исходной страницы;
- destinationPageTitle — заголовок сравниваемой страницы;
- diff — результат сравнения.
Сгенерируем геттеры и сеттеры, реализуем все методы, кроме getPage, как предлагает IDE по умолчанию. В полях sourcePageId, spaceKey и destinationPageName будут содержаться данные, которые пришли из формы внутри dialog2.
@Override
public AbstractPage getPage() {
return this.sourcePage;
}
Переопределим метод execute своим. Именно в нем и заключена основная логика работы плагина.
@Override
public String execute() throws Exception {
if (this.sourcePageId != null && this.spaceKey != null && this.destinationPageName != null) {
this.sourcePage = this.pageManager.getPage(this.sourcePageId);
Page destinationPage = this.pageManager.getPage(this.spaceKey, this.destinationPageName);
if (this.sourcePage != null && destinationPage != null) {
this.destinationPageId = destinationPage.getId();
this.sourcePageTitle = this.sourcePage.getTitle();
this.destinationPageTitle = destinationPage.getTitle();
this.diff = this.differ.diff(this.sourcePage, destinationPage);
}
}
return super.execute();
}
Остается реализовать frontend сравнения 2-х страниц. Он гораздо проще всплывающего окна.
Создадим в ресурсах /templates/diff-page.vm. В нем, кроме верстки, реализуем простейшую проверку на ошибки.
#if ($action.getDiff())
#diffBody()
#else
<div class="aui-message aui-message-error">
<p class="title">
<strong>$action.getText("diff.page.error")</strong>
</p>
<p>$action.getText("diff.page.error.message")</p>
</div>
#end
Написание плагина закончено. Еще раз выполним
maven package
, выберем страницу и насладимся полученным результатом.Полный код проекта доступен на GitHub.
gonchik
Спасибо за статью! Будут ли ещё продолжения?