pacify.ru \ opera-oex

Как написать расширение для браузера Opera

февраль 2013 года

В чём суть задачи, и в чём сложности

Задача состоит в разработке расширения, которое будет реагировать на открытие определенных HTML-страниц в браузере. Например, модифицировать HTML-код страницы сайта для более удобного использования этого сайта.
Решение опробовано на Opera 12.14 (Debian 6.0.6, amd64).

План решения задачи (общая схема для написания подобных расширений)

1. Расширение, которое мы пишем для браузера Opera, будет состоять из двух частей: "фоновая страница" (browser-related code/background page, start file) и скрипт для работы с открытыми страницами (page-related code, includes). Обмениваются эти страницы посредством сообщений (messages): вызов функции postMessage() + обработчики onmessage. Background-страницу можно настроить через config.xml.

2. В background'е у нас будет "крутиться" скачиваемая база сайтов, запросы к которой будет присылать content-script. База скачивается по таймауту. Таймаут задаём через вызов функции window.setTimeout(func, timeout), скачивание - через XMLHttpRequest(). Парсинг - через responseXML + getElementsByTagName() + textContent.

3. База данных - в localStorage (появилось в Опере с версии 10.5, в начале 2010 года). WebSQL использовать уже не модно, так как W3C прекратила работу над спецификацией в 2010 году (частная имплементация WebSQL существует сейчас в Chrome, Opera, Android browser и проч.). В общем, люди в основном используют IndexedDB или localStorage.

4. Code injection - простым доступом к event.target.body.innerHTML из content-скрипта. Injected HTML определять с important-атрибутами, чтобы перекрыть установки сайта.

5. Как проверять текущий URL, обрезать его и вычислять хэш - уже решённая задача для браузеров Firefox и Chrome.

6. Расширение упаковывается в .oex-формат очень просто:

#!/bin/bash 7z a -tzip ../poskidke-opera.zip * mv ../poskidke-opera.zip ../poskidke-opera.oex
Как опубликовать расширение, рассказано здесь.

?. Подумать над "локализацией" (locales/en/background.*);

Гладко было на бумаге, да забыли про овраги ... (конкретные вопросы реализации)

1. В начале includes-скриптов надо писать такую конструкцию (эти скрипты являются UserJS-скриптами?):

// ==UserScript== // @include * // ==/UserScript==

2. JavaScript в фоновом процессе надо оформлять в "head" страницы index.html, внутрь тэга "script".

<script language="JavaScript"> ...

3. Пример использования XMLHttpRequest() идентичен версии для Chrome/Chromium:

function loadXMLConfig(url) { xmlreq.open("GET", url, true); xmlreq.onreadystatechange = function (e) { try { // Важно! // только при состоянии "complete" if (xmlreq.readyState == 4) { // для статуса "OK" if (xmlreq.status == 200) { // обработка ответа var xml = xmlreq.responseXML.documentElement; var ts = xml.getElementsByTagName("timeout"); var timeout = ts[0].textContent; } else { console.log("Cannot load file"); } } } catch( e ) { console.log("Error"); } } xmlreq.send(null); }
Чтобы не выскакивало в логах: "Uncaught exception: DOMException: NETWORK_ERR", надо указать в config.xml:
<?xml version="1.0" encoding="utf-8"?> <widget xmlns="http://www.w3.org/ns/widgets" id="http://domain.ru/path/"> ... <access origin="*" subdomains="true"/> </widget>

4. Для обмена сообщениями между background page и content script, надо использовать такую конструкцию:

content_script.js: opera.extension.postMessage(event.target.href); ... opera.extension.onmessage = function(event) { alert("reply from bg:" + event.data); };
background.html: opera.extension.onconnect = function(event) { event.source.postMessage("y"); };
Вызов alert() в background-процессе не работает.

5. Вставку кода нужно правильно оформить, чтобы не поломались другие элементы на странице (например, не пропал набор соц.кнопок от Яндекса).

6. Ещё одна трабла - Опера скоро перейдёт на WebKit, возможно многое поменяется.


> Заглавная <