Наблюдатель за загрузкой страницы в настраиваемом браузере xul:

В своем расширении firefox я создаю элемент xul: browser. Я хочу иметь наблюдателя, который перехватывает любые изменения URL-адреса во встроенном браузере и открывает URL-адрес на новой вкладке браузера (в основном браузере). Я также хотел бы, чтобы новые окна, порожденные окном xul: browser, открывались во вкладке, а не в новом окне браузера.

Я создал обозреватель, который работает, но я еще не знаю, как применить его только к элементу xul: browser.

function myFunction(){
   var container = jQuery("#container")[0];
   var new_browser_element = document.createElement('browser');
   container.appendChild(new_browser_element);

   var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
   observerService.addObserver(myObserver, "http-on-modify-request", false);
}


var myObserver = {
   observe: function(aSubject, aTopic, aData){
      if (aTopic != 'http-on-modify-request'){
         aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
         // alert(aSubject.URI.spec);
        // Now open url in new tab
      } 
   },

   QueryInterface: function(iid){
      if (!iid.equals(Components.interfaces.nsISupports) &&
      !iid.equals(Components.interfaces.nsIObserver))
      throw Components.results.NS_ERROR_NO_INTERFACE;

      return this;
   }
};

person makeee    schedule 11.10.2009    source источник
comment
в общем, вы хотите проверить контекст, из которого исходит запрос, затем отменить его и указать браузеру открыть новую вкладку с URL-адресом и заголовками предыдущего запроса? (Я не думаю, что есть способ изменить цель запроса после его запуска, но я посмотрю)   -  person Jonathan Fingland    schedule 11.10.2009
comment
Да, именно этим я и хочу заниматься.   -  person makeee    schedule 11.10.2009
comment
решение на основе http-on-modify-request не отслеживает изменения URL-адресов, оно отслеживает нагрузки HTTP. Для изменения URL-адреса вам понадобится прослушиватель прогресса.   -  person Nickolay    schedule 14.01.2010


Ответы (1)


Вы можете попробовать:

var myObserver = {
   observe: function(aSubject, aTopic, aData){
      if (aTopic == 'http-on-modify-request')
              {
                aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
                var url = aSubject.URI.spec;
                var postData ;
                if (aSubject.requestMethod.toLowerCase() == "post") 
                {
                  var postText = this.readPostTextFromRequest(request);
                  if (postText)
                  {
                    var dataString = parseQuery(postText);
                    postData = postDataFromString(dataString);
                  }
                }

                var oHttp = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);

                var interfaceRequestor =   oHttp.notificationCallbacks.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
                var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); 


                //check if it is one of your mini browser windows
                if (jQuery(DOMWindow).hasClass('mini_browser')) 
                {

                  openInTab(url, postData);

                  var request = aSubject.QueryInterface(Components.interfaces.nsIRequest);
                  request.cancel(Components.results.NS_BINDING_ABORTED);

                }

      } 
   },

   QueryInterface: function(iid){
      if (!iid.equals(Components.interfaces.nsISupports) &&
          !iid.equals(Components.interfaces.nsIObserver))
        throw Components.results.NS_ERROR_NO_INTERFACE;

      return this;
   },

   readPostTextFromRequest : function(request) {
     var is = request.QueryInterface(Components.interfaces.nsIUploadChannel).uploadStream;
     if (is)
     {
       var ss = is.QueryInterface(Components.interfaces.nsISeekableStream);
       var prevOffset;
       if (ss)
       {
         prevOffset = ss.tell();
         ss.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0);
       }

       // Read data from the stream..
       var charset = "UTF-8";
       var text = this.readFromStream(is, charset, true);

       // Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
       // since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
       if (ss && prevOffset == 0) 
         ss.seek(Components.interfaces.nsISeekableStream.NS_SEEK_SET, 0);

       return text;
     }
     else {
       dump("Failed to Query Interface for upload stream.\n");
     }
   }
   return null;
 },

 readFromStream : function(stream, charset, noClose)    
 {
    var sis = Components.classes["@mozilla.org/binaryinputstream;1"]
                     .getService(Components.interfaces.nsIBinaryInputStream);

    sis.setInputStream(stream);

    var segments = [];
    for (var count = stream.available(); count; count = stream.available())
      segments.push(sis.readBytes(count));

if (!noClose)   
      sis.close();

    var text = segments.join("");
    return text;
  }
};

function openInTab(url, postData)
{
  var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
        .getService(Components.interfaces.nsIWindowMediator);
  var recentWindow = wm.getMostRecentWindow("navigator:browser");
  if (recentWindow) 
  {
    // Use an existing browser window, open tab and "select" it
    recentWindow.gBrowser.selectedTab = recentWindow.gBrowser.addTab(url, null, null, postData);
  } 
}

function parseQuery() {
  var qry = this;
  var rex = /[?&]?([^=]+)(?:=([^&#]*))?/g;
  var qmatch, key;
  var paramValues = {};
  // parse querystring storing key/values in the ParamValues associative array
  while (qmatch = rex.exec(qry)) {
    key = decodeURIComponent(qmatch[1]);// get decoded key
    val = decodeURIComponent(qmatch[2]);// get decoded value

    paramValues[key] = val;
  }
  return paramValues;
}

function postDataFromString(dataString)
{
  // POST method requests must wrap the encoded text in a MIME
  // stream
  var stringStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
               .createInstance(Components.interfaces.nsIStringInputStream);
  if ("data" in stringStream) // Gecko 1.9 or newer
    stringStream.data = dataString;
  else // 1.8 or older
    stringStream.setData(dataString, dataString.length);

  var postData = Components.classes["@mozilla.org/network/mime-input-stream;1"].
           createInstance(Components.interfaces.nsIMIMEInputStream);
  postData.addHeader("Content-Type", "application/x-www-form-urlencoded");
  postData.addContentLength = true;
  postData.setData(stringStream);

  return postData;
}

Я обновлю это, чтобы немного заполнить пробелы.

изменить: см. http://forums.mozillazine.org/viewtopic.php?p=2772951#p2772951, чтобы узнать, как получить исходное окно запроса.

Запросить код отмены на http://zenit.senecac.on.ca/wiki/index.php/Support_For_OpenID.

см. http://mxr.mozilla.org/mozilla-central/source/netwerk/base/public/nsIRequest.idl для получения подробной информации о nsIRequest.

См. http://forums.mozillazine.org/viewtopic.php?p=2404533#p2404533 и https://developer.mozilla.org/en/XUL/Method/addTab для определения addTab.

parseQuery поступает из http://blog.strictly-software.com/2008/10/using-javascript-to-parse-querystring.html.

См. https://developer.mozilla.org/en/Code_snippets/Post_data_to_window#Post_data_to_window#Post_data_prodata_window# a> о том, как обрабатывать данные публикации в форме, подходящей для addTab.

ReadPostFromText и ReadTextFromStream оба исходят от firebug (хотя и немного изменены)

person Jonathan Fingland    schedule 11.10.2009
comment
Эй, это прекрасно выглядит! Прямо сейчас я пытаюсь понять, как узнать, исходит ли запрос от моего элемента xul: browser. На самом деле у меня есть несколько элементов xul: browser в любой момент времени, и я хотел бы перехватывать запросы от всех из них. Возможно ли, что я могу просто дать каждому элементу браузера одно и то же имя класса: new_browser_element.setAttribute ('class', 'mini_browser'); А затем: if (DOMWindow.attr ('class') == 'mini_browser') .... Очевидно, что это неверно, но будет ли это имя класса содержаться в объекте DOMWindow? - person makeee; 11.10.2009
comment
Вам может понадобиться jQuery (DOMWindow) .hasClass ('mini_browser'). Я подозреваю, что вам нужно использовать jQuery () для доступа к методу hasClass - person Jonathan Fingland; 11.10.2009
comment
добавлена ​​передача пост-данных и проверка класса минибраузера - person Jonathan Fingland; 11.10.2009
comment
Круто, очень близко к этому. Несколько быстрых вопросов: разве не должно быть if (aTopic == 'http-on-modify-request') ..? И ваш код прямо сейчас также загрузит изображения, встроенные в страницу, в новую вкладку, поскольку http-on-modify-request включает все запросы, а не только URL-адрес страницы. Есть идеи, как ограничить его только URL-адресом главной страницы? Большое спасибо! - person makeee; 11.10.2009
comment
ааа, извини. эта часть была из вашего кода, и я недостаточно внимательно ее проверял. исправлено сейчас. Что касается изображений ... это хороший момент. В моем расширении я могу использовать URL-адрес, чтобы ограничить то, что передается TracingListener, но я посмотрю, что я могу узнать для вашего случая. - person Jonathan Fingland; 11.10.2009
comment
как насчет ожидания ответа http-on-explore-response? затем проверьте заголовки на предмет mime-типа и, при необходимости, убейте его? - person Jonathan Fingland; 11.10.2009
comment
Проблема с ожиданием, пока http-on-explore-response заключается в том, что я хочу отменить запрос (поэтому я хочу получить ответ), а затем вместо этого открыть URL-адрес на вкладке. Долго искал, но не смог найти способ различить запрос GET для страницы и запросы GET для различных изображений, CSS и т. Д., Которые есть на странице. Любые идеи? - person makeee; 13.10.2009
comment
как насчет того, чтобы пойти по старой школе и добавить слушателей событий для нажатия и отправки? Обработчик кликов проверит originalTarget и вернет false, если originalTarget (или предок) был ссылкой. - person Jonathan Fingland; 13.10.2009
comment
Спасибо. Мое решение заключалось в том, чтобы jQuery заменил все ссылки hrefs на mysite.com/go/+original_url. Затем моя функция наблюдателя проверяет, есть ли mysite.com/go; находится в запрошенном URL-адресе, и если да, то открывает его во вкладке. Я все равно хотел отслеживать исходящие клики, сначала перенаправляя на свой сайт, так что это убивает двух зайцев одним выстрелом. - person makeee; 13.10.2009