libretki — это framework, призванный упростить создание userjs и предоставить уже готовый набор полезных функций.
Другие статьи серии:
Ядро системы представлено файлом libretki.core.js, который является развитием loader.js из второй статьи. Ядро также предоставляет некоторые базовые функции. Если все, что Вам нужно — это возможность подключать другие файлы, ядра достаточно.
Типовой скрипт с использованием libretki:
Теперь функция «func» доступна как «habrahabr.example.func». Объект «unsafe» используется как пространство имен для функций, которые небезопасно отдавать за пределы userjs, такие как доступ к файлам.
Набор мелких удобностей первой необходимости: работа с коллекциями (forEach, map, filter, …), с опциональными аргументами (optional), обновление объектов (modifyObject) и прочие полезности без особой направленности.
Используется почти всеми остальными скриптами.
Пример:
Удобная работа с cookies, вместо прямого обращения к document.cookies и парсинга результата предоставляет функции set, get и del.
Пример:
Сериализация и десериализация объектов в JSON-формат.
Пример:
Хранение объектов в cookies. Является простым объединением библиотек cookies и json и в принципе избыточна, но осталась по историческим причинам.
Пример:
Получение элементов и значений с использованием XPath. Является тонкой прослойкой над document.evaluate, но избавляет от запоминания специфичных констант и полей.
Пример:
Предоставляет функции для быстрого и удобного создания элементов, а также функции для модификации дерева («append», «prepend», «before», «after», …) и добавления/удаления классов.
Пример:
Анимация элементов. Создавалось для панели инструментов, поэтому пока содержит только анимации «fadeIn», «fadeOut» и «moveY».
Пример:
Общая панель инструментов, на которую каждый скрипт может добавлять свои кнопки. Панель инструментов показывается при наведении мыши на небольшой квадрат в левом верхнем углу страницы. Можно добавлять простые кнопки и кнопки-переключатели. Выглядит не очень — я не дизайнер, накидал какой-никакой градиент и дальше погрузился в код.

Пример:
Сервис — это код, который слушает и отвечает на XDM-сообщения. Сервисы необходимы для безопасного использования расширенных возможностей userjs с любой страницы.
На голом JavaScript сервис и использующий код выглядят так:
Сервис:
Использование:
Как видно, дело хлопотное и имеет ряд недостатков:
Все эти сложности libretki берет на себя.
Безопасное и удобное использование XDM. Позволяет по одному и тому же адресу организовать несколько сервисов, различая их по имени. Используется JSON для передачи объектов. Предотвращает доступ к сервису скриптам со страницы.
Классы:
Пример сервиса на Server/Channel:
клиента:
То же на SeqServer/SeqClient:
Ещё более упрощает задачу создания сервиса. Просто пишем:
, использование:
Значительно меньше кода по сравнению с начальным вариантом, не так ли? Теперь можно приняться и за создание полезных сервисов.
Позволяет сохранять данные, доступные с любой страницы. Реализовано с помощью сохранения cookies на странице 'http://0.0.0.0/'.
Пример:
Требует Java.
Пример:
Позволяет создавать, удалять и переименовывать файлы и папки, сканировать папки. Требует Java.
Пример:
Пример использования XMLHttpRequest приводить не буду, все как обычно, только использовать нужно «libretki.xmlhttprequest.XMLHttpRequest».
Эмуляция XMLHttpRequest сделана для упрощения адаптации чужого кода. Если Вы пишете userjs с нуля, намного удобнее функция «fetch»:
Этот набор скриптов упакован в отдельный архив. Отдельные скрипты описывать не буду, скажу только, что они помогают при работе в режиме показа кэшированных рисунков. Так как у меня канал узкий, я этим режимом пользуюсь постоянно. Можно различными способами загружать отдельные изображения – наведя на него мышь, удерживая клавишу нажатой, выделив область на экране, выделив кусок текста, загружать видимые в окне изображения и т.д.
В папке libretki/tools можно найти несколько инструментов, выполненных как HTML-страницы.
Интерфейс настройки параметров скриптов.
Настройте требуемые параметры и не забудьте нажать кнопку «Сохранить». Работает и без Java, но тогда Вам придется сохранить файл настроек вручную.

Список установленных userjs с возможностью включения и выключения. Можно использовать в качестве боковой панели браузера. Требует Java.

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

Скачать libretki можно на libretki.kriomant.net.
Установка пока достаточно сложна:
В папке «libretki/examples» есть примеры использования некоторых возможностей. Так как некоторые возможности специально скрыты от скриптов на странице, для работы соответствующих примеров необходимо поместить файл «libretki/examples/libretki.allow-unsafe.js» в папку скриптов.
В процессе написания находятся инсталляторы для Windows и Linux.
Во-первых требуется feedback. Анонсировал libretki на OperaFan, вроде сколько-то людей скачали, но ни одного отзыва не оставили. Выразите свое отношение:
Во-вторых, libretki нуждается в логотипе и дизайне сайта, я сам в этом деле ни в зуб ногой. Место и домен уже есть.
Другие статьи серии:
Ядро
Ядро системы представлено файлом libretki.core.js, который является развитием loader.js из второй статьи. Ядро также предоставляет некоторые базовые функции. Если все, что Вам нужно — это возможность подключать другие файлы, ядра достаточно.
Типовой скрипт с использованием libretki:
if (! ('libretki' in window)) { libretki = { __scripts: [] }; } libretki.__scripts.push({ name: 'habrahabr.example', requires: ['libretki.utilities'], init: function(unsafe) { // some code... libretki.core.namespace('habrahabr.example', { func: function() { /* ... */ }, }); } });
Теперь функция «func» доступна как «habrahabr.example.func». Объект «unsafe» используется как пространство имен для функций, которые небезопасно отдавать за пределы userjs, такие как доступ к файлам.
Библиотеки функций
Утилиты (libretki.utilities)
Набор мелких удобностей первой необходимости: работа с коллекциями (forEach, map, filter, …), с опциональными аргументами (optional), обновление объектов (modifyObject) и прочие полезности без особой направленности.
Используется почти всеми остальными скриптами.
Пример:
var positive = libretki.utilities.filter(arr, function(item) { return item.value > 0; }); libretki.utilities.forEach(positive, function(item) { item.func(); });
Управление cookies (libretki.cookies)
Удобная работа с cookies, вместо прямого обращения к document.cookies и парсинга результата предоставляет функции set, get и del.
Пример:
libretki.cookies.set('name', 'value'); var value = libretki.cookies.get('name');
JSON (libretki.json)
Сериализация и десериализация объектов в JSON-формат.
Пример:
var str = libretki.json.stringify({name: 'name', value: 'value', active: true}); var obj = libretki.json.parse(str);
Хранение объектов в cookies (libretki.cookies_json)
Хранение объектов в cookies. Является простым объединением библиотек cookies и json и в принципе избыточна, но осталась по историческим причинам.
Пример:
libretki.cookies_json.set('name', {value: 'value', active: true}); var obj = libretki.cookies_json.get('name');
XPath (libretki.xpath)
Получение элементов и значений с использованием XPath. Является тонкой прослойкой над document.evaluate, но избавляет от запоминания специфичных констант и полей.
Пример:
var nodes = libretki.xpath.getNodes(document.body, '//img[@class="adv"]'); var value = libretki.xpath.getNumber(tbody, 'tr/td[@id="header"]/@colspan');
Модификация документа с помощью DOM (libretki.visual.dom)
Предоставляет функции для быстрого и удобного создания элементов, а также функции для модификации дерева («append», «prepend», «before», «after», …) и добавления/удаления классов.
Пример:
var dom = libretki.visual.dom; dom.before(elem, dom.html.a({href: "http://...", className: "outlink"}, [ dom.html.img({src: "..."}), "link content" ]);
Анимация (libretki.visual.animation)
Анимация элементов. Создавалось для панели инструментов, поэтому пока содержит только анимации «fadeIn», «fadeOut» и «moveY».
Пример:
libretki.visual.animation.fadeOut(elem, {time: 500});
Общая панель инструментов (libretki.visual.toolbar)
Общая панель инструментов, на которую каждый скрипт может добавлять свои кнопки. Панель инструментов показывается при наведении мыши на небольшой квадрат в левом верхнем углу страницы. Можно добавлять простые кнопки и кнопки-переключатели. Выглядит не очень — я не дизайнер, накидал какой-никакой градиент и дальше погрузился в код.

Пример:
// Добавляем свою кнопку. libretki.toolbar.onShow(function(toolbar) { var group = new libretki.toolbar.ButtonsGroup("Example"); var button = new libretki.toolbar.CommandButton("Alert", "data:image/svg+xml;base64,...", function() { alert("Example"); }); group.addButton(button); toolbar.addGroup(group); });
Сервисы
Сервис — это код, который слушает и отвечает на XDM-сообщения. Сервисы необходимы для безопасного использования расширенных возможностей userjs с любой страницы.
На голом JavaScript сервис и использующий код выглядят так:
Сервис:
if (location.href == 'http://0.0.0.0/') { window.addEventListener('message', function(ev) { var fields = ev.data.split('|'); if (fields[0] == 'set') { // … ev.source.postMessage('ok'); } else if (fields[0] == 'get') { // … ev.source.postMessage(value); } }, true); }
Использование:
window.addEventListener('message', function(ev) { // Обработка ответа от сервиса. }); var frame = document.createElement('iframe'); frame.onload = function() { // Здесь можно использовать сервис. frame.contentWindow.postMessage('get|key'); }; frame.src = 'http://0.0.0.0/'; frame.style = 'display: none;'; document.documentElement.appendChild(frame);
Как видно, дело хлопотное и имеет ряд недостатков:
- передать можно только строки, поэтому их приходится вручную парсить;
- на каждый сервис приходится загружать отдельный фрейм с другим адресом;
- сложно обрабатывать ответы при использовании нескольких сервисов;
- возможно непреднамеренное создание нескольких фреймов с одним и тем же адресом;
- сервис может быть доступен скриптам со страницы, что небезопасно.
Все эти сложности libretki берет на себя.
Cross-domain messaging (libretki.xdm)
Безопасное и удобное использование XDM. Позволяет по одному и тому же адресу организовать несколько сервисов, различая их по имени. Используется JSON для передачи объектов. Предотвращает доступ к сервису скриптам со страницы.
Классы:
- Server – принимает сообщения и может отвечать на них;
- Client – отправляет сообщения, но не может принимать ответов;
- Channel – клиент и сервер в одном лице, может отправлять сообщения и принимать ответы на них;
- SeqClient, SeqServer – аналоги Channel и Server соответственно, но если первые не отслеживают соответствия между запросом и ответом, то эти позволяют узнать, ответ на какой запрос пришел. Также обнаруживает пропажи сообщений.
Пример сервиса на Server/Channel:
if (location.href == 'http://0.0.0.0/') { new Server('habrahabr.example', function(msg, client) { switch (msg.command) { case 'get': client.post({command: 'get', key: msg.key, value: get_value(msg.key)}); break; case 'set': set_value(msg.key, msg.value); client.post({command: 'set', key: msg.key, success: true}); break; } } }
клиента:
load_page('http://0.0.0.0/', function(win) { var channel = new Channel(win, 'habrahabr.example', function(msg) { switch (msg.command) { case 'get': data[msg.key] = msg.value; break; case 'set': if (msg.success) written[msg.key] = true; break; } } channel.post({command: 'get', key: 'some'}); channel.post({command: 'set', key: 'some', value: 'bla'}); });
То же на SeqServer/SeqClient:
new SeqServer('habrahabr.example', function(msg) { switch (msg.command) { case 'get': return get_value(msg.key); case 'set': set_value(msg.key, msg.value); return true; } });
load_page('http://0.0.0.0/', function(win) { var client = new SeqClient(win, 'habrahabr.example'); client.post({command: 'get', key: 'some'}, function(result) { data['some'] = result; }); client.post({command: 'set', key: 'some', value: 'bla'}, function(result) { if (result) written['some'] = true; }); });
Remote procedure call (libretki.xdm.rpc)
Ещё более упрощает задачу создания сервиса. Просто пишем:
unsafe.libretki.xdm.rpc.service('http://0.0.0.0/', 'habrahabr.example', { get: function(key) { return data[key]; }, set: function(key, value) { data[key] = value; }, });
, использование:
var ex = unsafe.__services.habrahabr.example; // Возвращается не просто результат выполнения, а функция, которую необходимо вызвать // для получения результата. Это сделано для того, чтобы можно было передавать исключения. ex.get('key', function(res) { data['key'] = res(); }); ex.set('key', 'value', function(res) { res(); written['key'] = true; });
Значительно меньше кода по сравнению с начальным вариантом, не так ли? Теперь можно приняться и за создание полезных сервисов.
Разделяемое хранилище данных (libretki.xdm.storage)
Позволяет сохранять данные, доступные с любой страницы. Реализовано с помощью сохранения cookies на странице 'http://0.0.0.0/'.
Пример:
var storage = unsafe.__services.libretki.storage; storage.set('habrahabr_auth', {login: 'login', password: '123qwe'}); storage.get('habrahabr_auth', function(res) { var data = res(); login(data.login, data.password); });
Буфер обмена (libretki.xdm.clipboard)
Требует Java.
Пример:
var clipboard = unsafe.__services.libretki.clipboard; clipboard.set('text'); clipboard.get(function(res) { var text = res(); alert('Clipboard content: '+text); });
Доступ к файловой системе (libretki.xdm.io.file)
Позволяет создавать, удалять и переименовывать файлы и папки, сканировать папки. Требует Java.
Пример:
var file = unsafe.__services.libretki.io.file; file.exists('/some/path', function(res) { alert(res()); }); // Прочитать максимум 10 строк. file.readLines('/another/path', 'utf-8', 10, function(res) { var lines = res(); });
Cross-domain XMLHttpRequest (libretki.xmlhttprequest)
Пример использования XMLHttpRequest приводить не буду, все как обычно, только использовать нужно «libretki.xmlhttprequest.XMLHttpRequest».
Эмуляция XMLHttpRequest сделана для упрощения адаптации чужого кода. Если Вы пишете userjs с нуля, намного удобнее функция «fetch»:
libretki.xmlhttprequest.fetch('http://some.url/path', { username: 'user', method: 'POST', content: 'blabla', onOpened: function() { }, onDone: function(status, headers, response) { }, onError: function() { }, });
Набор скриптов для загрузки изображений в режиме «Show cached only» (libretki.imaginate)
Этот набор скриптов упакован в отдельный архив. Отдельные скрипты описывать не буду, скажу только, что они помогают при работе в режиме показа кэшированных рисунков. Так как у меня канал узкий, я этим режимом пользуюсь постоянно. Можно различными способами загружать отдельные изображения – наведя на него мышь, удерживая клавишу нажатой, выделив область на экране, выделив кусок текста, загружать видимые в окне изображения и т.д.
Инструменты
В папке libretki/tools можно найти несколько инструментов, выполненных как HTML-страницы.
Настройка (libretki/tools/libretki.settings.html)
Интерфейс настройки параметров скриптов.
Настройте требуемые параметры и не забудьте нажать кнопку «Сохранить». Работает и без Java, но тогда Вам придется сохранить файл настроек вручную.

Управление скриптами (libretki/tools/libretki.scripts.html)
Список установленных userjs с возможностью включения и выключения. Можно использовать в качестве боковой панели браузера. Требует Java.

Создание кнопок (libretki/tools/libretki.bookmarklets.html)
Автоматизирует создание bookmarklets для различных команд. Выберите команду, настройте её аргументы, дайте команде имя и перетащите получившуюся ссылку на панель инструментов или в закладки.

Где взять
Скачать libretki можно на libretki.kriomant.net.
Установка
Установка пока достаточно сложна:
- распакуйте содержимое архива в папку пользовательских скриптов;
- установите Java, если желаете использовать доступ к файлам или буфер обмена;
- узнайте расположение файла политики Java («opera:config#Java|SecurityPolicy»), скопируйте его куда-нибудь, добавьте разрешения, используя образец в libretki/opera.policy, укажите путь к новому файлу в настройках;
- откройте libretki/tools/libretki.settings.html и нажмите «Сохранить», это необходимо для генерации уникального кода, который используется для XDM
Примеры
В папке «libretki/examples» есть примеры использования некоторых возможностей. Так как некоторые возможности специально скрыты от скриптов на странице, для работы соответствующих примеров необходимо поместить файл «libretki/examples/libretki.allow-unsafe.js» в папку скриптов.
Планы
В процессе написания находятся инсталляторы для Windows и Linux.
Проблемы
Во-первых требуется feedback. Анонсировал libretki на OperaFan, вроде сколько-то людей скачали, но ни одного отзыва не оставили. Выразите свое отношение:
- это бесполезная вещь;
- слишком сложно установить;
- слишком много весит;
- не хватает документации;
- другое.
Во-вторых, libretki нуждается в логотипе и дизайне сайта, я сам в этом деле ни в зуб ногой. Место и домен уже есть.