Pull to refresh

Укрощаем GreaseMonkey

Reading time5 min
Views21K
За последние пару недель мне пришлось плотно поработать с системой управления пользовательскими скриптами для продуктов Mozilla — GreaseMonkey. И раз уж я сам себя назначил администратором одноименного блога, значит написать введение в вопрос — моя святая обязанность.



Введение



GreaseMonkey (далее GM) — система управления пользовательскими скриптами для продуктов Mozilla. В моей статье я буду говорить о браузере этой компании, о Firefox далее (FF). Так же в некоторых местах я коснусь его конкурентов, а именно Opera, Safari и конечно-же Internet Explorer (далее IE).

Пользовательский скрипт (User Script) — скрипт, написанный на языке JavaScript (далее JS), устанавливаемый пользователем в браузер и исполняющийся при загрузке веб-страниц. Используется для изменения их дизайна (в широком смысле этого слова).

Говоря проще, с помощью пользовательских скриптов, можно добавить/удалить/изменить элементы веб-страницы, изменить их поведение, улучшить User Experience.

Установка



GM легко ставится как расширение для FF с сайта дополнений. Так-же у GM есть официальный сайт, где можно найти массу полезной информации.

После установки и перезапуска у FF появится иконка:



И это значит что можно устанавливать пользовательские скрипты.

Самый большой склад пользовательских скриптов — это userscripts.org. Установка проиходит очень просто. GreaseMonkey просто перехватывает ответ на запрос JS-файла, и если он имеет специальный заголовок (расскажу о нем ниже), то вызывает диалог установки:



Обзор



Управлять GM и установленными скриптами можно через контекстное меню, которое вызывается правом щелчком по рожице обезьяны:



В верхней части меню отображается спискок активных для данной страницы скриптов. Любой скрипт можно отключить, убрав галочку.

С помощью API GM вы можете расширить это меню. Все действия, зарегистрированные через GM_registerMenuCommand, появятся в подменю «Команды скрипта».

Пункт меню «Новый скрипт» я пропущу, так как уверен, что в редакторе делать скрипт удобнее, в том числе и редактировать метаниформацию. В любом случае, я надеюсь, что освоение этого мастера не вызовет у читателей проблем.

«Управление скриптами» вызвывает следующее окно:



В этом окне вы можете сами поднастроить любой установленный пользовательский скрипт. Для этого выберите его в левом списке. Можно добавить удалить маски URL, для которых этот скрипт будет загружаться или НЕ загружаться (классический Allow/Deny), включить/выключить/удалить скрипт и, что самое важное для разработчика, отредактировать его вживую.

Для редактирования скрипта надо нажать кнопку «Изменить». В первый раз GM попросит выбрать редактор. В последующие будет автоматически открывать рабочую копию скрипта в выбранном редакторе.

На этом обзорная экскурсия по GM считается законченной и можно переходить непосредственно к тонкостям разработки пользовательских скриптов.

Пользовательские скрипты



GM-скрипты практически ничем (о некоторых особенностях, я расскажу в следующем разделе) не отличаются от обычных JS-скриптов, поэтому никаких специальных знаний для написания не нужно. Но для того чтобы GM могла распознать скрипт как пользовательский нужно добавить специальный заголовок:

// ==UserScript==
// @name Weborama Inline Player
// @namespace tbms.ru/weborama/inline
// @description Includes weborama inline player
// @author Konstantin Shvydky, Nick Mitin
// @include *
// @exclude file://*
// ==/UserScript==
/*
This code is licenced under the GPL
www.fsf.org/licensing/licenses/gpl.html
*/


С name, author, description все понятно, надо остановиться на остальных параметрах

namespace — любая URI (это не ссылка, а аналог HTML namespace). Можно считать этот параметр уникальным идентификатором скрипта.
include — маска для страниц, которые будут активировать данный скрипт. Может быть несколько директив.
@exclude — маска для страниц, которые НЕ будут активировать данный скрипт. Может быть несколько директив.

Также хорошим тоном будет указать лицензию, под которой распространяется сам скрипт. Это можно сделать ниже метаданных.

* О метаданных на greasespot.net.

Вторым обязательным условием является окончание названия файла. Оно должно заканчиваться на ".user.js", иначе GM не будет распознавать скрипт.

Запуск скрипта для GM производится в порядке очередности по наступлению события DOMContentLoaded у обрабатываемой веб-страницы. Имейте это ввиду.

Tips & Tricks



Мы уже выяснили, что пользовательские скрипты обычно меняют дизайн веб-страниц. Поэтому основные задачи, которые встают перед разработчиками связаны с DOM-программированием, а именно манипуляциями с DOM-моделью веб-страниц. Проблема здесь в том, что порой очень сложно добиться адекватной работы скрипта на антисемантических сайтах. И я бы хотел дать несколько наводок для GM-разработчиков.

В Опере, Сафари и Файерфоксе есть встроенная поддержка XPath, через функцию document.evaluate(). Хорошее описание этой функции есть в MDC. Тем кто не в курсе, XPath (XML Path Language) является языком для обращения к частям XML-документа. В случае веба это определение верно и для HTML. Отличный туториал есть на ZVON.org. Суть метода в том, что вы создаете и посылаете «запрос» в DOM-модель, а в ответ вам приходит итератор со всеми нодами, которые удовлетворяют этому запросу.

Важно знать, что нельзя напрямую изменять эти ноды в итераторе, так как любое изменение перестраивает DOM, таким образом делая итератор невалидным. Поэтому сначала создайте массив и скопируйте туда ссылки на эти ноды, а потом уже работайте с ними. В примере в MDC все это рассмотрено.

В IE тоже есть частичная поддержка evaluate, которая реализуется черех хак, созданный Dimitri Glazkov и Mehdi Hassan.

Мы внесли его в свой JS-Extender, поправив в нем некоторые баги. Тем не менее, у нас не получилось выполнять сложные XPath запросы, поэтому мы не пользуемся этой функцией в IE.

Еще один важный момент, который стоит отметить, это то что при использовании свойства element.childNodes, FF считает текстовыми нодами переносы строки между тегами. Например у div с id = container будет не три, а пять дочерних нод:

<div id=«container»>
<div>content1</div>
<div>content2</div>
</div>

Будьте бдительны!

И последнее, но самое важное. В JS есть объект window, который как-бы является глобальным неймспесом для всех глобальных сущностей JS. если мы пишем

var myVar = 1;

то она будет доступна через

window.myVar или window['myVar'].

Так вот, в GM тоже есть window, но он является оболочкой вокруг самого window веб-страницы. это сделано для того, чтобы ваш код не пересекался с оригинальным кодом страницы и не мешал ему. Но существуют ситуации, когда нужно напрямую обратиться к тому самому window, чтобы, например, получить значение переменной сайта. На помощь приходит глобальное свойство unsafeWindow, которое и предоставляет к нему доступ.

Если вы пишете кросс-браузерный пользовательский скрипт, то имейте ввиду, что unsafeWindow есть только в GM, в Опере его нет. Поэтому лучше сразу завести глобальную переменную и положить в нее нужный вам window, например так:

var aWindow = (typeof unsafeWindow != 'undefined')? unsafeWindow: window;

Ложка дегтя



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

Существует несколько попыток решить эту проблему:

yoast.com/greasemonkey-auto-update-notification
splintor.wordpress.com/2007/05/01/greasemonkey-wish-auto-update-user-scripts
userscripts.org/scripts/show/2296

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

В общем можно сказать, что GreaseMonkey — это частный случай механизма управления пользовательскими скриптами. В Опере они поддерживаются без всяких расширений, по информации, поступисшей от pepelsbey сушествует плагин для Safari, который позволяет запускать эти скрипты — GreaseKit, по информации поступившей от jursovet уже реализована поддержка скриптов и для Chrome

На этом считаю свой доклад законченным. Спасибо, что дочитали.
Tags:
Hubs:
Total votes 46: ↑42 and ↓4+38
Comments27

Articles