#javascript #firefox #firefox-addon #firefox-addon-sdk
#javascript #firefox #firefox-дополнение #firefox-addon-sdk
Вопрос:
Я пытаюсь создать надстройку Firefox с использованием SDK (версия 1.6), но у меня возникла проблема с вкладками, которые открывает расширение.
Я хотел бы получить вкладку, на которой aContext
находится (узел). Для этого я «получал» окно узла, а затем, в частности, использовал утилиты Tab в SDK getTabForContentWindow()
. Иногда это не работает, вкладка, возвращаемая из getTabForContentWindow()
, равна нулю. Есть ли лучший, более надежный способ получить вкладку узла?
Кроме того, я заметил на странице утилит вкладки, что в нем указано, что он «нестабилен». Должен ли я избегать использования Tab Utils SDK?
Ниже приведен код из main.js:
const {Cc, Ci, Cr, Cu, Cm, components} = require("chrome");
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm");
var winUtils = require('sdk/window/utils');
var tabUtils = require('sdk/tabs/utils');
let policy =
{
classDescription: "my content policy",
classID: components.ID("{2DA54ECA-FBDD-11E3-B3B1-695C1D5D46B0}"),
contractID: "@www.com/policy;1",
xpcom_categories: ["content-policy"],
init: function()
{
let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(this.classID, this.classDescription, this.contractID, this);
let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
for each (let category in this.xpcom_categories)
catMan.addCategoryEntry(category, this.contractID, this.contractID, false, true);
},
// nsIContentPolicy interface implementation
shouldLoad: function(aContentType, aContentLocation, aRequestOrigin, aContext, aMimeTypeGuess, aExtra, aRequestPrincipal) {
console.log("*****");
console.log("aContentLocation.spec [" aContentLocation.spec "] ");
console.log("aContentType [" aContentType "] ");
if (aContext instanceof components.interfaces.nsIDOMNode) {
var node = aContext.QueryInterface(components.interfaces.nsIDOMNode);
var win = getWindow(node);
if (win) {
console.log("window found" );
var selectedTab = tabUtils.getTabForContentWindow(win);
if (selectedTab) {
console.log("tab found" );
var tabId = tabUtils.getTabId(selectedTab);
console.log("Node's tabId:" tabId);
} else {
console.log("tab undefined" );
}
} else {
console.log("win undefined" );
}
}
return Ci.nsIContentPolicy.ACCEPT;
},
shouldProcess: function(contentType, contentLocation, requestOrigin, node, mimeTypeGuess, extra) {
return Ci.nsIContentPolicy.ACCEPT;
},
// nsIFactory interface implementation
createInstance: function(outer, iid) {
if (outer)
throw Cr.NS_ERROR_NO_AGGREGATION;
return this.QueryInterface(iid);
},
// nsISupports interface implementation
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIFactory])
};
policy.init();
var scheduleCheckFilterUpdates = function() {
var tabs = require("sdk/tabs");
tabs.open("http://wikipedia.org");
}
require('sdk/timers').setTimeout(scheduleCheckFilterUpdates, 1000);
function getWindow(node) {
if ("ownerDocument" in node amp;amp; node.ownerDocument)
node = node.ownerDocument;
if ("defaultView" in node)
return node.defaultView;
return null;
}
Ответ №1:
Вы должны иметь в виду, что:
- Не все запросы исходят из окна. (фоновые запросы)
- Не все запросы, исходящие из окна, на самом деле исходят из вкладки. Когда вы запускаете свой код, вы можете видеть, например, запросы на подобные вещи
chrome://browser/skin/tabbrowser/tab-separator.png
, которые загружает само окно браузера (в данном случае для использования в пользовательском интерфейсе). Также имейте в виду, что не все окна верхнего уровня на самом деле являются окнами браузера (browser.xul
). - Даже если это навигация по вкладкам, начальная загрузка (
aContentLocation.spec [http://wikipedia.org/]
) будет исходить из создаваемого нового, не полностью инициализированного окна содержимого, которое еще не связано ни с одной вкладкой. Вкладка на этом этапе остается неподвижнойabout:blank
, и новое окно (wikipedia
) будет заменено только после того, как станет ясно, что это окно может быть полностью создано: запрос не был заблокирован, DNS был разрешен, последовали перенаправления, и окончательный ответ фактически предоставил данные, и эти данные могут быть преобразованы в окно. Например. если бы моя сеть была отключена,wikipedia
окно было бы закрыто до того, как оно было назначено вкладке, и вместо этого были бы созданы документ и окно с ошибкой подключения.
Последний пункт также задокументирован в самом nsIContentPolicy
интерфейсе:
/**
* Should the resource at this location be loaded?
* ShouldLoad will be called before loading the resource at aContentLocation
* to determine whether to start the load at all.
*
* @param aContentType the type of content being tested. This will be one
* one of the TYPE_* constants.
*
* @param aContentLocation the location of the content being checked; must
* not be null
*
* @param aRequestOrigin OPTIONAL. the location of the resource that
* initiated this load request; can be null if
* inapplicable
*
* @param aContext OPTIONAL. the nsIDOMNode or nsIDOMWindow that
* initiated the request, or something that can QI
* to one of those; can be null if inapplicable.
* Note that for navigation events (new windows and
* link clicks), this is the NEW window.
*
* @param aMimeTypeGuess OPTIONAL. a guess for the requested content's
* MIME type, based on information available to
* the request initiator (e.g., an OBJECT's type
* attribute); does not reliably reflect the
* actual MIME type of the requested content
*
* @param aExtra an OPTIONAL argument, pass-through for non-Gecko
* callers to pass extra data to callees.
*
* @param aRequestPrincipal an OPTIONAL argument, defines the principal that
* caused the load. This is optional only for
* non-gecko code: all gecko code should set this
* argument. For navigation events, this is
* the principal of the page that caused this load.
*
* @return ACCEPT or REJECT_*
*
* @note shouldLoad can be called while the DOM and layout of the document
* involved is in an inconsistent state. This means that implementors of
* this method MUST NOT do any of the following:
* 1) Modify the DOM in any way (e.g. setting attributes is a no-no).
* 2) Query any DOM properties that depend on layout (e.g. offset*
* properties).
* 3) Query any DOM properties that depend on style (e.g. computed style).
* 4) Query any DOM properties that depend on the current state of the DOM
* outside the "context" node (e.g. lengths of node lists).
* 5) [JavaScript implementations only] Access properties of any sort on any
* object without using XPCNativeWrapper (either explicitly or
* implicitly). Due to various DOM0 things, this leads to item 4.
* If you do any of these things in your shouldLoad implementation, expect
* unpredictable behavior, possibly including crashes, content not showing
* up, content showing up doubled, etc. If you need to do any of the things
* above, do them off timeout or event.
*/
short shouldLoad(in nsContentPolicyType aContentType,
in nsIURI aContentLocation,
in nsIURI aRequestOrigin,
in nsISupports aContext,
in ACString aMimeTypeGuess,
in nsISupports aExtra,
[optional] in nsIPrincipal aRequestPrincipal);
Заключение
Насколько я могу судить, утилиты вкладок работают так, как ожидалось, как и код из ответа @Notidart. Неверно ожидать, что новый документ будет немедленно назначен вкладке.
Кроме того, я заметил на странице утилит вкладки, что в нем указано, что он «нестабилен». Должен ли я избегать использования Tab Utils SDK?
Что ж, это зависит от вашего личного вкуса. нестабильный, по сути, означает, что API может снова измениться или даже быть удален снова в более поздней версии браузера. Альтернативы, такие как using window.gBrowser
, по крайней мере, столь же нестабильны, как и SDK API (также могут измениться в любой момент), поэтому, IMHO, нет ничего, что можно было бы получить, избегая этого SDK API, при условии, что он каким-то образом не оказался глючным (но если это произойдет, вы все равно можете переключиться начто-то еще).
Комментарии:
1. Дамба, я просто не могу конкурировать. Bookmaring, черт возьми, такой хороший материал.
2. Третий пункт списка выше (о том, что вкладка не полностью инициализирована) — это то, что, как я думал, может произойти. Спасибо за подтверждение.
Ответ №2:
Это способ, который вы можете попробовать. Из окна содержимого вы получаете окно dom. Затем в окне dom вы выполняете getTabForContentWindow:
//var node = focused element?
var contentWin = node.ownerDocument.defaultView;
var DOMWin = contentWin.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
if (DOMWin.gBrowser amp;amp; DOMWin.gBrowser.tabContainer) {
var tab = DOMWin.gBrowser._getTabForContentWindow(contentWin);
} else {
//the node is in a firefox window with no tabs
}
Возможно, это окно poup без вкладок.
Комментарии:
1. Спасибо за предложение, но вкладка вернулась в строке: var tab = DOMWin.gBrowser._getTabForContentWindow(contentWin); для исходного документа значение null. Это то же самое поведение, которое я наблюдаю с моим исходным кодом.
2. Что такое «начальный документ»? Я хочу воспроизвести, чтобы протестировать его.