вторник, 25 декабря 2012 г.

Firefox: пишем расширение для браузера

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

Внедерение своего скрипта в тело страницы
//защищенная часть скрипта - оборачиваем в анонимную функцию, чтобы не было повторов имен переменных
(function() {
    var YT_global_doc = undefined;

    var YT_loader = new function(){};
    YT_loader.run = function(e) {
        //проверяем адрес сайта
	var unsafeWin = e.target.defaultView;
	var unsafeLoc = new XPCNativeWrapper(unsafeWin, 'location').location;
	var href = new XPCNativeWrapper(unsafeLoc, 'href').href;
	if (!href.match(/^http:\/\/www\.xxxx\.com\/watch(.*)?$/i) )
	      return;

        //обращаемся к dom сайта
	YT_global_doc = e.target.defaultView.document;

	if(YT_global_doc) {

          //подгружаем наш скрипт
	  var script = YT_global_doc.createElement( 'script' );
	  script.type = 'text/javascript';
	  script.src = 'chrome://xxx/content/yyy.js';
	  YT_global_doc.body.appendChild(script);

	}
    };

    var yt_load = function() {
        //событие загрузки вкладки с сайтом, выполняется каждый раз при загрузке страницы
        window.document.addEventListener("DOMContentLoaded", YT_loader.run, true);
    };
    //событие загрузки приватной части - выполняется один раз
    window.addEventListener("load", yt_load, false);

})();


Правильное создание новых узлов в DOM
Внутренними правилами firefox запрещено обращаться и работать с dom через innerHtml. Взамен этого необходимо пользоваться шаблонами. В своих аддонах я пользуюсь JQuery Templating.
Вот пример:
$("#pv_actions").prepend (
      $("<a>", {
	href: 	"#",
	target: "_blank",
	text:	"Загрузить оригинал",
	id:	"pv_down_link"
      })
      .css("font-weight", "bold")
      .bind("click", function (o) {
	//
      })
);


Взаимодействие с защищенной частью скрипта
Аддон состоит из 2 частей: защищенной и внедренной (небезопасной части). В безопасной части можно работать с апи браузера: сохранять файл, делать ajax запросы и т.д.
Взаимодействовать эти две изолированные части могут только по средствам событий.
Рассмотрим пример: узнать размер файла.
В незащищённой части создаем событие с нашими параметрами.
  //yt_getFileSizeEvent - название события
  var element = document.createElement("yt_getFileSizeEvent");
  element.setAttribute("attribute_url", "адрес до файла" );
  element.setAttribute("attribute_id",  "индекс файла" );
  document.documentElement.appendChild(element);
  var evt = document.createEvent("Events");
  evt.initEvent("yt_getFileSizeEvent", true, false);
  element.dispatchEvent(evt);
В защищенной части ловим событие:
document.addEventListener("yt_getFileSizeEvent", function(e) { YT_secureEvent.getFileSize(e); }, false, true);
После этого обрабатываем и повторяем все в обратном порядке, чтобы передать данные в незащищённую часть скрипта.