Pull to refresh

«Валидность» расширения для Firefox и пара мелочи

Reading time6 min
Views1.6K
Привет!

На Хабре достаточно много статей на тему написания расширений для Mozilla Firefox.
Воспользовавшись поиском, можно найти информацию, например: здесь, здесь, здесь или даже здесь.

Но я пока не нашел (если есть, то — простите) статьи про валидные расширения.

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

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

И ещё приведу парочку примеров и подкину ссылок.



  • Никогда, не используйте eval(). Хотя, все знают это правило, но здесь оно тем более чревато.

    Кроме того, думаю, что немногие постоянно помнят, что eval() является «замыканием».
    Все, что было объявлено в его «области видимости» (scope), становится доступно коду, который содержался в eval(). В том числе и это чревато очень многими проблемами. Особенно если Вы предпочитаете давать вспомогательным переменным имена типа «i», «str» и тому подобное.

  • При использовании window.setTimeout() всегда пишите так:

      window.setTimeout( function(){<br>    [ ваш код здесь]<br>  }, милисекунды );<br><br>* This source code was highlighted with Source Code Highlighter.


    Во-первых — это валидно, и во-вторых — это валидно, и в-третьих тоже.

    Что делать если нужно передать переменные?

    Воспользуйтесь же scope замыканием!

      (function ( [ переменные, которые Вы хотите получить внутри Timeout ] ){

          window.setTimeout( function(){
            [ ваш код здесь]
          }, милисекунды );

      }( [ переменные, которые Вы хотите "положить" для доступности в Timeout ] ));


    * This source code was highlighted with Source Code Highlighter.


    Есть, конечно, совсем «правильный» вариант — воспользоваться, например, вот этим:

    Components.classes['@mozilla.org/timer;1'].createInstance(Components.interfaces.nsITimer);<br><br>* This source code was highlighted with Source Code Highlighter.


    Но это уже «совсем» правильно.

  • Никогда, вообще никогда не попадайте в Global Scrope для оверлея.

    То есть вот этого:
    <toolbarbutton id="helloButton" label="&helloworld;" oncommand="showHello();"/><br><br>* This source code was highlighted with Source Code Highlighter.


    Нужно избегать.

    Что здесь не так?

    Не так то, что есть глобальная функция «showHello()».

    Да, все знают, что она «в песочнице» и не в прямом смысле «доступна» из

    Global Overlay for Firefox Skin.

    Но ведь это не мешает ей оставаться глобальной!

    Хотя бы в рамках проекта…

    А значит её «что-нибудь» или «кто-нибудь» может «случайно»…

    Что же делать?

    Но ведь никто пока не отменил "addEventListener"

    То есть делаем вот так:

    <toolbarbutton id="helloButton" label="&helloworld;" />

    var gid = function(id){ return window.document.getElementById(id); }

    gid('helloButton').addEventListener('command', function(evt){ our_event_handler(evt); }, false);


    * This source code was highlighted with Source Code Highlighter.


    Да, это «муторно», но валидация дороже!


Что ещё можно придумать, чтобы усложнить Себе жизнь:

  1. Для вашего XUL оверлея желательно создать только один (должен остаться только один, как в «Горце») JS файл, который и будет «всем вашим кодом».

    Причем, весь код этого файла будет внутри замыкания, вот так:

    (function(){
      var e;
      try{
        
        [ Ваш Код Здесь ]
        
      }catch(e){ window.alert(e); }
    })();

    * This source code was highlighted with Source Code Highlighter.


  2. Хотите, чтобы код при этом был «разбросан» по «кучке мелких файлов в кучке директорий?

    Это тоже можно!

    var JS_Loader = function( path_to_file, object_where_file_will_be_loaded ){

      Components.classes['@mozilla.org/moz/jssubscript-loader;1']
        .getService(Components.interfaces.mozIJSSubScriptLoader)
        .loadSubScript( path_to_file , object_where_file_will_be_loaded ); }
    }

    var our_scope_object = {};

    // USING:

    JS_Loader( 'some_path to chrome:// or resource://' , our_scope_object);

    /*

    В данном случае все, что было "глобального" в нашем 'some_path' станет частью our_scope_object.
    Кроме того, в момент загрузки для этого 'some_path' this будет являться our_scope_object

    */


    * This source code was highlighted with Source Code Highlighter.


    Если данный вариант не устраивает по причине известных „глюков“, и, кстати, по причине того, что при валидации свалится Warning, то „совсем правильно“ нужно делать через:

    Components.utils.import( path_to_file , object_where_file_will_be_loaded )

    * This source code was highlighted with Source Code Highlighter.


    Хотя, здесь будут немножко другие „заморочки“.

  3. Вообще, можно, конечно, убрать все действия по „навешиванию“ „addEventListener“ для контролов в отдельную функцию… Но тогда нужно не забыть что бывают „казусы“, если пытаться регистрировать события на несуществующие контролы.

    Кроме всего прочего в этом нам поможет!:

      window.addEventListener("aftercustomization", function(evt){

        [ действия, которые производятся для регистрации событий <br>после того, как пользователь добавил или удалил Вашу кнопку с панели toolbar ]
        
      }, false);


    * This source code was highlighted with Source Code Highlighter.




Напоследок, позвольте пару „приятных“ мелочей:

Работа со свойствами „расширения“.

  var ADDON_ID = '[ em:id из install.rdf ]';
  var EXTENSION = {};
  if (Application.extensions){ EXTENSION = Application.extensions.get(ADDON_ID); }
  else{ Application.getExtensions(function(extensions){ EXTENSION = extensions.get(ADDON_ID); }); }
  return {
     ext : function(){ return EXTENSION; }
    , ver : function(){ return EXTENSION.version; }
  }


* This source code was highlighted with Source Code Highlighter.


Путь к расширению в файловой системе:

  var addonLocation = '';
  Components.utils.import("resource://gre/modules/AddonManager.jsm"); 
  AddonManager.getAddonByID( '[ em:id из install.rdf ]', function(addon) {
    addonLocation = addon.getResourceURI("").QueryInterface(Components.interfaces.nsIFileURL).file;
  } );


* This source code was highlighted with Source Code Highlighter.


Моргалка...

  var blinker = function(cnt){
    for(var i = 1; i < cnt; i++){
      (function(ist){
        // window.alert('' + ist + ' ' + (ist % 2));
        window.setTimeout( function(){ show_status((ist % 2)); }, ist*450 );
      })(i);
    }
  }
  
  /*
  
  show_status, например, принимает 1 или 0
  и в зависимости от этого меняет свойства объекта
  можно "поморгать" шрифтом на кнопке, или сделать ещё что-нибудь "подмигивающее"
  
  */


* This source code was highlighted with Source Code Highlighter.


В заключение хотелось бы привести пару ссылочек:

В комментариях не нуждается: addons.mozilla.org/en-US/developers
Mozilla Developer Network: developer.mozilla.org/en-US

Просмотрим „это“ с заботой.:
XUL Specification: developer.mozilla.org/en/XUL
developer.mozilla.org/en/JavaScript
developer.mozilla.org/en/DOM
developer.mozilla.org/en/XUL_Overlays
developer.mozilla.org/en/XUL_controls

А это обязательно просмотрим!:
developer.mozilla.org/en/Setting_up_extension_development_environment
developer.mozilla.org/en/Extension_Frequently_Asked_Questions
developer.mozilla.org/en/Creating_toolbar_buttons
developer.mozilla.org/en/XUL_School/Adding_Toolbars_and_Toolbar_Buttons
developer.mozilla.org/en/XUL_School/Adding_Events_and_Commands
developer.mozilla.org/en/Addons/Add-on_Manager/Code_Samples
developer.mozilla.org/en/chrome_registration
developer.mozilla.org/en/XPCOM_Interface_Reference/mozIJSSubScriptLoader

А об этом когда-нибудь, наверное, вспомним…:
developer.mozilla.org/en/Code_snippets
developer.mozilla.org/en/XUL_School/Handling_Preferences
developer.mozilla.org/en/Security_best_practices_in_extensions
Tags:
Hubs:
+19
Comments13

Articles

Change theme settings