пятница, 8 апреля 2016 г.

CustomButtons часть 1-я. О запуске скриптов в браузере или почему я предпочитаю CustomButtons.

  1. О запуске скриптов
  2. Достоинства и недостатки.
  3. Почему я предпочитаю CustomButtons
  4. Миниликбез по XUL
  5. Куда все это вставлять

О запуске скриптов



Любому пользователю интернета, умеющему хоть немного программировать, по всей видимости приходила в голову мысль, что неплохо было бы иметь возможность автоматизировать некоторые задачи собственным кодом. Здесь причины могут быть разные: и определенные неудобства интерфейсов на любимых ресурсах, и необходимость вытягивать какую-то информацию из страниц, да и мало ли что еще. Благо - возможности такие предоставляют и сами браузеры и их расширения, причем расширений, запускающих скрипты, - несколько, вот о некоторых из них речь и пойдет( главным образом о том, которое упомянуто в заголовке).

Сразу скажу, что глубокого исследования этого вопроса я не проводил и писать буду только о том, чем сам пользовался и пользуюсь. Из браузеров я отдаю предпочтение Firefox, так что в основном "запускать" будем из него. Использовать мне приходилось: букмарклеты, iMacros, GreaseMonkey и CustomButtons. Последние три - расширения для Firefox. iMacros существует для разных браузеров, GreaseMonkey имеет аналоги(по крайней мере для Chromе точно существует расширение, запускающее обезьяньи скрипты), CustomButtons ориентирован на архитектуру mozilla, так что, даже если бы и были аналоги, то его скрипты в других браузерах просто не работали бы.

Достоинства и недостатки.



Букмарклеты.
Достоинства:
  1. Не требуют установки расширений.
  2. Если писать кроссбраузерный код, то работать будут в разных браузерах. Раньше работали вообще везде, но как-то наткнулся на новую версию Opera, там они с закладками намутили такого, что букмарклеты стало использовать невозможно. Не знаю, возможно это как-то настраивается, но я тогда не нашел способа.
  3. Таким скриптом легко поделиться, можно сделать просто ссылку на странице и для установки потребуется просто перетащить ссылку на панель закладок. Кроме того, можно даже с панели одного браузера перетащить на панель другого и оставить там.
  4. Поскольку это просто закладки, с ними можно делать все то же самое, что делается с закладками, то есть они прекрасно организуются в меню любого уровня вложенности, причем часто используемые букмарклеты можно оставить на панели закладок, а остальные отправить куда подальше и таким образом организовать рабочее пространство браузера как угодно.
  5. Опять-таки, будучи закладками, букмарклеты прекрасно синхронизируются и добавив его на одном компьютере, можно использовать на любом другом, где браузер синхронизирован с данным.

Недостатки:
  1. Главный недостаток - это, по всей видимости, права. Есть существенные ограничения в политике безопасности браузеров для кода, выполняющегося из букмарклета. Например оттуда невозможно отправить аякс-запрос, по всей видимости потому, что в качестве адреса страницы, с которой он отправляется считается не адрес страницы, загруженной в активную вкладку браузера, а сам букмарклет (javascript:...), а стало быть любой аякс-запрос будет считаться кроссдоменным.
  2. Букмарклеты не очень удобно(чтобы не сказать "очень неудобно") редактировать. При создании код надо писать в каком-нибудь редакторе, потом создается закладка и в строку адреса закладки надо вписать код, предварив его javascript:. Если что-то не получилось, опять надо внести изменения в том же редакторе, скопировать код и отредактировать закладку. Если делается в Firefox, то браузер сам "эскейпит" код, а вот в том же IE придется сделать это другими средствами. Ну и соответственно, если не иметь исходного кода букмарклета, то отредактировать его можно только, если сначала код "отанэскейпить". Естественно все это неудобно.
  3. Отсутствие возможности повторного использования кода. То есть, если есть код, актуальный для нескольких скриптов, то его просто придется полностью копировать в каждый букмарклет, где этот код будет использоваться.
  4. Случается, что по непонятным причинам достаточно простой и вполне рабочий букмарклет "отказывается" работать на некоторых страницах.
В общем и целом, когда скрипт небольшой и несложный, а кроме того не требует каких-то полномочий, которых у букмарклетов нет - этот способ вполне можно и даже желательно использовать.

iMacros. Несмотря на то, что это расширение дает возможностей больше, чем все другие, я, все-таки, снес его довольно давно и ни разу об этом не пожалел. Напишу о нем то, что помню.

Достоинства:
  1. Фактически это расширение не является инструментом запуска скриптов javascript, а у него есть собственный язык макросов, возможность запуска javascript в нем - просто дополнительная функция. Само же расширение имеет огромный набор возможностей, некоторые из которых из скрипта не реализовать. Например он умеет взаимодействовать с Flash-приложениями, просто имитируя действия пользователя, такие как клики и прочее. В нем есть функция записи макроса, который потом можно будет редактировать. В этом направлении он обладает массой достоинств, перечислять которые нет смысла, поскольку речь здесь ведется, в основном, о javascript-сценариях.
  2. Скрипты выполняются с chrome-привилегиями, что дает доступ не только к объектам веб-страницы, но и к объектной модели самого браузера, к объектам XPCOM и таким образом все, что можно делать в коде, написанном под платформу Mozilla, становится доступным.
  3. Скрипты достаточно удобно организованы, для них есть отдельный каталог, где они хранятся в виде отдельных файлов. Их можно редактировать в любом редакторе.
  4. Сами скрипты не занимают полезное пространство браузера, поскольку доступны они в боковой панели браузера, которую можно открывать и закрывать по желанию (если не изменяет память, для этого используется клавиша F8).
  5. Из скрипта или макроса можно создать закладку и запускать его из панели закладок.
  6. В настройках расширения можно указать пути к каталогам со скриптами, базами данных и внешнему редактору скриптов(вроде бы, опять таки если не изменяет память). Ну и внешний редактор для скрипта можно запустить из интерфейса браузера.
Недостатки:
  1. Хоть макросы я и отнес к достоинствам, но сам ими никогда не пользовался. Изучать язык, используемый в одном-единственном расширении браузера и больше нигде - мне лично просто было лень, поэтому весь функционал макросов лично мной востребован не был.
  2. Как оказалось, скрипты запускаются в какой-то изолированной области, поэтому выполняются в несколько раз медленнее, чем в других расширениях. Причем это заметно даже невооруженным глазом.
  3. Есть проблемы с кодировками. Например, если в настройках указать пути к скриптам или внешнему редактору, то это прекрасно работает, если пути не содержат кирилических символов. Не то чтобы это было нерешаемой проблемой, но все же - неприятно.
  4. Новый скрипт из интерфейса браузера не создашь, видимо из-за того, что скрипты - не главное в этом расширении. Приходится лезть в каталог со скриптами, создавать новый файл, а чтобы он был доступен в дереве скриптов, это дерево еще и обновить надо(насколько помню достаточно закрыть боковую панель и при повторном открытии скрипт доступен, правда в дереве при этом все ветви будут закрыты, так что придется открывать их снова).
  5. Несмотря на то, что запускать скрипты и макросы можно с помощью закладок, это удобно только с точки зрения доступности, а вот с синхронизацией все не так хорошо, как в случае с букмарклетами: сама закладка только запускает скрипт(макрос), находящийся в файловой системе, так что синхронизирована она будет как и все закладки, но для того, чтобы на другом компьютере она работала, там должен быть установлен этот же скрипт, да еще по такому же адресу(ну и расширение должно быть установлено).

GreaseMonkey.

Достоинства:
  1. Хоть это расширение и не предоставляет возможности кастомизировать расположение "менюшек", запускающих скрипты, как это было с букмарклетами или даже в iMacros, тем не менее здесь реализовано очень удобное управление всеми возможностями буквально через одну кнопку с меню. Таким образом рабочее пространство не загромождается, а доступ к скриптам остается удобным.
  2. В расширении реализован фильтр скриптов. То есть в каждом скрипте указываются шаблоны адресов страниц, для которых он актуален и ни на каких других страницах он не будет доступен. Благодаря этому, скриптов может быть установлена ни одна сотня, и тем не менее, даже не смотря на то, что доступ к ним осуществляется через одно-единственное меню, доступ ко всем функциям остается простым и удобным. То есть на каждой странице будут доступны только актуальные для нее скрипты и их команды. Мало того, можно какие-то скрипты оперативно отключить из этого же меню и их команды перестанут отображаться.
  3. Очень простой механизм создания нового скрипта, опять-таки через то же самое меню, а так же оттуда можно перейти к странице управления всеми скриптами или открыть в редакторе конкретный скрипт, если он доступен в данный момент.
  4. Достаточно неплохой встроенный редактор кода, с подсветкой синтаксиса, подсказками и прочими приятностями.
  5. Поскольку в одном скрипте можно создать несколько команд, это уже само по себе дает возможность повторного использования кода, так как в этом же скрипте может содержаться код, который можно использовать разными командами. Кроме того, существует возможность подключения дополнительных скриптов, как локальных, так и из интернета (ну там jQuery всякие и прочие вкусности, ну и собственный код, разумеется).
  6. Кроме скриптов можно еще подключать внешние ресурсы, и запускать некоторые дополнительные фукнции(например выполнять кроссдоменные аякс-запросы).
  7. Простой механизм установки скриптов из внешних источников (пустячок, а приятно).
Недостатки:
  1. Ограничения по безопасности, некоторые, на мой взгляд, не вполне оправданы. С этим еще может и можно было бы смириться, но проблема в том, что политика безопасности может измениться в новой версии, в результате чего перестанут работать старые скрипты. Причем, когда скрипты перестают работать как надо, в первую очередь думаешь, что что-то изменилось на страницах, которые они обрабатывают, а потом вдруг оказывается, что это разработчики расширения преподнесли такой сюрприз.
  2. Несмотря на наличие удобного редактора, отладка скрипта может стать делом довольно хлопотным, поскольку при внесении изменений в код, его недостаточно сохранить, нужно еще страницу, на которой он будет запускаться, перезагрузить, иначе запустится не измененная версия скрипта, а прежняя.
  3. На некоторых ресурсах (том же вконтактике, например), переход на страницу по внутренней ссылке остается для "обезьяны" незамеченным, и страницу надо опять-таки обновить, чтобы определенные для нее скрипты стали доступными.
В общем и целом, каких-то серьезных недостатков у этого расширения обнаружено не было, а достоинств - масса. Так что, по всей видимости это одно из лучших расширений данного типа.

CustomButtons.
Достоинства:
  1. Код выполняется с chrome-привилегиями. Как будет показано ниже, это дает возможность реализовать самостоятельно то, чего в расширении не хватает. Ну и соответственно, практически все чего нельзя сделать с помощью букмарклетов или GreaseMonkey становится доступно с помощью CustomButtons.
  2. Достаточно просто создается и редактируется новая кнопка.
  3. Опять же закладки. Здесь нет возможности запускать код из закладок или создавать кнопки в виде закладок, но разработчики добавили в браузер поддержку собственного протокола custobutton, в котором в качестве адреса используется XML-документ с описанием кнопки, закодированный в URL-формат. Переход по такому адресу вызывает окошко, предлагающее установить кнопку. Из любой кнопки легко можно сделать закладку (команда вызывается из контекстного меню кнопки), закладка содержит весь код, поэтому после синхронизации, ее можно установить на другом браузере. Можно сохранить такие закладки в HTML-документе, используя штатные средства браузера, опубликовать в виде ссылки и т. д.

Недостатки:
  1. Для каждой отдельной функции требуется отдельная кнопка. Таким образом кнопки загромождают рабочее пространство браузера. Это и раньше-то было не очень удобно, а сейчас, когда из нового дизайна убрали панель расширений, а любая новая кнопка отнимает место у адресной строки, строки поиска и т. д., которые реально становятся от этого меньше, - тут уж не разгуляешься. Отчасти проблема решается установкой
    classicthemerestorer, с помощью которого можно вернуть панель расширений, тем не менее проблему загромождения пространства это не решает полностью.
  2. Поскольку каждая кнопка выполняет одну функцию, то с повторным использованием кода тоже не все просто. Хотя подключить внешний скрипт можно, благодаря chrome-привилегиям, но встроенного механизма все-таки нет.
  3. Встроенный редактор - просто ужасен, там код пишется в обычном текстовом окошке, вроде есть даже некий функционал, помогающий немного с индентами, но работает криво, так что может было бы лучше, если бы его вовсе не было.
  4. Во встроенном редакторе есть кнопка запуска внешнего редактора, но работает не так как надо. После установки расширения можно запустить функцию, она предложит выбрать внешний редактор и вроде все нормально. Проблема возникнет, если появится желание уже после этого поменять редактор. Такое там не предусмотрено. Мало того, если программу, назначенную редактором удалить, то эта кнопка будет выводить сообщение, что редактор не найден, ничего не предлагая взамен. Написал об этом на форуме расширения, разработчик ответил, что этот код писал не он и развитие этого направления не является приоритетным. Пообещал исправить когда-нибудь, если не забудет. Хотя исправить несложно, можно просто добавить кнопку сброса внешнего редактора, тем более, что код сброса я там же привел. (После того как написал это, я поставил последнюю сборку расширения. Проблему решили только отчасти: если удалить назначенное приложение из системы, то будет предложено выбрать другое, однако возможности просто сменить редактор так и не реализовали).

Несмотря на вроде бы минимум достоинств и серьезные недостатки, тем не менее CustomButtons я считаю лучшим вариантом из всех описанных. А вот почему - давайте разбираться.

Почему я предпочитаю CustomButtons



На самом деле, хоть такое достоинство как исполнение кода с chrome-привилегиями и выглядит скромно, тем не менее потенциал у этой возможности огромен. Все те возможности, которые предоставляются различными расширениями, они могут предоставить именно потому, что написаны с такими привилегиями. И значительная часть самого Firefox написана так же. Да, отсутствие некоторых встроенных инструментов немного напрягает, но все можно реализовать в своем коде и даже больше, поскольку нас ничего не ограничивает. Тут, конечно, возникает вопрос: а зачем тогда все реализовывать в кнопке, когда можно собственное расширение написать. Но тут видимо каждый сам для себя может решить, что для него лучше в каждом конкретном случае.

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

Миниликбез по XUL



Естественно, в двух словах этого не расскажешь, но в данном случае прояснить пару нюансов, которые помогут решить нашу задачу - вполне возможно.

Пользовательские интерфейсы программ на платформе Mozilla описываются на специальном языке XUL, который основан на XML. Для каждого элемента управления там есть отдельный XML-элемент, естественно изучать все нам не потребуется, поскольку все, что нужно - это сформировать меню кнопки.

Код кнопки выполняется в контексте XUL-окна, то есть объект window - это XUL-Window или корневой элемент документа XUL. Объект document - это тоже XUL-документ. Ключевое слово this будет ссылаться на сам объект кнопки, которая в объектной модели документа представлена элементом toolbarbutton. На странице описания данного элемента есть пример кнопки со вложенным меню.

В двух словах, как устроена кнопка-меню.
В элементе toolbarbutton дочерним элементом должен быть элемент menupopup. Это как раз та самая панелька, на которой расположены элементы меню. menupopup может включать дочерние элементы: menuitem - конечные элементы меню, по которым мы и будем в конце концов клацать; menuseparator - просто разделительная линия, для группировки элементов в пределах одного menupopup; menu - служит для создания вложенных меню, в этот элемент вкладывается новый элемент menupopup, в котором можно расположить элементы подменю.

Элементы создаются с помощью document.createElement, значения атрибутов можно устанавливать как с помощью setAttribute, так и присваивая их одноименным свойствам элементов. Есть исключения, но в основном они хорошо известны всем, кто имел дело с объектной моделью веб-страницы (например нюансы работы с классами, где атрибут называется class, но приходится работать со свойствами className и classList). В принципе поддерживается большинство свойств и методов элемнетов HTML, хотя ожидать, что будет поддерживаться свойство innerHTML для XML-элементов было даже странно и, к сожалению, насколько мне известно, аналогичного свойства или метода тоже нет.

Атрибуты подробно описаны на страницах элементов, так что здесь следует упомянуть только те, которые понадобятся для решения нашей задачи на базовом уровне.

Для того, чтобы кнопка имела вид кнопки меню, ее свойству(или атрибуту) type надо присвоить значение menu-button
Код javascript Выделить

this.type = "menu-button";

или
Код javascript Выделить

this.setAttribute("type", "menu-button");

Дальше создаем popup
Код javascript Выделить

var popup = document.createElement("menupopup");

this.appendChild(popup);

Добавляем первый элемент
Код javascript Выделить

var item1 = document.createElement("menuitem");

item1.label = "Открыть киберфорум";

item1.image = "http://www.cyberforum.ru/favicon.ico";

item1.classList.add("menuitem-iconic");

item1.addEventListener("click", function (evt) { loadURI("http://www.cyberforum.ru/") }, false);

popup.appendChild(item1);

Атрибут и свойство label - это текст, который будет отображаться.
image - иконка элемента меню, но она отображается только тогда, когда элемент имеет класс menuitem-iconic, так что его и добавили.
Остальное, думаю, и так понятно. Такой код лучше выделить в отдельную функцию, поскольку выполнять его придется для каждого добавляемого меню. Ну что-то типа такого.
Код javascript Выделить

function addItem(popup, label, clickhandler, image, attributes)

{

    var item = popup.appendChild(document.createElement("menuitem"));

    item.setAttribute("label", label);

    item.onclick = clickhandler;

    if (image)

    {

        item.className = "menuitem-iconic";

        item.setAttribute("image", image);

    }

    for (var p in attributes)

    {

        item.setAttribute(p, attributes[p]);

    }

    return item;

}

Думаю, здесь все параметры понятны, а последний - это словарь с дополнительными атрибутами, которые будут установлены для нового элемента. Теперь новый элемент в ранее созданный popup можно добавить так
Код javascript Выделить

addItem(popup, "Надпись нового элемента", function (evt) {/* Код, выполняемый при клике */ }, "путь к иконке или dataurl", { "name": "newitem" });

addItem(popup, "Элемент с галочкой", function (evt) {/* Код, выполняемый при клике */ }, null, { "type": "checkbox", "autocheck": "true" });

Из атрибутов стоит обратить внимание на, tooltiptext - отображает всплывающую подсказку для элемента, а также autochek, checked, type, ну возможно еще accesskey. Это то, что действительно полезно.

Куда все это вставлять



В окне редактора кнопки есть вкладка Initialization. Там пишется код, который будет выполнен единожды при инициализации кнопки. То есть при добавлении кнопки на панель инструментов или, к примеру, если при редактировании кнопки выполнить сохранение (Ctrl+S), при загрузке браузера и т. д. в любом из этих случаев код инициализации будет выполнен один раз, стало быть туда и надо писать, но...

В последней версии расширения, представленной в репозитории расширений есть небольшой баг, связанный именно с инициализацией, а именно: она просто не выполняется. Я указал разработчику на этот баг на форуме поддержки и он его исправил, но пока (на данный момент) новая версия не прошла проверку в Мозилле, так что ее можно установить отсюда. Здесь, правда есть еще одна проблема. В последних версиях Firefox по умолчанию запрещено устанавливать расширения из неизвестных источников и браузер просто блокирует такую установку, а установленные ранее расширения стали недоступными. Поэтому, если все-таки есть желание установить обновленную версию, не дожидаясь пока она пройдет проверку, то надо внести изменения в конфигурацию браузера. Для этого заходим на страницу about:config, обещаем быть осторожными :-D , находим раздел xpinstall.signatures.required и устанавливаем его значение в false. При этом надо понимать, что в этом случае при установке других расширений этот параметр будет иметь такое же значение и для них. Так что делать это или ждать пока новая версия пройдет проверку - пусть каждый решает сам.

В принципе можно "соорудить костыль" как временное решение. В кнопке-меню клик по самой кнопке обычно не используется. Стало быть можно во вкладке Code выполнить запуск кода инициализации, в этом случае кнопка примет желанный вид только после того, как по ней будет выполнен клик. Код инициализации можно выполнить так
Код javascript Выделить

custombutton.buttonInit(this);

Но, видимо следует также позаботиться и о том, чтобы при повторном клике этот код не выполнялся. Сделать это можно, например, так
Код javascript Выделить

if (!this.initialized)

{

    custombutton.buttonInit(this);

    this.initialized = true;

}

Методика, описанная здесь, объясняет принцип того, что надо делать. Процесс создания кнопок-меню для CustomButtons можно значительно упростить, пример того, как это можно сделать я опишу в следующей статье (или одной из следующих).

Комментариев нет :

Отправить комментарий