Как стать автором
Обновить

Расширение Google Chrome — корзина вкладок

Программирование *

Пролог


Доброго времени суток, уважаемый посетитель ХабраХабра!
В этот очередной в нашей с Вами жизни день знаний (который я, однако, провел исключительно за работой, а не учебой), под влиянием данной статьи, пишу повествование о моем опыте создания расширения для Google Chrome – TabBasket (не знаю, как Вы, но я на названия неказист). Статья оформлена в смешанном стиле – перекликаются элементы урока, а так же пояснения по коду и описание ключевых моментов.
Прежде чем перейти непосредственно к главному, замечу, что мои знания CSS немного сумбурны, опыта было совсем немного, поэтому какое-то мое решение может показаться слегка странным.

Что мы имеем


Для написания расширения нам практически не нужны никакие инструменты, всю работу можно провести хоть в блокноте или gedit. Выбираем редактор на свой вкус (лично я в таких случаях пользуюсь либо Notepad++, либо NetBeans; первое легче, второе функциональнее, выбор как всегда за Вами).

Ближе к делу


Перво-наперво исходники.

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

{
"name" : "TabBasket ",
"version" : "1.5",
"permissions" : [
"tabs", "http://*/*"
],
"background_page" : "back.html",
"browser_action" : {
   "default_title": "Closed tabs",
   "default_icon": "icon.png",
   "popup": "popup.html"
}
}


* This source code was highlighted with Source Code Highlighter.

Два элемента back.html и popup.html будут постепенно рассмотрены (созданы, написаны) далее. Никаких неожиданной в манифесте нет, все достаточно прозрачно. Для большего понимания процесса, кратенько изложу идею. Замечательная страничка back.html работает в тени, не имеет внешнего вида, её код стартует сразу после установки расширения или запуска браузера, если расширение уже было установлено. Ее роль – установить обработчики для событий создания, удаления или обновления вкладок. Popup.html непосредственно формирует список закрытых вкладок, позволяет восстановить какую – либо из них.

Двигаемся дальше. Разбираем файл back.html:

/* Tab constructor function. */
function AnyTab()
{
this.id = 0
this.url = ""
this.name = ""
this.favicon = ""
}


* This source code was highlighted with Source Code Highlighter.

Функция-конструктор для объекта, хранящего информацию о вкладке. Язык позволяет создать инициализированный значениями по умолчанию объект разными методами, я выбрал именно этот. Хранится id вкладки (выдается самим браузером), url(что это о_О?), name (название сайта) и favicon (иконка сайта, с ней отдельная свистопляска). Далее по коду

var active = []
var closedTabs = []
var maxTabCount = 15


* This source code was highlighted with Source Code Highlighter.

Нам понадобятся два массива – активных (открытых) вкладок и закрытых. Максимальное число вкладок я выбрал (по-моему мнению) оптимальное. Вешаем обработчики на события

chrome.tabs.onUpdated.addListener(onTabUpdated)
chrome.tabs.onRemoved.addListener(onTabRemoved)
chrome.tabs.onCreated.addListener(onTabCreated)


* This source code was highlighted with Source Code Highlighter.

В таком случае onTabUpdated, onTabRemoved И onTabCreated – имена функций обработчиков. Теперь немного приоткроем завесу тайны – когда вкладка создается, необходимо запомнить необходимые нам характеристики (ссылку, название и др.). Делается это потому, что в функцию onTabRemoved приходит только id закрытой вкладки, а ее самой уже и в помине нет. Поэтому при закрытии вкладки она ищется по своему id в массиве active(кстати ее там может и не быть – если расширение было установлено в момент, когда в программе уже были открытие вкладки), данные копируются в массив closedTabs и, соответственно, удаляются из массива active. Теперь мы имеем полную информацию о закрытой вкладке и без труда можем ее восставить! Внимательный читатель, однако, обратит внимание на то, что я не упомянул про функцию onTabUpdated. У нее особенная роль, вызванная следующей особенностью (читай проблемой) – в функцию onTabCreated совсем не сразу приходит вся информация о вкладке. Невооруженным глазом видно, как у новоиспеченной вкладки меняется заголовок, прогружается иконка. Эти данные позднее дотекают в функцию onTabUpdated.

Роль рабочей лошадки играет функция updateTab. Если первым параметром передать -1, то просто напросто создастся новая вкладка. В другом случае туда передается id вкладки, информацию о которой обновилась.

function updateTab(index, tab) {
    /* Add new tab. index = -1 passed in onTabCreated */
    if (index === -1) {
      var newTab = new AnyTab()
      newTab.id = tab.id
      newTab.url = tab.url
      newTab.name = tab.title
      newTab.favicon = tab.favIconUrl
      active.push(newTab)
    }
    /* Or update tab. Find index first. */
    else {
      var j, tbCt = active.length

      for ( j = 0; j < tbCt; j++ ) {
        if ( index == active[j].id )
          break
      }
      
      if ( j == tbCt ) {
        console.log("updateTab not found ID "+index)
        return
      }
      
      active[j].id = tab.id
      active[j].url = tab.url
      active[j].name = tab.title
      active[j].favicon = tab.favIconUrl || "icon.png" 
    }
  }


* This source code was highlighted with Source Code Highlighter.

Самая сложная часть позади, теперь немного о внешнем виде и popup.html?
Интерфейс данного расширения – всплывающее окошко со списком сайтов, слева иконка для более интуитивного использования. Так же сверху имеется div класса toolArea – это область инструментов, пока там почетно красуется одна единственная кнопочка – очистка списка.

JavaScript’овая начинка данной странички достаточно типична и прозрачна, ключевой момент здесь – доступ к back.html, то бишь ко всем функциям и переменным, объявленным там, через вызов метода chrome.extension.getBackgroundPage().

Скрипт объемный, но если разбить его на логические части, получается очень просто:
  • Создание списка
  • Задание обработчиков mouseover и mouseout
  • Реализация функций клика по элементу списка, а так же наведения курсора

Это уже чистый, простой JavaScript, с небольшими примесями уже использованных нами приемов.
Создание:

var back = chrome.extension.getBackgroundPage()
  for ( var k = back.closedTabs.length - 1; k >= 0; k--) {  
    document.write ("<div id='" + back.closedTabs[k].id + "' onclick='divClick(this)' class='divClass'>")
    document.write ("<img src=" + back.closedTabs[k].favicon + " class='imgClass'>")
    var txtName = back.closedTabs[k].name
    if (txtName.length > 40)
        txtName = txtName.substr(0, 35) + "..."
    document.write ("<span class='labelClass'>" + txtName + "</span>")
    document.write ("</div>")
  }


* This source code was highlighted with Source Code Highlighter.

Обработчики:

var divs = document.getElementsByTagName("div");
  for (var i = 0; i < divs.length; i++)
  {
    if (divs[i].id === "toolDiv") {
      divs[i].onclick = cleanToolClick
    } else {
      divs[i].onmouseover = mouseOverEvent
      divs[i].onmouseout = mouseOutEvent
    }
  }


* This source code was highlighted with Source Code Highlighter.

В определенный момент разработки подловил себя на мысли, что при создании новой вкладки в divClick с помощью функции chrome.tabs.create (которая, кстати, принимает объект аргументов, которые легче подсмотреть в документации, чем запоминать из статьи), вкладка автоматически попадает в onTabCreated, так что не нужно беспокоиться о добавлении в массив active вкладок, созданных программно!

ToDo


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

Эпилог


В результате проделанной работы получаем достаточно полезное в хозяйстве и быту расширение, реализующее столь необходимую функциональность, как браузерная корзина. В статье рассмотрены основные приемы работы с вкладками, принципы тесного взаимодействия структурных элементов расширения Google Chrome. Создание расширений – очень интересное и увлекательное занятие! Желательным требованием является базовое знание html, css и JavaScript, однако не обязательным – перед живым интересом ничто не устоит!
И принимаю замечания по коду, так как считаю себя новичком в JS!
Удачи Вам в начинаниях, дерзайте, экспериментируйте, создавайте!
Теги:
Хабы:
Всего голосов 10: ↑7 и ↓3 +4
Просмотры 13K
Комментарии Комментарии 10