Pull to refresh

Как написать плагин для TiddlyWiki

Reading time6 min
Views7.1K
TiddlyWiki — очень хорошая штука и я давно ею пользуюсь. Тем не менее, некоторых вещей в ней нет, и это минус. Но её можно творчески допилить напильником, и это плюс.

Понадобился мне прогрессбар. Применений у него куча: показывать степень готовности поста, например. Или количество выполненных дел по сравнению с оставшимися. Да и вообще, наглядная штука.

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

  • цвет заполнения;
  • размер;
  • подсказку при наведении.

Если какой-то параметр не задан, то он должен вычисляться автоматически.

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

В рамках эксперимента, я набросал пробный макрос, выводящий прогрессбар:

\define progressbar(count:"0" total:"10")
<svg width="$total$5" height="15">
<g>
<title>$count$ из $total$</title>
<rect x="1.5" y="4.5" height="10" width="$count$0" rx="3" ry="3" style="fill: green; stroke: none" />
<rect x="1.5" y="4.5" height="10" width="$total$0" rx="3" ry="3" style="fill: none; stroke: green" />
</g>
</svg>
\end

В том же тиддлере (так в TiddlyWiki называется фрагмент текста) дописал внизу вызов этого макроса:

Прогрессбар: <<progressbar 3 4>>

Сохранил тиддлер и полюбовался результатом:

image

Схема оказалась принципиально рабочей. Но имела кучу несоответствий исходным требованиям. И исправить это было пока нельзя из-за крайней ограниченности создания макросов с помощью формата WikiText. Пришлось разбираться дальше.

В документации обнаружилось упоминание, что макросы можно писать и на JavaScript. Для этого тиддлер макроса должен содержать поле module-type со значением macro (поля в TiddlyWiki представляют собой метаданные и могут назначаться любому тиддлеру). Скрипт макроса должен экспортировать следующие свойства:

  • name: Строка, представляющая собой имя, по которому будут вызывать макрос
  • params: Массив объектов со следующими свойствами:
    • name: имя параметра
    • default: (необязательно) значение параметра по умолчанию
  • run: Функция, которая будет вызываться при запуске макроса. Параметры извлекаются из вызова макроса и располагаются согласно массиву params. Функция run должна вернуть строковое значение макроса. При вызове this указывает на узел виджета, вызвавшего макрос.

Если массив params пуст или отсутствует, то все параметры будут просто переданы в метод run().

Это уже было хорошо. Но в TiddlyWiki нельзя просто взять и сделать тиддлер с куском JavaScript-а. Вернее, можно, но работать не будет. Чтобы конструкция заработала, её следует надлежащим образом оформить. Например, сделать плагин.

Что есть плагин в терминологии TiddlyWiki? Это некая совокупность тиддлеров, собранная в единое целое, которая помечена как скрытая и не отображается в обычном списке тиддлеров, может встраиваться в систему и запускаться на выполнение, а также может импортироваться из одной wiki в другую парой щелчков.

Первоначально для написания плагинов требовалось развернуть довольно сложную инфраструктуру с использованием node.js. Я когда-то пробовал это делать, но не получилось (не помню уже, по какой причине). Однако, на данный момент разработчик добавил возможность писать плагины прямо в браузере, чем я воспользовался и сейчас расскажу вам, как это делается.

Итак, уважаемые читатели, давайте приступим к созданию плагина. Сверяясь с документацией, скачаем чистый файл TiddlyWiki и начнём делать из него заготовку для плагина.

Первое, что надо сделать, это создать тиддлер HelloThere, настроить его автоматическое отображение при открытии страницы и прописать в нём ссылки на тиддлеры плагина.

Путь к плагину, согласно документации, должен выглядеть так:

$:/plugins/ваше_имя/название_плагина

Путь к скриптам, входящим в плагин, формируется подобным же образом:

$:/plugins/ваше_имя/название_плагина/имя_скрипта.js

Вот так выглядит мой вариант тиддлера HelloThere:

* [[$:/plugins/morthan/progress]]
* [[$:/plugins/morthan/progress/progressbar.js]]

Прогрессбар получает следующие параметры:

; `count`
: Количество выполненного
; `total`
: Количество всего
; `width`
: Если указано --- длина прогрессбара в пикселях
; `color`
: Цвет заполнения (стандартно --- зелёный)
; `title`
: Подсказка, которая выводится при наведении мыши (по умолчанию --- '{count} из {total}')

<<progressbar 30 42 80>>

А это он же в отрисованном виде:

image

Стоит обратить внимание на две вещи. Во-первых, ссылки даны курсивом, потому что ни плагина, ни скрипта, входящего в его состав, пока не существует. Во-вторых, прогрессбар тоже пока не отрисован — по той же причине.

Чтобы настроить автоматическое отображение тиддлера при открытии страницы надо добавить его в список Default tiddlers. Его можно обнаружить либо в открывающемся по умолчанию тиддлере GettingStarted, либо найти в сайдбаре пиктограмму в виде шестерёнки и нажать её. В появившейся панели настроек ищем Default tiddlers и прописываем туда наш HelloThere.

image

Всё, первая часть готова. Теперь надо создать тиддлеры плагина и скрипта. Начнём с плагина.

Чтобы создать тиддлер, достаточно щёлкнуть по ссылке на него. Появляется заготовка тиддлера, нажимаем «Редактировать» и редактируем.

Как подсказывает документация, в плагине должны быть прописаны такие поля:
Поле Значение
dependents Список разделённых пробелами плагинов, от которых зависит наш плагин
(для названий с пробелами используйте квадратные скобки)
description Описание плагина
plugin-type Для обычного плагина «plugin», для темы «theme», а для языкового пакета «language»
type Задайте «application/json»
version Номер версии плагина (например, «0.0.1»)
Заполняем поля, а в теле плагина пишем:

{"tiddlers": {}}

image

Сохраняем тиддлер. Треть работы выполнена.

Аналогичным образом поступаем со второй ссылкой, скриптом макроса. Щёлкаем по ней, нажимаем «Редактировать», заполняем поля:
Поле Значение
type «application/javascript»
module-type «macro»
Теперь само тело скрипта (под спойлером):

Показать код
/*\
title: $:/plugins/morthan/progress/progressbar.js
type: application/javascript
module-type: macro

Macro to display progressbar

\*/
(function(){

/*jslint node: true, browser: true */
/*global $tw: false */
"use strict";

/*
Information about this macro
*/

exports.name = "progressbar";

exports.params = [
    {name: "count"},
    {name: "total"},
    {name: "width",
     default: ""},
    {name: "color",
     default: "green"},
    {name: "title",
     default: "{count} из {total}"}
];

/*
Run the macro
*/
exports.run = function(count, total, width, color, title) {
    count = parseInt(count);
    total = parseInt(total);
    width = (width == '') ? total * 10 : parseInt(width);
    var html = [svg(width), '<g>', tagTitle(count, total, title),
        innerRect(count, total, width, color), outerRect(width), '</g>',
        '</svg>'];
    return html.join("\n");
};

function svg(width) {
    width += 5;
    return '<svg width="' + width + '" height="15">';
};

function rect(width, fill) {
    return '<rect x="1.5" y="4.5" height="10" width="' + width +
        '" rx="3" ry="3" style="fill: ' + fill + '; stroke: green" />';
};

function outerRect(width) {
    return rect(width, 'none');
};

function innerRect(count, total, width, color) {
    var dx = 0;
    if (count > 0 && count != total) {
        dx = count * width / total;
    }
    else if (count == total) {
        dx = width;
    }
    return rect(dx, color);
};

function tagTitle(count, total, title) {
    if (title == '') return '';
    return '<title>' + title.replace('{count}', count).replace('{total}', total) + '</title>';
};

})();


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

В общем, сохраняем готовый тиддлер. Всё, что нужно, уже написано. Но не работает, потому что не оформлено.

А сейчас — магия! Открываем консоль JavaScript в браузере и пишем там вот что:

$tw.utils.repackPlugin('$:/plugins/morthan/progress', ['$:/plugins/morthan/progress/progressbar.js'])

Первый аргумент это имя плагина, который подлежит перепаковке. Второй — список тиддлеров, которые будут включены в плагин. Нажимаем Enter. Браузер говорит, что всё прошло успешно и для того, чтобы изменения возымели действие, надо сохранить и перезагрузить wiki.

Так и сделаем. После переоткрытия в тиддлере HelloThere внезапно появляется красивый зелёненький прогрессбар.

Заключение


В новой версии TiddlyWiki появилась возможность писать плагины прямо не выходя из бассейна браузера. Это позволяет творчески доработать систему под себя, открывает неограниченные горизонты и ещё на один маленький шаг приближает нас к мировому господству.

PS: не уверен в правильности выбора хабов, ибо не совсем понимаю, зачем они нужны. Если что-то сделал неправильно, буду благодарен за разъяснения в комментариях.
Tags:
Hubs:
Total votes 9: ↑9 and ↓0+9
Comments4

Articles