From:  Andre Pang <ozone@algorithm.com.au>
Date:  23 Jan 2005 23:42:55 Hong Kong Time
Newsgroup:  news.mozilla.org/netscape.public.mozilla.netlib
Subject:  

Re: Launching chromes via nsIContentHandler

NNTP-Posting-Host:  rheet.mozilla.org

Christian Biesinger wrote:

> On Fri, Jan 21, 2005 at 03:56:39PM +1100, Andre Pang wrote:
> 
>>typed the http://www.example.com/data.foo URL, i.e. I'm trying to look 
>>like a plugin.  From a webpage author's point of view, I kind of want 
>>to "redirect"  to 
>>, but 
>>still have the location bar to still display the original 
>> URL.
> 
> Oh, I see... we don't really have a good way to do this. What you can
> maybe do is: Implement a stream converter (nsIStreamConverter) that
> converts from application/x-foo to application/vnd.mozilla.xul+xml. In
> its OnStartRequest, it could create a channel for the chrome:// URL of
> your viewer, and give it the stream listener you got in asyncConvert.
> Your OnDataAvailable and OnStopRequest implementations would do nothing.
> 
> It's kinda hacky... and I'm unsure whether you get chrome privileges
> with that. To get the content URL, you may need to use
> document.location.href itself, instead of parsing the URL and finding a
> ?.

Hi Christian!  Well, I have good news and bad news for you ...

The good news, is your suggestion worked :).  I created an 
nsIStreamConverter and did as you said, and I did actually manage to get 
the data.foo URL displayed in the location bar, with the chrome:// 
loaded and rendered in the content via the nsIStreamConverter's new 
channel.  That's fantastic.

The bad news is two-fold: first, any hyperlinks I have in the browser 
content display don't actually update the location bar with the new 
hyperlink.  i.e. If I am viewing data.foo via chrome://fooviewer/, and 
the chrome presents a hyperlink to data2.foo, then when the user clicks 
on that link, the location bar still displays data.foo.  Second, 
pressing the Back button when viewing data2.foo displays the entire 
chrome:// URL again for viewing data.foo (and pressing Forward from 
there displays the entire chrome:// URL for data2.foo).

To solve the first problem, I've tried all sorts of combinations to get 
at the "real" document's location (rather than the "content view's" 
location), such as parent, window.parent, document.parent, 
window.parent.parent :), top, and even using nsIWindowMediator to get 
the current window and try to set the location there, but I just can't 
seem to update the "real" location.  I suspect that if I can do that, I 
can solve problem #2 by using real.location.href.replace before loading 
the hyperlinked URL.

Another possible solution I've been tinkering with but haven't gotten to 
work is using window.gBrowser.addTab to load the data2.foo URL, and then 
removing the old tab that was viewing data.foo.  To the user, this looks 
like it's simply loading the URL in the same window, even though it's 
really replacing the current tab with another one.  This, however, 
requires that I copy across the current session history to the new tab, 
so that if the user presses the Back button when viewing data2.foo in 
the new tab, they can go back to viewing data.foo.  If I could find a 
way to add entries or copy entries to the new tab's history, I think 
this approach would work.  (Adding the new tab and removing the old tab 
already works.)  I've tried playing with nsIHistory and friends[1], but 
can't seem to get it to work yet.

Anyway, I realise I'm most likely at the limits of what Mozilla's 
architecture can do here, but if you do have any further ideas, I'd be 
really happy to hear them.  Thanks for all your help so far!

1. Here's the code I'm using, just in case I'm doing something obviously 
wrong with it.  In particular, I'm a bit confused whether you can "cast" 
a nsIHistoryEntry to a nsISHEntry by using QueryInterface.

   var thisHistory = thisWindow.gBrowser.sessionHistory;

   var newTab = thisWindow.gBrowser.addTab("about:blank");
   var newHistory = newTab.gBrowser.sessionHistory;

   var newHistoryInternal = 
newHistory.QueryInterface(Components.interfaces.nsISHistoryInternal);

   var i;
   var historyEntry;
   var sessionHistoryEntry;
   for (i = 0; i < thisHistory.count(); i++)
   {
     historyEntry = thisHistory.getEntryAtIndex(i, false);
     sessionHistoryEntry = 
historyEntry.QueryInterface(Components.interfaces.nsISHEntry);
     newHistoryInternal.addEntry(historyEntry, true);
   }

   var thisTab = thisWindow.gBrowser.selectedTab;
   thisWindow.gBrowser.removeTab(thisTab);


-- 
% Andre Pang : trust.in.love.to.save