Поводом для этой статьи послужила неприятная ситуация, которая периодически возникает при переключении табов при помощи команды iimPlayCode("TAB T=1");
. Если вы не используете JS в своих iMacros-скриптах, то вероятность столкнуться с проблемой мала. Но к нам, продвинутым пользователям iMacros — это не относится.
Баги с табами в iMacros
Откройте 3 вкладки в браузере и создайте макрос test.js:
iimPlayCode("TAB T=1");
Теперь перейдите в первую вкладку и запустите его — мы остались на первой вкладке — замечательно!
Теперь перейдите во вторую и потом в третью вкладку и запустите. Ничего не происходит. Как-то это не очень круто, я все же ожидал, что при запуске из любой вкладки — мы будем переключаться на первую.
Чтобы лучше понять, как оно работает, измените код на следующий:
iimPlayCode("TAB T=2");
Теперь снова попробуйте запустить из каждой вкладки.
Из первой вкладки перекидывает на вторую — замечательно!
Из второй вкладки перекидывает на третью, как-то это не правильно, мне бы хотелось остаться на второй вкладке после выполнения кода.
Из третьей вкладки он включает таймер и в итоге выдает ошибку RuntimeError: Tab number 2 does not exist, line 1 (Error code: -971)
Это никуда не годится, зато теперь ясна логика работы этой функции — при запуске макроса, под номером один — будет текущий таб, под номером два — идущий за ним таб. Вы можете попробовать поэкспериментировать с iimPlayCode("TAB T=0");
или с iimPlayCode("TAB T=-1");
Такой вариант меня абсолютно не устраивает, потому что я хочу полностью и точно контролировать браузер и подобное поведение неприемлемо.
Решение проблемы при помощи XPCOM и функций расширения Firefox
XPCOM (англ. Cross Platform Component Object Model) — кросплатформенная компонентно-ориентированная модель разработки ПО от Mozilla. XPCOM позволяет создавать компоненты на JavaScript и других языках. Осуществляется это через слой абстракции XPConnect, а интерфейсы классов берутся из бинарных библиотек типов.
Если говорить простым языком — нам доступен огромный набор объектов, классов, компонентов, которые позволяют получить доступ к практически любым функциям браузера и даже позволяют взаимодействовать с операционной системой, например, чтение\запись файлов.
Вы можете открыть консоль в фаербаге и запустить макрос со следующим кодом:
window.console.log(Components); window.console.log(Components.classes); window.console.log(Components.interfaces);
И исследовать содержимое этих объектов, кликая по ним в консоли и разворачивая древовидную структуру.
Мы будем использовать компонент и сервис Window Mediator
.Поскольку каждый раз для переключения табов писать простыню кода неудобно, мы обернем весь функционал в небольшой JS-объект и сможем переключаться между вкладками одной маленькой, короткой функцией.
Давайте попробуем:
var Tabs = { _browser: function () { var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"] .getService(Components.interfaces.nsIWindowMediator); return wm.getMostRecentWindow("navigator:browser").gBrowser; }(), go: function (tabIndex) { this._browser.selectedTab = this._browser.tabContainer.childNodes[tabIndex - 1]; } };
Мы создали небольшой Javascript-объект, с которым теперь очень удобно работать. Нижнее подчеркивание для функции _browser
говорит нам, что она приватная и используется только внутри объекта, можно этого не делать, но это хорошая практика написания красивого и понятного кода. Хочу обратить внимание, что эта функция вызывается только один раз, при первом вызове Tabs.go(), после чего она перезаписывается и в ней оказывается объект gBrowser со всеми его свойствами и методами.
Использовать очень просто:
Tabs.go(1); iimPlayCode("WAIT SECONDS=3"); Tabs.go(2); iimPlayCode("WAIT SECONDS=3"); Tabs.go(3);
Перейдите в браузер с тремя или более открытыми сайтами и попробуйте запустить этот код из любой вкладки. Все работает корректно, и поведение такое, как и ожидается, также наша маленькая функция не мешает работе других команд iMacros.
Пишите ваши вопросы, пожелания и дополнения в комментариях.
Спасибо за ваш блог, очень много полезного.
Помогите доработать пожалуйста:
var wm = Components.classes[«@mozilla.org/appshell/window-mediator;1»]
.getService(Components.interfaces.nsIWindowMediator);
var mainWindow = wm.getMostRecentWindow(«navigator:browser»);
kolvo = mainWindow.gBrowser.tabContainer.childNodes.length
if(kolvo > 1){
mainWindow.gBrowser.selectedTab = mainWindow.gBrowser.tabContainer.childNodes[2];
window.close();
}
В условии хочу сделать переключение на 1-ую и закрытие других вкладок:
mainWindow.gBrowser.selectedTab = mainWindow.gBrowser.tabContainer.childNodes[1];
mainWindow.gBrowser.removeTabsToTheEndFrom(gBrowser.mCurrentTab);
Подскажите пожалуйста
Спасибо за пост! Действительно работает. Очень помогли!
Здрасте, спасибо за ваши труды! iimPlayCode(«WAIT SECONDS=3»); При проходе данной строки просит закрыть все вкладки. Как избавиться от этого сообщения?
Добрый день. Спасибо, у вас получается классный полезный код! Могу поделиться своими библиотеками.
Для перебора вкладок и поиска ранее открытого сайта я дописал себе определение общего количества вкладок:
count: function () {
return (this._browser.tabContainer.childNodes.length);
}
Буду потихоньку статью в комментариях набирать ) Очень хороший материал, полезный, здесь: https://developer.mozilla.org/en-US/docs/Archive/Add-ons/Tabbed_browser
openAndReuseOneTabPerURL — функция позволяет находить вкладку по URL и открывать ее. Если вкладки с нужным URL нет — открывается новая вкладка.
А как можно определить индекс текущей открытой вкладки?
Хотя, нашел сам. Может пригодится кому…
Дополняем JS-объект из статьи. Возвращаем индекс открытой вкладки:
index: function () {
return (this._browser.tabContainer.selectedIndex + 1);
}
Применяем:
Tabs.index()