Pull to refresh

UserJS. Часть 4: libretki framework

Reading time 8 min
Views 1.7K
libretki — это framework, призванный упростить создание userjs и предоставить уже готовый набор полезных функций.

Другие статьи серии:

Ядро



Ядро системы представлено файлом 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)

Общая панель инструментов, на которую каждый скрипт может добавлять свои кнопки. Панель инструментов показывается при наведении мыши на небольшой квадрат в левом верхнем углу страницы. Можно добавлять простые кнопки и кнопки-переключатели. Выглядит не очень — я не дизайнер, накидал какой-никакой градиент и дальше погрузился в код.

toolbar.png - image uploaded to Picamatic

Пример:
// Добавляем свою кнопку.
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, но тогда Вам придется сохранить файл настроек вручную.

settings.png - Picamatic - upload your images

Управление скриптами (libretki/tools/libretki.scripts.html)


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

scripts.png - Picamatic - upload your images

Создание кнопок (libretki/tools/libretki.bookmarklets.html)


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

bookmarklets.png - image uploaded to Picamatic

Где взять


Скачать libretki можно на libretki.kriomant.net.

Установка


Установка пока достаточно сложна:
  1. распакуйте содержимое архива в папку пользовательских скриптов;
  2. установите Java, если желаете использовать доступ к файлам или буфер обмена;
  3. узнайте расположение файла политики Java («opera:config#Java|SecurityPolicy»), скопируйте его куда-нибудь, добавьте разрешения, используя образец в libretki/opera.policy, укажите путь к новому файлу в настройках;
  4. откройте libretki/tools/libretki.settings.html и нажмите «Сохранить», это необходимо для генерации уникального кода, который используется для XDM


Примеры


В папке «libretki/examples» есть примеры использования некоторых возможностей. Так как некоторые возможности специально скрыты от скриптов на странице, для работы соответствующих примеров необходимо поместить файл «libretki/examples/libretki.allow-unsafe.js» в папку скриптов.

Планы


В процессе написания находятся инсталляторы для Windows и Linux.

Проблемы


Во-первых требуется feedback. Анонсировал libretki на OperaFan, вроде сколько-то людей скачали, но ни одного отзыва не оставили. Выразите свое отношение:
  • это бесполезная вещь;
  • слишком сложно установить;
  • слишком много весит;
  • не хватает документации;
  • другое.


Во-вторых, libretki нуждается в логотипе и дизайне сайта, я сам в этом деле ни в зуб ногой. Место и домен уже есть.
Tags:
Hubs:
+23
Comments 40
Comments Comments 40

Articles