Home

KiberInfinity edited this page Oct 15, 2016 · 41 revisions

Оглавление

Сборка расширения из исходников

  • Запустить _build.bat (Windows) или _build.sh (Linux/Mac).
    Скрипты из папки source/ скопируются в папку builds/[браузер]/
  • запустить сборку для нужного браузера:
    • Если у вас установлен Python, запускаем builds/_[браузер]_pack.bat
    • Если нет, но установлен WinRAR - то тогда builds/_winrar_[браузер].bat

Cобранное расширение появится в папке builds/.

Расширенные настройки

Для целей отладки расширения существуют дополнительные настройки, которые скрыты. См. страницу Расширенные настройки.

Принцип организации работы расширения

VkOpt состоит из двух вспомогательных скриптов, исполняемых в песочницах браузеров: background.js и content_script.js - далее "загрузчик".

Их можно считать одним целым. Их основная задача - инъектировать нужные скрипты в страницы. Загрузчик срабатывает в каждой странице vk.com и в каждом фрейме на ней.

Скрипты инъектируются в контекст страницы, а не исполняются в песочнице расширения, потому что они тесно взаимодействуют со скриптами самого сайта, которые, очевидно, видно только в контексте страницы.

Есть всего два варианта набора скриптов, которые инъектирует загрузчик:

  • для основной страницы (для window.top)
  • для фрейма (запускаются в каждом фрейме)

Конкретные списки скриптов можно посмотреть в начале background.js:

   packed_scripts:[
      // Набор для основной страницы.
      {
         // 1 - для window.top, 0 - для фреймов. Кто-нибудь, назовите это адекватнее!
         "in_frames":1,

         // Отвечает за время инъектирования - до или после DOMContentLoaded/Load.
         "run_at":0,

         // Можно смело сжимать эти файлы в таком порядке.
         "files":[
            "vkopt.js",
            "vk_face.js",
            "vk_lib.js",
            "vk_main.js",
            "vk_media.js",
            "vk_page.js",
            "vk_resources.js",
            "vk_settings.js",
            "vk_skinman.js",
            "vk_txtedit.js",
            "vk_users.js",
            "vklang.js"
         ],

         // Инфа для загрузчика. Назначение вполне очевидно, хотя тоже можно рефакторить.
         "domain":"vkontakte\\.ru|vk\\.com",
         "exclude":"|notifier\\.php|im_frame\\.php|about:blank|i",
         "api_enabled":true
      },

      // Набор для фреймов.
      {
         // in_frames не указано, значит, нестрого равно 0 - для фреймов.
         // Всего один файл.
         "files":["vk_lib.js"],

         "domain":"vkontakte\\.ru|vk\\.com|vk\\.me|userapi\\.com",
         "exclude":"|notifier\\.php|im_frame\\.php|about:blank|i"
      }
   ]

Механизм плагинов

Чтобы по всякой мелочи не править код вкопта для подключения к часто используемым местам в 2.х версии был реализован механизм плагинов.
Текущая версия вкопта 3.x полностью состоит из отдельных модулей, напрямую не взаимодействующих между собой (за некоторыми исключениями), и помещаемых в объект vkopt примерно так:

vkopt['myModuleName'] = {
  обработчик1: function(...){ ... },
  handler2: function(...){ 
     vkopt.myModuleName.mega_func( ... )
  },
  ...
  mega_func: function(...){ ... },
}

Опрос интересующего обработчика у всех модулей производится подобным вызовом

var result_array = vkopt_core.plugins.call_modules('названиеОбработчика', аргумент1, агрумент2, ..., аргументN);

На выходе получаем массив с результатами выполнения обработчиков модулей, если обработчики с там названием были у них обнаружены. В обработчик в модуль передаются аргументы переданные после названия обработчика, если же в качестве обработчика у модуля указана не функция, то в result_array попадёт то, что указано вместо функции (строка, объект и т.д) Т.е существуют обработчики вызываемые как и ядром вкопта, так и другими модулями. Это нужно например в том случае, если мы добавили своим модулем какую-то менюшку, в которую, возможно, какой-то другой модуль захочет добавить и свои пункты тоже. В этом случае наш модуль при генерации меню вызывает нечто такое:

var additional_items = vkopt_core.plugins.call_modules('onMyCoolMenuItems', 'id1'); // в текущем примере additional_items = [['item1','item2','item3'],['item4_id1','item5_id1']];

А в другие модули выглядят как-то так:

vkopt['extend_cool_menu'] = {
  onMyCoolMenuItems: function(user_id){
     return ['item1','item2','item3']
  }
}

vkopt['menu_extender'] = {
  onMyCoolMenuItems: function(user_id){
     return ['item4_'+user_id,'item5_'+user_id]
  }
}

Пример кода подключения модуля к существующим обработчикам вкопта (если код располагается в файлах расширения, то вызов vkopt_core.plugins.delayed_run не обязателен):

   var m = {
      id: 'vkopt_any_plugin',
      // <core>
      onInit:                 function(){},                                // выполняется один раз после загрузки страницы
      onLibFiles:             function(file_name){},                       // место для инъекций - срабатывает при подключении нового js-файла c именем file_name движком контакта через stManager.
      onLocation:             function(nav_obj,cur_module_name){},         // вызывается при переходе между страницами, nav_obj - распарсенный в объект URL страницы
      onRequestQuery:         function(url, query, options){}              // вызывается перед выполнением запроса через ajax.post. Если функция вернёт false, то запрос выполнен не будет. Можно изменять поля объектов query и options
      onResponseAnswer:       function(answer,url,params){},               // перехват ответов на ajax-запросы выполняемые скриптами vk. answer - массив аргументов передаваемых потом в коллбек аякс-запроса, для модификации изменять только его элементы, url и объект params позволяют понять, куда был направлен запрос. 
      onCmd :                 function(command_obj){},          // слушает сообщения отосланные из других вкладок вк через vkopt.cmd(command_obj)
      processNode:            function(node, params){}                     // обработка элемента
      processLinks:           function(link, params){},                    // обработка элемента ссылки <a>
      onModuleDelayedInit:    function(plugin_id){},                       // реакция нашего модуля на то, что подключился какой-то другой модуля, опоздавший появиться до полной загрузки страницы.
      onElementTooltipFirstTimeShow: function(ett, ett_options)            // реакция на первый показ ElementTooltip, при создании его контента. На момент вызова в элементе ett._ttel уже есть контент. По ett._opts.id можно определить к чему тултип относится. Например через это реализовано подсовывание доп. пунктов в "Ещё" просмотрщика фото

      // <settings>
      onSettings:             function(){} || {}                           // возвращаем объект с перечисленными по категориям настройками этого модуля
      onOptionChanged:        function(option_id, val, option_data){},     // реакция на изменение опции
      firstRun:               function(){}                                 // вызывается при первом запуске (не найдены ранее прописанные настройки vkopt'a), 
                                                                           // P.S. вкопт из хранилища расширения восстанавливает только данные из своего конфига, если они были сохранены,
                                                                           // тогда это первым запуском не считается, но в локальном хранилище могут отсутствовать данные от других модулей, 
                                                                           // хранящих инфу не через vkopt.settings.get | vkopt.settings.set

      // <audio>
      onAudioRowMenuItems: function(audio_info_obj){},                     // вернуть массив из строк с пунктами-ссылками "<a>..</a>"

      // <wall>
      onDatepickerCreate: function(args){},                                // вызывается при создании селектора даты new Datepicker(), args - массив аргументов переданных в конструктор
   };
   window.vkopt = (window.vkopt || {});
   window.vkopt[m.id] = m;
   if (window.vkopt_core_ready) vkopt_core.plugins.delayed_run(m.id);      // запускает модуль, если мы опоздали к загрузке страницы, провоцирует вызов события onModuleDelayedInit

Возвращаемая для обработчика onSettings структура выглядит так:

   onSettings:{
      "Категория":{  // Название категории подставляется как ID строки из vk_lang.js. По умолчанию используются такие категории: Media, Users, vkInterface, Messages, Others, Extra
         "[id_опции]":{
            title: 'ID строки из ленга, либо текст без локализации',
            class_toggler: true // указывает, что при включенной опции нужно добавлять к тегу <html> css-класс с именем "vk_[id_опции]",
            info: '', // TODO: будет использоваться для пометок опций предупреждениями
            need_reload: true // TODO: будет показывать пользователям, что для применения этой опции нужно обновить страницу

         }
      }
   },

Пример модуля для выбора кастомного цвета фона сайта

Функции, доступные в VkOpt-e

VkOpt предоставляет публичный API для плагинов VkOpt и сторонних расширений. См. страницу Публичный API расширения.

AMO