За последние пару недель мне пришлось плотно поработать с системой управления пользовательскими скриптами для продуктов 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 могла распознать скрипт как пользовательский нужно добавить специальный заголовок:
С name, author, description все понятно, надо остановиться на остальных параметрах
namespace — любая URI (это не ссылка, а аналог HTML namespace). Можно считать этот параметр уникальным идентификатором скрипта.
include — маска для страниц, которые будут активировать данный скрипт. Может быть несколько директив.
@exclude — маска для страниц, которые НЕ будут активировать данный скрипт. Может быть несколько директив.
Также хорошим тоном будет указать лицензию, под которой распространяется сам скрипт. Это можно сделать ниже метаданных.
* О метаданных на greasespot.net.
Вторым обязательным условием является окончание названия файла. Оно должно заканчиваться на ".user.js", иначе GM не будет распознавать скрипт.
Запуск скрипта для GM производится в порядке очередности по наступлению события DOMContentLoaded у обрабатываемой веб-страницы. Имейте это ввиду.
Мы уже выяснили, что пользовательские скрипты обычно меняют дизайн веб-страниц. Поэтому основные задачи, которые встают перед разработчиками связаны с 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
На этом считаю свой доклад законченным. Спасибо, что дочитали.
Введение
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
На этом считаю свой доклад законченным. Спасибо, что дочитали.