1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is Mozilla Communicator client code, released
18 * The Initial Developer of the Original Code is
19 * Netscape Communications Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 1998-1999
21 * the Initial Developer. All Rights Reserved.
24 * Ian Oeschger <oeschger@brownhen.com> (Original Author)
25 * Peter Wilson (added sidebar tabs)
26 * R.J. Keller <rlk@trfenv.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either the GNU General Public License Version 2 or later (the "GPL"), or
30 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 //-------- global variables
47 var emptySearchText = "No search items found.";
48 var emptySearchLink = "about:blank";
51 var helpGlossaryPanel;
54 const NC = "http://home.netscape.com/NC-rdf#";
55 const MAX_LEVEL = 40; // maximum depth of recursion in search datasources.
58 const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
59 const RDF_ROOT = RDF.GetResource("urn:root");
60 const NC_PANELLIST = RDF.GetResource(NC + "panellist");
61 const NC_PANELID = RDF.GetResource(NC + "panelid");
62 const NC_PLATFORM = RDF.GetResource(NC + "platform");
63 const NC_EMPTY_SEARCH_TEXT = RDF.GetResource(NC + "emptysearchtext");
64 const NC_EMPTY_SEARCH_LINK = RDF.GetResource(NC + "emptysearchlink");
65 const NC_DATASOURCES = RDF.GetResource(NC + "datasources");
66 const NC_SUBHEADINGS = RDF.GetResource(NC + "subheadings");
67 const NC_NAME = RDF.GetResource(NC + "name");
68 const NC_CHILD = RDF.GetResource(NC + "child");
69 const NC_LINK = RDF.GetResource(NC + "link");
70 const NC_TITLE = RDF.GetResource(NC + "title");
71 const NC_BASE = RDF.GetResource(NC + "base");
72 const NC_DEFAULTTOPIC = RDF.GetResource(NC + "defaulttopic");
74 const RDFCUtils = Components.classes["@mozilla.org/rdf/container-utils;1"].getService(Components.interfaces.nsIRDFContainerUtils);
75 var RDFContainer = Components.classes["@mozilla.org/rdf/container;1"].createInstance(Components.interfaces.nsIRDFContainer);
76 const CONSOLE_SERVICE = Components.classes['@mozilla.org/consoleservice;1'].getService(Components.interfaces.nsIConsoleService);
82 // Set from nc:base attribute on help rdf file. It may be used for prefix reduction on all links within
83 // the current help set.
86 const defaultHelpFile = "chrome://help/locale/mozillahelp.rdf";
87 // Set from nc:defaulttopic. It is used when the requested uri has no topic specified.
88 var defaultTopic = "welcome";
89 var searchDatasources = "rdf:null";
91 var platform = /mac/i.test(navigator.platform) ? "mac" :
92 /win/i.test(navigator.platform) ? "win" :
93 /os\/2/i.test(navigator.platform) ? "os/2" : "unix";
95 const NSRESULT_RDF_SYNTAX_ERROR = 0x804e03f7;
97 // This function is called by dialogs/windows that want to display context-sensitive help
98 // These dialogs/windows should include the script chrome://help/content/contextHelp.js
99 function displayTopic(topic) {
100 // Use default topic if topic is not specified.
102 topic = defaultTopic;
104 // Get the help page to open.
105 var uri = getLink(topic);
107 // Use default topic if specified topic is not found.
108 if (!uri) // Topic not found - revert to default.
109 uri = getLink(defaultTopic);
113 var helpContentListener = {
114 onStartURIOpen: function(aURI) {
117 doContent: function(aContentType, aIsContentPreferred, aRequest, aContentHandler) {
118 throw Components.results.NS_ERROR_UNEXPECTED;
120 isPreferred: function(aContentType, aDesiredContentType) {
123 canHandleContent: function(aContentType, aIsContentPreferred, aDesiredContentType) {
127 parentContentListener: null,
128 QueryInterface: function (aIID) {
129 if (aIID.equals(Components.interfaces.nsIURIContentListener) ||
130 aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
131 aIID.equals(Components.interfaces.nsISupports))
133 Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
138 // Initialize the Help window
140 //cache panel references.
141 helpSearchPanel = document.getElementById("help-search-panel");
142 helpTocPanel = document.getElementById("help-toc-panel");
143 helpIndexPanel = document.getElementById("help-index-panel");
144 helpGlossaryPanel = document.getElementById("help-glossary-panel");
145 helpBrowser = document.getElementById("help-content");
146 helpExternal = document.getElementById("help-external");
147 helpExternal.docShell.useErrorPages = false;
150 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
151 .getInterface(Components.interfaces.nsIURIContentListener)
152 .parentContentListener = helpContentListener;
154 // Get the help content pack, base URL, and help topic
155 var helpTopic = defaultTopic;
156 if ("arguments" in window && window.arguments[0] instanceof Components.interfaces.nsIDialogParamBlock) {
157 helpFileURI = window.arguments[0].GetString(0);
158 helpBaseURI = helpFileURI.substring(0, helpFileURI.lastIndexOf("/")+1); // trailing "/" included.
159 helpTopic = window.arguments[0].GetString(1);
164 displayTopic(helpTopic);
166 window.XULBrowserWindow = new nsHelpStatusHandler();
168 //Start the status handler.
169 window.XULBrowserWindow.init();
171 // Hook up UI through Progress Listener
172 helpBrowser.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
173 helpExternal.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
175 //Always show the Table of Contents sidebar at startup.
176 showPanel('help-toc');
178 // alwaysRaised only works on Mac & Win.
179 if (!/Win|Mac/.test(navigator.platform)) {
180 var toggleSeparator = document.getElementById("context-sep-selectall");
181 var toggleOnTop = document.getElementById("context-zlevel");
182 toggleOnTop.hidden = true;
183 toggleSeparator.hidden = true;
187 function contentClick(event) {
188 // is this a left click on a link?
189 if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey || event.button != 0)
193 var target = event.target;
194 while (!(target instanceof HTMLAnchorElement))
195 if (!(target = target.parentNode))
198 // is this an internal link?
199 if (target.href.lastIndexOf("chrome:", 0) == 0)
202 var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"]
203 .getService(Components.interfaces.nsIURLFormatter);
204 var uri = target.href;
205 if (/^x-moz-url-link:/.test(uri))
206 uri = formatter.formatURLPref(RegExp.rightContext);
208 const loadFlags = Components.interfaces.nsIWebNavigation.LOAD_FLAGS_IS_LINK;
210 helpExternal.webNavigation.loadURI(uri, loadFlags, null, null, null);
215 function loadHelpRDF() {
218 helpFileDS = RDF.GetDataSourceBlocking(helpFileURI);
220 catch (e if (e.result == NSRESULT_RDF_SYNTAX_ERROR)) {
221 log("Help file: " + helpFileURI + " contains a syntax error.");
224 log("Help file: " + helpFileURI + " was not found.");
227 document.title = getAttribute(helpFileDS, RDF_ROOT, NC_TITLE, "");
228 helpBaseURI = getAttribute(helpFileDS, RDF_ROOT, NC_BASE, helpBaseURI);
229 defaultTopic = getAttribute(helpFileDS, RDF_ROOT, NC_DEFAULTTOPIC, "welcome");
231 var panelDefs = helpFileDS.GetTarget(RDF_ROOT, NC_PANELLIST, true);
232 RDFContainer.Init(helpFileDS, panelDefs);
233 var iterator = RDFContainer.GetElements();
234 while (iterator.hasMoreElements()) {
235 var panelDef = iterator.getNext();
237 var panelPlatforms = getAttribute(helpFileDS, panelDef, NC_PLATFORM, platform);
238 panelPlatforms = panelPlatforms.split(/\s+/);
240 if (panelPlatforms.indexOf(platform) == -1)
241 continue; // ignore datasources for other platforms.
243 var panelID = getAttribute(helpFileDS, panelDef, NC_PANELID, null);
245 var datasources = getAttribute(helpFileDS, panelDef, NC_DATASOURCES, "rdf:null");
246 datasources = normalizeLinks(helpBaseURI, datasources);
247 // cache additional datsources to augment search datasources.
248 if (panelID == "search") {
249 emptySearchText = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_TEXT, emptySearchText);
250 emptySearchLink = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_LINK, emptySearchLink);
251 searchDatasources += " " + datasources;
252 continue; // but don't try to display them yet!
255 // cache toc datasources for use by ID lookup.
256 var tree = document.getElementById("help-" + panelID + "-panel");
257 loadDatabasesBlocking(datasources);
258 tree.setAttribute("datasources", tree.getAttribute("datasources") + " " + datasources);
267 function loadDatabasesBlocking(datasources) {
268 var ds = datasources.split(/\s+/);
269 for (var i=0; i < ds.length; ++i) {
270 if (ds[i] == "rdf:null" || ds[i] == "")
273 // we need blocking here to ensure the database is loaded so getLink(topic) works.
274 var datasource = RDF.GetDataSourceBlocking(ds[i]);
277 log("Datasource: " + ds[i] + " was not found.");
282 // prepend helpBaseURI to list of space separated links if the don't start with "chrome:"
283 function normalizeLinks(helpBaseURI, links) {
286 var ls = links.split(/\s+/);
289 for (var i=0; i < ls.length; ++i) {
292 if (ls[i].substr(0,7) != "chrome:" && ls[i].substr(0,4) != "rdf:")
293 ls[i] = helpBaseURI + ls[i];
298 function getLink(ID) {
301 // Note resources are stored in fileURL#ID format.
302 // We have one possible source for an ID for each datasource in the composite datasource.
303 // The first ID which matches is returned.
304 var tocTree = document.getElementById("help-toc-panel");
305 var tocDS = tocTree.database;
308 var tocDatasources = tocTree.getAttribute("datasources");
309 var ds = tocDatasources.split(/\s+/);
310 for (var i=0; i < ds.length; ++i) {
311 if (ds[i] == "rdf:null" || ds[i] == "")
314 var rdfID = ds[i] + "#" + ID;
315 var resource = RDF.GetResource(rdfID);
317 var link = tocDS.GetTarget(resource, NC_LINK, true);
319 link = link.QueryInterface(Components.interfaces.nsIRDFLiteral);
327 catch (e) { log(rdfID + " " + e);}
332 // Called by contextHelp.js to determine if this window is displaying the requested help file.
333 function getHelpFileURI() {
338 function getWebNavigation()
340 return helpBrowser.webNavigation;
343 function loadURI(uri)
345 if (uri.substr(0,7) != "chrome:")
346 uri = helpBaseURI + uri;
347 const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
348 getWebNavigation().loadURI(uri, nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
353 var webNavigation = getWebNavigation();
354 if (webNavigation.canGoBack)
355 webNavigation.goBack();
360 var webNavigation = getWebNavigation();
361 if (webNavigation.canGoForward)
362 webNavigation.goForward();
366 // load "Welcome" page
367 displayTopic(defaultTopic);
378 function createBackMenu(event)
380 return FillHistoryMenu(event.target, "back");
383 function createForwardMenu(event)
385 return FillHistoryMenu(event.target, "forward");
388 function gotoHistoryIndex(aEvent)
390 var index = aEvent.target.getAttribute("index");
394 getWebNavigation().gotoIndex(index);
402 function nsHelpStatusHandler()
406 nsHelpStatusHandler.prototype =
408 onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus)
410 const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
412 // Turn on the throbber.
413 if (aStateFlags & nsIWebProgressListener.STATE_START)
414 this.throbberElement.setAttribute("busy", "true");
415 else if (aStateFlags & nsIWebProgressListener.STATE_STOP)
416 this.throbberElement.removeAttribute("busy");
418 onStatusChange : function(aWebProgress, aRequest, aStateFlags, aStatus) {},
419 onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress,
420 aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
421 onSecurityChange : function(aWebProgress, aRequest, state) {},
422 onLocationChange : function(aWebProgress, aRequest, aLocation)
424 UpdateBackForwardButtons();
426 QueryInterface : function(aIID)
428 if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
429 aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
430 aIID.equals(Components.interfaces.nsIXULBrowserWindow) ||
431 aIID.equals(Components.interfaces.nsISupports))
433 throw Components.results.NS_NOINTERFACE;
438 this.throbberElement = document.getElementById("navigator-throbber");
443 //this is needed to avoid memory leaks, see bug 60729
444 this.throbberElement = null;
447 setJSStatus : function(status) {},
448 setJSDefaultStatus : function(status) {},
449 setOverLink : function(link, context) {}
452 function UpdateBackForwardButtons()
454 var backBroadcaster = document.getElementById("canGoBack");
455 var forwardBroadcaster = document.getElementById("canGoForward");
456 var webNavigation = getWebNavigation();
458 // Avoid setting attributes on broadcasters if the value hasn't changed!
459 // Remember, guys, setting attributes on elements is expensive! They
460 // get inherited into anonymous content, broadcast to other widgets, etc.!
461 // Don't do it if the value hasn't changed! - dwh
463 var backDisabled = (backBroadcaster.getAttribute("disabled") == "true");
464 var forwardDisabled = (forwardBroadcaster.getAttribute("disabled") == "true");
466 if (backDisabled == webNavigation.canGoBack)
467 backBroadcaster.setAttribute("disabled", !backDisabled);
469 if (forwardDisabled == webNavigation.canGoForward)
470 forwardBroadcaster.setAttribute("disabled", !forwardDisabled);
474 function getFindInstData()
476 if (!gFindInstData) {
477 gFindInstData = new nsFindInstData();
478 gFindInstData.browser = helpBrowser;
479 // defaults for rootSearchWindow and currentSearchWindow are fine here
481 return gFindInstData;
484 function find(again, reverse)
487 findAgainInPage(getFindInstData(), reverse);
489 findInPage(getFindInstData())
492 function getMarkupDocumentViewer()
494 return helpBrowser.markupDocumentViewer;
497 //Show the selected sidebar panel
498 function showPanel(panelId) {
499 //hide other sidebar panels and show the panel name taken in from panelID.
500 helpSearchPanel.setAttribute("hidden", "true");
501 helpTocPanel.setAttribute("hidden", "true");
502 helpIndexPanel.setAttribute("hidden", "true");
503 helpGlossaryPanel.setAttribute("hidden", "true");
504 var thePanel = document.getElementById(panelId + "-panel");
505 thePanel.setAttribute("hidden","false");
507 //remove the selected style from the previous panel selected.
508 document.getElementById("help-glossary-btn").removeAttribute("selected");
509 document.getElementById("help-index-btn").removeAttribute("selected");
510 document.getElementById("help-search-btn").removeAttribute("selected");
511 document.getElementById("help-toc-btn").removeAttribute("selected");
513 //add the selected style to the correct panel.
514 var theButton = document.getElementById(panelId + "-btn");
515 theButton.setAttribute("selected", "true");
516 document.commandDispatcher.advanceFocusIntoSubtree(theButton);
519 function onselect_loadURI(tree) {
520 var row = tree.currentIndex;
522 var resource = tree.view.getResourceAtIndex(row);
523 var link = tree.database.GetTarget(resource, NC_LINK, true);
524 if (link instanceof Components.interfaces.nsIRDFLiteral && link.Value)
530 var searchTree = document.getElementById("help-search-tree");
531 var findText = document.getElementById("findText");
533 // clear any previous results.
534 clearDatabases(searchTree.database);
536 // if the search string is empty or contains only whitespace, purge the results tree and return
537 RE = findText.value.match(/\S+/g);
539 searchTree.builder.rebuild();
543 // compile the search string, which has already been split up above, into regexps
544 for (var i=0; i < RE.length; ++i) {
545 RE[i] = new RegExp(RE[i], "i");
550 var resultsDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"].createInstance(Components.interfaces.nsIRDFDataSource);
551 var tree = document.getElementById("help-toc-panel");
552 var sourceDS = tree.database;
553 doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
555 // search additional search datasources
556 if (searchDatasources != "rdf:null") {
558 searchDS = loadCompositeDS(searchDatasources);
559 doFindOnDatasource(resultsDS, searchDS, RDF_ROOT, 0);
563 tree = document.getElementById("help-index-panel");
564 sourceDS = tree.database;
565 if (!sourceDS) // If the index has never been displayed this will be null.
566 sourceDS = loadCompositeDS(tree.datasources);
567 doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
570 tree = document.getElementById("help-glossary-panel");
571 sourceDS = tree.database;
572 if (!sourceDS) // If the glossary has never been displayed this will be null (sigh!).
573 sourceDS = loadCompositeDS(tree.datasources);
574 doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
577 assertSearchEmpty(resultsDS);
578 // Add the datasource to the search tree
579 searchTree.database.AddDataSource(resultsDS);
580 searchTree.builder.rebuild();
583 function clearDatabases(compositeDataSource) {
584 var enumDS = compositeDataSource.GetDataSources()
585 while (enumDS.hasMoreElements()) {
586 var ds = enumDS.getNext();
587 compositeDataSource.RemoveDataSource(ds);
591 function doFindOnDatasource(resultsDS, sourceDS, resource, level) {
592 if (level > MAX_LEVEL) {
594 log("Recursive reference to resource: " + resource.Value + ".");
597 log("Recursive reference to unknown resource.");
601 // find all SUBHEADING children of current resource.
602 var targets = sourceDS.GetTargets(resource, NC_SUBHEADINGS, true);
603 while (targets.hasMoreElements()) {
604 var target = targets.getNext();
605 target = target.QueryInterface(Components.interfaces.nsIRDFResource);
606 // The first child of a rdf:subheading should (must) be a rdf:seq.
607 // Should we test for a SEQ here?
608 doFindOnSeq(resultsDS, sourceDS, target, level+1);
612 function doFindOnSeq(resultsDS, sourceDS, resource, level) {
613 // load up an RDFContainer so we can access the contents of the current rdf:seq.
614 RDFContainer.Init(sourceDS, resource);
615 var targets = RDFContainer.GetElements();
616 while (targets.hasMoreElements()) {
617 var target = targets.getNext();
618 var link = sourceDS.GetTarget(target, NC_LINK, true);
619 var name = sourceDS.GetTarget(target, NC_NAME, true);
620 name = name.QueryInterface(Components.interfaces.nsIRDFLiteral);
621 if (link && isMatch(name.Value)) {
622 // we have found a search entry - add it to the results datasource.
623 var urn = RDF.GetAnonymousResource();
624 resultsDS.Assert(urn, NC_NAME, name, true);
625 resultsDS.Assert(urn, NC_LINK, link, true);
626 resultsDS.Assert(RDF_ROOT, NC_CHILD, urn, true);
629 // process any nested rdf:seq elements.
630 doFindOnDatasource(resultsDS, sourceDS, target, level+1);
634 function assertSearchEmpty(resultsDS) {
635 var resSearchEmpty = RDF.GetResource("urn:emptySearch");
636 resultsDS.Assert(RDF_ROOT,
640 resultsDS.Assert(resSearchEmpty,
642 RDF.GetLiteral(emptySearchText),
644 resultsDS.Assert(resSearchEmpty,
646 RDF.GetLiteral(emptySearchLink),
650 function isMatch(text) {
651 for (var i=0; i < RE.length; ++i ) {
652 if (!RE[i].test(text))
658 function loadCompositeDS(datasources) {
659 // We can't search on each individual datasource's - only the aggregate (for each sidebar tab)
660 // has the appropriate structure.
661 var compositeDS = Components.classes["@mozilla.org/rdf/datasource;1?name=composite-datasource"]
662 .createInstance(Components.interfaces.nsIRDFCompositeDataSource);
664 var ds = datasources.split(/\s+/);
665 for (var i=0; i < ds.length; ++i) {
666 if (ds[i] == "rdf:null" || ds[i] == "")
669 // we need blocking here to ensure the database is loaded.
670 var sourceDS = RDF.GetDataSourceBlocking(ds[i]);
671 compositeDS.AddDataSource(sourceDS);
674 log("Datasource: " + ds[i] + " was not found.");
680 function getAttribute(datasource, resource, attributeResourceName, defaultValue) {
681 var literal = datasource.GetTarget(resource, attributeResourceName, true);
682 return literal instanceof Components.interfaces.nsIRDFLiteral ? literal.Value : defaultValue;
684 // Write debug string to error console.
685 function log(aText) {
686 CONSOLE_SERVICE.logStringMessage(aText);
690 //INDEX OPENING FUNCTION -- called in oncommand for index pane
691 // iterate over all the items in the outliner;
692 // open the ones at the top-level (i.e., expose the headings underneath
693 // the letters in the list.
694 function displayIndex() {
695 var treeview = helpIndexPanel.view;
696 var i = treeview.rowCount;
698 if (!treeview.getLevel(i) && !treeview.isContainerOpen(i))
699 treeview.toggleOpenState(i);
702 // Shows the panel relative to the currently selected panel.
703 // Takes a boolean parameter - if true it will show the next panel,
704 // otherwise it will show the previous panel.
705 function showRelativePanel(goForward) {
706 var selectedIndex = -1;
707 var sidebarBox = document.getElementById("helpsidebar-box");
708 var sidebarButtons = new Array();
709 for (var i = 0; i < sidebarBox.childNodes.length; i++) {
710 var btn = sidebarBox.childNodes[i];
711 if (btn.nodeName == "toolbarbutton") {
712 if (btn.getAttribute("selected") == "true")
713 selectedIndex = sidebarButtons.length;
714 sidebarButtons.push(btn);
717 if (selectedIndex == -1)
719 selectedIndex += goForward ? 1 : -1;
720 if (selectedIndex >= sidebarButtons.length)
722 else if (selectedIndex < 0)
723 selectedIndex = sidebarButtons.length - 1;
724 sidebarButtons[selectedIndex].doCommand();
727 // getXulWin - Returns the current Help window as a nsIXULWindow.
728 function getXulWin() {
729 window.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
730 var webnav = window.getInterface(Components.interfaces.nsIWebNavigation);
731 var dsti = webnav.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
732 var treeowner = dsti.treeOwner;
733 var ifreq = treeowner.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
735 return ifreq.getInterface(Components.interfaces.nsIXULWindow);
738 // toggleZLevel - Toggles whether or not the window will always appear on top.
739 // element is the DOM node that persists the checked state
740 function toggleZLevel(element) {
741 var xulwin = getXulWin();
743 // Now we can flip the zLevel, and set the attribute so that it persists correctly
744 if (xulwin.zLevel > xulwin.normalZ) {
745 xulwin.zLevel = xulwin.normalZ;
746 element.setAttribute("checked", "false");
748 xulwin.zLevel = xulwin.raisedZ;
749 element.setAttribute("checked", "true");