toolkit/components/help/content/help.js

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     1 # This Source Code Form is subject to the terms of the Mozilla Public
     2 # License, v. 2.0. If a copy of the MPL was not distributed with this
     3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
     5 # Global Variables
     6 var helpBrowser;
     7 var helpSearchPanel;
     8 var emptySearch;
     9 var emptySearchText;
    10 var emptySearchLink = "about:blank";
    11 var helpTocPanel;
    12 var helpIndexPanel;
    13 var helpGlossaryPanel;
    14 var strBundle;
    15 var gTocDSList = "";
    17 # Namespaces
    18 const NC = "http://home.netscape.com/NC-rdf#";
    19 const MAX_LEVEL = 40; // maximum depth of recursion in search datasources.
    20 const MAX_HISTORY_MENU_ITEMS = 6;
    22 # ifdef logic ripped from toolkit/components/help/content/platformClasses.css
    23 #ifdef XP_WIN
    24 const platform = "win";
    25 #else
    26 #ifdef XP_MACOSX
    27 const platform = "mac";
    28 #else
    29 const platform = "unix";
    30 #endif
    31 #endif
    33 # Resources
    34 const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"]
    35     .getService(Components.interfaces.nsIRDFService);
    36 const RDF_ROOT = RDF.GetResource("urn:root");
    37 const NC_PANELLIST = RDF.GetResource(NC + "panellist");
    38 const NC_PANELID = RDF.GetResource(NC + "panelid");
    39 const NC_EMPTY_SEARCH_TEXT = RDF.GetResource(NC + "emptysearchtext");
    40 const NC_EMPTY_SEARCH_LINK = RDF.GetResource(NC + "emptysearchlink");
    41 const NC_DATASOURCES = RDF.GetResource(NC + "datasources");
    42 const NC_PLATFORM = RDF.GetResource(NC + "platform");
    43 const NC_SUBHEADINGS = RDF.GetResource(NC + "subheadings");
    44 const NC_NAME = RDF.GetResource(NC + "name");
    45 const NC_CHILD = RDF.GetResource(NC + "child");
    46 const NC_LINK = RDF.GetResource(NC + "link");
    47 const NC_TITLE = RDF.GetResource(NC + "title");
    48 const NC_BASE = RDF.GetResource(NC + "base");
    49 const NC_DEFAULTTOPIC = RDF.GetResource(NC + "defaulttopic");
    51 var RDFContainer =
    52    Components.classes["@mozilla.org/rdf/container;1"]
    53              .createInstance(Components.interfaces.nsIRDFContainer);
    54 const CONSOLE_SERVICE = Components.classes['@mozilla.org/consoleservice;1']
    55     .getService(Components.interfaces.nsIConsoleService);
    57 var RE;
    59 var helpFileURI;
    60 var helpFileDS;
    61 # Set from nc:base attribute on help rdf file. It may be used for prefix
    62 # reduction on all links within the current help set.
    63 var helpBaseURI;
    65 /* defaultTopic is either set
    66    1. in the openHelp() call, passed as an argument to the Help window and
    67       evaluated in init(), or
    68    2. in nc:defaulttopic in the content pack (e.g. firebirdhelp.rdf),
    69       evaluated in loadHelpRDF(), or
    70    3. "welcome" as a fallback, specified in loadHelpRDF() as well;
    71       displayTopic() then uses defaultTopic because topic is null. */
    72 var defaultTopic;
    74 const NSRESULT_RDF_SYNTAX_ERROR = 0x804e03f7;
    76 # This function is called by dialogs/windows that want to display
    77 # context-sensitive help
    78 # These dialogs/windows should include the script
    79 # chrome://help/content/contextHelp.js
    80 function displayTopic(topic) {
    81     // Get the page to open.
    82     var uri = getLink(topic);
    83     // Use default topic if specified topic is not found.
    84     if (!uri) {
    85         uri = getLink(defaultTopic);
    86     }
    87     // Load the page.
    88     if (uri)
    89       loadURI(uri);
    90 }
    92 # Initialize the Help window
    93 function init() {
    94   // Cache panel references.
    95   helpSearchPanel = document.getElementById("help-search-panel");
    96   helpTocPanel = document.getElementById("help-toc-panel");
    97   helpIndexPanel = document.getElementById("help-index-panel");
    98   helpGlossaryPanel = document.getElementById("help-glossary-panel");
    99   helpBrowser = document.getElementById("help-content");
   101   // Turn off unnecessary features for security
   102   helpBrowser.docShell.allowJavascript = false;
   103   helpBrowser.docShell.allowPlugins = false;
   104   helpBrowser.docShell.allowSubframes = false;
   105   helpBrowser.docShell.allowMetaRedirects = false;
   107   strBundle = document.getElementById("bundle_help");
   108   emptySearchText = strBundle.getString("emptySearchText");
   110   // Get the content pack, base URL, and help topic
   111   var helpTopic = defaultTopic;
   112   if ("arguments" in window && 
   113        window.arguments[0] instanceof Components.interfaces.nsIDialogParamBlock) {
   114     helpFileURI = window.arguments[0].GetString(0);
   115     // trailing "/" included.
   116     helpBaseURI = helpFileURI.substring(0, helpFileURI.lastIndexOf("/")+1);
   117     helpTopic = window.arguments[0].GetString(1);
   118   }
   120   loadHelpRDF();
   121   displayTopic(helpTopic);
   123   // Move to Center of Screen
   124   const width = document.documentElement.getAttribute("width");
   125   const height = document.documentElement.getAttribute("height");
   126   window.moveTo((screen.availWidth - width) / 2, (screen.availHeight - height) / 2);
   128   // Initialize history.
   129   getWebNavigation().sessionHistory = 
   130     Components.classes["@mozilla.org/browser/shistory;1"]
   131               .createInstance(Components.interfaces.nsISHistory);
   132   window.XULBrowserWindow = new nsHelpStatusHandler();
   134   //Start the status handler.
   135   window.XULBrowserWindow.init();
   137   // Hook up UI through Progress Listener
   138   const interfaceRequestor = helpBrowser.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
   139   const webProgress = interfaceRequestor.getInterface(Components.interfaces.nsIWebProgress);
   141   webProgress.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL);
   143   var searchBox = document.getElementById("findText");
   144   searchBox.clickSelectsAll = getBoolPref("browser.urlbar.clickSelectsAll", true);
   146   setTimeout(focusSearch, 0);
   147 }
   149 function showSearchSidebar() {
   150   // if you tab too quickly, you end up with stuck focus, revert focus to the searchbar
   151   var searchTree = document.getElementById("help-toc-panel");
   152   if (searchTree.treeBoxObject.focused) {
   153     focusSearch();
   154   }
   156   var tableOfContents = document.getElementById("help-toc-sidebar");
   157   tableOfContents.setAttribute("hidden", "true");
   159   var sidebar = document.getElementById("help-search-sidebar");
   160   sidebar.removeAttribute("hidden");
   161 }
   163 function hideSearchSidebar(aEvent) {
   164   // if we're focused in the search results, focus content
   165   var searchTree = document.getElementById("help-search-tree");
   166   if (searchTree.treeBoxObject.focused) {
   167     content.focus();
   168   }
   170   var sidebar = document.getElementById("help-search-sidebar");
   171   sidebar.setAttribute("hidden", "true");
   173   var tableOfContents = document.getElementById("help-toc-sidebar");
   174   tableOfContents.removeAttribute("hidden");
   175 }
   177 # loadHelpRDF
   178 # Parse the provided help content pack RDF file, and use it to
   179 # populate the datasources attached to the trees in the viewer.
   180 # Filter out any information not applicable to the user's platform.
   181 function loadHelpRDF() {
   182   if (!helpFileDS) {
   183     try {
   184       helpFileDS = RDF.GetDataSourceBlocking(helpFileURI);
   185     } catch (e if (e.result == NSRESULT_RDF_SYNTAX_ERROR)) {
   186       log("Help file: " + helpFileURI + " contains a syntax error.");
   187     } catch (e) {
   188       log("Help file: " + helpFileURI + " was not found.");
   189     }
   191     try {
   192       document.title = getAttribute(helpFileDS, RDF_ROOT, NC_TITLE, "");
   193       helpBaseURI = getAttribute(helpFileDS, RDF_ROOT, NC_BASE, helpBaseURI);
   194       // if there's no nc:defaulttopic in the content pack, set "welcome"
   195       // as the default topic
   196       defaultTopic = getAttribute(helpFileDS,
   197         RDF_ROOT, NC_DEFAULTTOPIC, "welcome");
   199       var panelDefs = helpFileDS.GetTarget(RDF_ROOT, NC_PANELLIST, true);
   200       RDFContainer.Init(helpFileDS, panelDefs);
   201       var iterator = RDFContainer.GetElements();
   202       while (iterator.hasMoreElements()) {
   203         var panelDef = iterator.getNext();
   205         var panelID        = getAttribute(helpFileDS, panelDef, NC_PANELID, null);
   206         var datasources    = getAttribute(helpFileDS, panelDef, NC_DATASOURCES, "");
   207         var panelPlatforms = getAttribute(helpFileDS, panelDef, NC_PLATFORM, null);
   209         if (panelPlatforms && panelPlatforms.split(/\s+/).indexOf(platform) == -1)
   210           continue; // ignore datasources for other platforms
   212         // empty datasources are valid on search panel definitions
   213         // convert them to "rdf:null" which can be filtered and ignored
   214         if (!datasources)
   215           datasources = "rdf:null";
   217         datasources = normalizeLinks(helpBaseURI, datasources);
   219         var datasourceArray = datasources.split(/\s+/)
   220                                          .filter(function(x) { return x != "rdf:null"; })
   221                                          .map(RDF.GetDataSourceBlocking);
   223         // Cache Additional Datasources to Augment Search Datasources.
   224         if (panelID == "search") {
   225           emptySearchText = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_TEXT, emptySearchText);
   226           emptySearchLink = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_LINK, emptySearchLink);
   228           datasourceArray.forEach(helpSearchPanel.database.AddDataSource,
   229                                   helpSearchPanel.database);
   230           if (!panelPlatforms)
   231             filterDatasourceByPlatform(helpSearchPanel.database);
   233           continue; // to next panel definition
   234         }
   236         // cache toc datasources list for use in getLink()
   237         if (panelID == "toc")
   238           gTocDSList += " " + datasources;
   240         var tree = document.getElementById("help-" + panelID + "-panel");
   242         // add each datasource to the current tree
   243         datasourceArray.forEach(tree.database.AddDataSource,
   244                                 tree.database);
   246         // filter and display the current tree
   247         if (!panelPlatforms)
   248           filterDatasourceByPlatform(tree.database);
   249         tree.builder.rebuild();
   250       }
   251     } catch (e) {
   252       log(e + "");
   253     }
   254   }
   255 }
   257 # filterDatasourceByPlatform
   258 # Remove statements for other platforms from a datasource.
   259 function filterDatasourceByPlatform(aDatasource) {
   260   filterNodeByPlatform(aDatasource, RDF_ROOT, 0);
   261 }
   263 # filterNodeByPlatform
   264 # Remove statements for other platforms from the provided datasource.
   265 function filterNodeByPlatform(aDatasource, aCurrentResource, aCurrentLevel) {
   266   if (aCurrentLevel > MAX_LEVEL) {
   267      log("Datasources over " + MAX_LEVEL + " levels deep are unsupported.");
   268      return;
   269   }
   271   // get the subheadings under aCurrentResource and filter them
   272   var nodes = aDatasource.GetTargets(aCurrentResource, NC_SUBHEADINGS, true);
   273   while (nodes.hasMoreElements()) {
   274     var node = nodes.getNext();
   275     node = node.QueryInterface(Components.interfaces.nsIRDFResource);
   276     // should we test for rdf:Seq here?  see also doFindOnDatasource
   277     filterSeqByPlatform(aDatasource, node, aCurrentLevel+1);
   278   }
   279 }
   281 # filterSeqByPlatform
   282 # Go through the children of aNode, if any, removing statements applicable
   283 # only on other platforms.
   284 function filterSeqByPlatform(aDatasource, aNode, aCurrentLevel) {
   285   // get nc:subheading children into an enumerator
   286   var RDFC = Components.classes["@mozilla.org/rdf/container;1"]
   287                        .createInstance(Components.interfaces.nsIRDFContainer);
   288   RDFC.Init(aDatasource, aNode);
   289   var targets = RDFC.GetElements();
   291   // process items in the rdf:Seq
   292   while (targets.hasMoreElements()) {
   293     var currentTarget = targets.getNext();
   295     // find out on which platforms this node is meaningful
   296     var nodePlatforms = getAttribute(aDatasource,
   297                                      currentTarget.QueryInterface(Components.interfaces.nsIRDFResource),
   298                                      NC_PLATFORM,
   299                                      platform);
   301     if (nodePlatforms.split(/\s+/).indexOf(platform) == -1) { // node is for another platform
   302       var currentNode = currentTarget.QueryInterface(Components.interfaces.nsIRDFNode);
   303       // "false" because we don't want to renumber elements in the container
   304       RDFC.RemoveElement(currentNode, false);
   306       // move to next node - ignore the children, because 1) they might be
   307       // needed elsewhere and 2) nodes not connected to RDF_ROOT are ignored
   308       continue;
   309     }
   311     // filter any children
   312     filterNodeByPlatform(aDatasource, currentTarget, aCurrentLevel+1);
   313   }
   314 }
   316 # Prepend helpBaseURI to list of space separated links if they don't start with
   317 # "chrome:"
   318 function normalizeLinks(helpBaseURI, links) {
   319   if (!helpBaseURI) {
   320     return links;
   321   }
   322   var ls = links.split(/\s+/);
   323   if (ls.length == 0) {
   324     return links;
   325   }
   326   for (var i=0; i < ls.length; ++i) {
   327     if (ls[i] == "")
   328       continue;
   330     if (ls[i].substr(0,7) != "chrome:" && ls[i].substr(0,4) != "rdf:")
   331       ls[i] = helpBaseURI + ls[i];
   332   }
   333   return ls.join(" ");
   334 }
   336 function getLink(ID) {
   337     if (!ID)
   338       return null;
   340     var tocDS = document.getElementById("help-toc-panel").database;
   341     if (!tocDS)
   342       return null;
   344     // URIs include both the ID part and the base file name,
   345     // so we need to check for a matching ID in each datasource
   346     var tocDSArray = gTocDSList.split(/\s+/)
   347                                .filter(function(x) { return x != "rdf:null"; });
   349     for (var i = 0; i < tocDSArray.length; i++) {
   350       var resource = RDF.GetResource(tocDSArray[i] + "#" + ID);
   351       var link = tocDS.GetTarget(resource, NC_LINK, true);
   352       if (!link)  // no such rdf:ID found
   353         continue;
   354       return link.QueryInterface(Components.interfaces.nsIRDFLiteral).Value;
   355     }
   356     return null;
   357 }
   359 # Called by contextHelp.js to determine if this window is displaying the
   360 # requested help file.
   361 function getHelpFileURI() {
   362     return helpFileURI;
   363 }
   365 function getBrowser() {
   366   return helpBrowser;
   367 }
   369 function getWebNavigation() {
   370   try {
   371     return helpBrowser.webNavigation;
   372   } catch (e)
   373   {
   374     return null;
   375   }
   376 }
   378 function loadURI(uri) {
   379     if (uri.substr(0,7) != "chrome:") {
   380         uri = helpBaseURI + uri;
   381     }
   382     getWebNavigation().loadURI(uri, Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE,
   383         null, null, null);
   384 }
   386 function goBack() {
   387   try
   388   {
   389     getWebNavigation().goBack();
   390   } catch (e)
   391   {
   392   }
   393 }
   395 function goForward() {
   396     try
   397     {
   398       getWebNavigation().goForward();
   399     } catch(e)
   400     {
   401     }
   402 }
   404 function goHome() {
   405     // Load "Welcome" page
   406     displayTopic(defaultTopic);
   407 }
   409 function print() {
   410     try {
   411         _content.print();
   412     } catch (e) {
   413     }
   414 }
   416 function FillHistoryMenu(aParent, aMenu)
   417   {
   418     // Remove old entries if any
   419     deleteHistoryItems(aParent);
   421     var sessionHistory = getWebNavigation().sessionHistory;
   423     var count = sessionHistory.count;
   424     var index = sessionHistory.index;
   425     var end;
   426     var j;
   427     var entry;
   429     switch (aMenu)
   430       {
   431         case "back":
   432           end = (index > MAX_HISTORY_MENU_ITEMS) ? index - MAX_HISTORY_MENU_ITEMS : 0;
   433           if ((index - 1) < end) return false;
   434           for (j = index - 1; j >= end; j--)
   435             {
   436               entry = sessionHistory.getEntryAtIndex(j, false);
   437               if (entry)
   438                 createMenuItem(aParent, j, entry.title);
   439             }
   440           break;
   441         case "forward":
   442           end  = ((count-index) > MAX_HISTORY_MENU_ITEMS) ? index + MAX_HISTORY_MENU_ITEMS : count - 1;
   443           if ((index + 1) > end) return false;
   444           for (j = index + 1; j <= end; j++)
   445             {
   446               entry = sessionHistory.getEntryAtIndex(j, false);
   447               if (entry)
   448                 createMenuItem(aParent, j, entry.title);
   449             }
   450           break;
   451       }
   452     return true;
   453   }
   455 function createMenuItem( aParent, aIndex, aLabel)
   456   {
   457     var menuitem = document.createElement( "menuitem" );
   458     menuitem.setAttribute( "label", aLabel );
   459     menuitem.setAttribute( "index", aIndex );
   460     aParent.appendChild( menuitem );
   461   }
   463 function deleteHistoryItems(aParent)
   464 {
   465   var children = aParent.childNodes;
   466   for (var i = children.length - 1; i >= 0; --i)
   467     {
   468       var index = children[i].getAttribute("index");
   469       if (index)
   470         aParent.removeChild(children[i]);
   471     }
   472 }
   474 function createBackMenu(event) {
   475     return FillHistoryMenu(event.target, "back");
   476 }
   478 function createForwardMenu(event) {
   479     return FillHistoryMenu(event.target, "forward");
   480 }
   482 function gotoHistoryIndex(aEvent) {
   483     var index = aEvent.target.getAttribute("index");
   484     if (!index) {
   485         return false;
   486     }
   487     try {
   488         getWebNavigation().gotoIndex(index);
   489     } catch(ex) {
   490         return false;
   491     }
   492     return true;
   493 }
   495 function nsHelpStatusHandler() {
   496   this.init();
   497 }
   499 nsHelpStatusHandler.prototype = {
   501     onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) {},
   502     onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress,
   503         aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {},
   504     onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) {},
   505     onSecurityChange : function(aWebProgress, aRequest, state) {},
   506     onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) {
   507         UpdateBackForwardButtons();
   508     },
   509     QueryInterface : function(aIID) {
   510         if (aIID.equals(Components.interfaces.nsIWebProgressListener) ||
   511                 aIID.equals(Components.interfaces.nsISupportsWeakReference) ||
   512                 aIID.equals(Components.interfaces.nsIXULBrowserWindow) ||
   513                 aIID.equals(Components.interfaces.nsISupports)) {
   514             return this;
   515         }
   516         throw Components.results.NS_NOINTERFACE;
   517     },
   519     init : function() {},
   521     destroy : function() {},
   523     setJSStatus : function(status) {},
   524     setOverLink : function(link, context) {},
   525     onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {}
   526 }
   528 function UpdateBackForwardButtons() {
   529     var backBroadcaster = document.getElementById("canGoBack");
   530     var forwardBroadcaster = document.getElementById("canGoForward");
   531     var webNavigation = getWebNavigation();
   533     // Avoid setting attributes on broadcasters if the value hasn't changed!
   534     // Remember, guys, setting attributes on elements is expensive!  They
   535     // get inherited into anonymous content, broadcast to other widgets, etc.!
   536     // Don't do it if the value hasn't changed! - dwh
   538     var backDisabled = (backBroadcaster.getAttribute("disabled") == "true");
   539     var forwardDisabled = (forwardBroadcaster.getAttribute("disabled") == "true");
   541     if (backDisabled == webNavigation.canGoBack) {
   542       if (backDisabled)
   543         backBroadcaster.removeAttribute("disabled");
   544       else
   545         backBroadcaster.setAttribute("disabled", true);
   546     }
   548     if (forwardDisabled == webNavigation.canGoForward) {
   549       if (forwardDisabled)
   550         forwardBroadcaster.removeAttribute("disabled");
   551       else
   552         forwardBroadcaster.setAttribute("disabled", true);
   553     }
   554 }
   556 function onselect_loadURI(tree) {
   557     try {
   558         var resource = tree.view.getResourceAtIndex(tree.currentIndex);
   559         var link = tree.database.GetTarget(resource, NC_LINK, true);
   560         if (link) {
   561             link = link.QueryInterface(Components.interfaces.nsIRDFLiteral);
   562             loadURI(link.Value);
   563         }
   564     } catch (e) {
   565     }// when switching between tabs a spurious row number is returned.
   566 }
   568 function focusSearch() {
   569   var searchBox = document.getElementById("findText");
   570   searchBox.focus();
   571 }
   573 # doFind - Searches the help files for what is located in findText and outputs into
   574 #        the find search tree.
   575 function doFind() {
   576     if (document.getElementById("help-search-sidebar").hidden)
   577       showSearchSidebar();
   579     var searchTree = document.getElementById("help-search-tree");
   580     var findText = document.getElementById("findText");
   582     // clear any previous results.
   583     clearDatabases(searchTree.database);
   585     // if the search string is empty or contains only whitespace, purge the results tree and return
   586     RE = findText.value.match(/\S+/g);
   587     if (!RE) {
   588       searchTree.builder.rebuild();
   589       hideSearchSidebar();
   590       return;
   591     }
   593     // compile the search string, which has already been split up above, into regexps
   594     for (var i=0; i < RE.length; ++i) {
   595       RE[i] = new RegExp(RE[i], "i");
   596     }
   597     emptySearch = true;
   599     // search TOC
   600     var resultsDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"]
   601         .createInstance(Components.interfaces.nsIRDFDataSource);
   602     var sourceDS = helpTocPanel.database;
   603     doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
   605     // search glossary.
   606     sourceDS = helpGlossaryPanel.database;
   607     doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
   609     // search index
   610     sourceDS = helpIndexPanel.database;
   611     doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
   613     // search additional search datasources
   614     sourceDS = helpSearchPanel.database;
   615     doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0);
   617     if (emptySearch)
   618         assertSearchEmpty(resultsDS);
   619     // Add the datasource to the search tree
   620     searchTree.database.AddDataSource(resultsDS);
   621     searchTree.builder.rebuild();
   622 }
   624 function clearDatabases(compositeDataSource) {
   625     var enumDS = compositeDataSource.GetDataSources()
   626     while (enumDS.hasMoreElements()) {
   627         var ds = enumDS.getNext();
   628         compositeDataSource.RemoveDataSource(ds);
   629     }
   630 }
   632 function doFindOnDatasource(resultsDS, sourceDS, resource, level) {
   633     if (level > MAX_LEVEL) {
   634         try {
   635             log("Recursive reference to resource: " + resource.Value + ".");
   636         } catch (e) {
   637             log("Recursive reference to unknown resource.");
   638         }
   639         return;
   640     }
   641     // find all SUBHEADING children of current resource.
   642     var targets = sourceDS.GetTargets(resource, NC_SUBHEADINGS, true);
   643     while (targets.hasMoreElements()) {
   644         var target = targets.getNext();
   645         target = target.QueryInterface(Components.interfaces.nsIRDFResource);
   646         // The first child of a rdf:subheading should (must) be a rdf:seq.
   647         // Should we test for a SEQ here?
   648         doFindOnSeq(resultsDS, sourceDS, target, level+1);
   649     }
   650 }
   652 function doFindOnSeq(resultsDS, sourceDS, resource, level) {
   653     // load up an RDFContainer so we can access the contents of the current
   654     // rdf:seq.
   655     RDFContainer.Init(sourceDS, resource);
   656     var targets = RDFContainer.GetElements();
   657     while (targets.hasMoreElements()) {
   658         var target = targets.getNext();
   659         var link = sourceDS.GetTarget(target, NC_LINK, true);
   660         var name = sourceDS.GetTarget(target, NC_NAME, true);
   662         if (link &&
   663             name instanceof Components.interfaces.nsIRDFLiteral &&
   664             isMatch(name.Value)) {
   665             // we have found a search entry - add it to the results datasource.
   666             var urn = RDF.GetAnonymousResource();
   667             resultsDS.Assert(urn, NC_NAME, name, true);
   668             resultsDS.Assert(urn, NC_LINK, link, true);
   669             resultsDS.Assert(RDF_ROOT, NC_CHILD, urn, true);
   671             emptySearch = false;
   672         }
   673         // process any nested rdf:seq elements.
   674         doFindOnDatasource(resultsDS, sourceDS, target, level+1);
   675     }
   676 }
   678 function assertSearchEmpty(resultsDS) {
   679     var resSearchEmpty = RDF.GetResource("urn:emptySearch");
   680         resultsDS.Assert(RDF_ROOT,
   681             NC_CHILD,
   682                 resSearchEmpty,
   683                 true);
   684         resultsDS.Assert(resSearchEmpty,
   685             NC_NAME,
   686                 RDF.GetLiteral(emptySearchText),
   687                 true);
   688         resultsDS.Assert(resSearchEmpty,
   689                 NC_LINK,
   690                 RDF.GetLiteral(emptySearchLink),
   691                 true);
   692 }
   694 function isMatch(text) {
   695     for (var i=0; i < RE.length; ++i ) {
   696         if (!RE[i].test(text)) {
   697             return false;
   698         }
   699     }
   700     return true;
   701 }
   703 function getAttribute(datasource, resource, attributeResourceName,
   704         defaultValue) {
   705     var literal = datasource.GetTarget(resource, attributeResourceName, true);
   706     if (!literal) {
   707         return defaultValue;
   708     }
   709     return getLiteralValue(literal, defaultValue);
   710 }
   712 function getLiteralValue(literal, defaultValue) {
   713     if (literal) {
   714         literal = literal.QueryInterface(Components.interfaces.nsIRDFLiteral);
   715         if (literal) {
   716             return literal.Value;
   717         }
   718     }
   719     if (defaultValue) {
   720         return defaultValue;
   721     }
   722     return null;
   723 }
   725 # Write debug string to error console.
   726 function log(aText) {
   727     CONSOLE_SERVICE.logStringMessage(aText);
   728 }
   730 function getBoolPref (aPrefname, aDefault)
   731 {
   732   try { 
   733     var pref = Components.classes["@mozilla.org/preferences-service;1"]
   734                          .getService(Components.interfaces.nsIPrefBranch);
   735     return pref.getBoolPref(aPrefname);
   736   }
   737   catch(e) {
   738     return aDefault;
   739   }
   740 }
   742 # getXulWin - Returns the current Help window as a nsIXULWindow.
   743 function getXulWin()
   744 {
   745   window.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
   746   var webnav = window.getInterface(Components.interfaces.nsIWebNavigation);
   747   var dsti = webnav.QueryInterface(Components.interfaces.nsIDocShellTreeItem);
   748   var treeowner = dsti.treeOwner;
   749   var ifreq = treeowner.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
   751   return ifreq.getInterface(Components.interfaces.nsIXULWindow);
   752 }
   754 # toggleZLevel - Toggles whether or not the window will always appear on top. Because
   755 #   alwaysRaised is not supported on an OS other than Windows, this code will not
   756 #   appear in those builds.
   757 #
   758 #   element - The DOM node that persists the checked state.
   759 #ifdef XP_WIN
   760 #define HELP_ALWAYS_RAISED_TOGGLE
   761 #endif
   762 #ifdef HELP_ALWAYS_RAISED_TOGGLE
   763 function toggleZLevel(element)
   764 {
   765   var xulwin = getXulWin();
   767   // Now we can flip the zLevel, and set the attribute so that it persists correctly
   768   if (xulwin.zLevel > xulwin.normalZ) {
   769     xulwin.zLevel = xulwin.normalZ;
   770     element.setAttribute("checked", "false");
   771   } else {
   772     xulwin.zLevel = xulwin.raisedZ;
   773     element.setAttribute("checked", "true");
   774   }
   775 }
   776 #endif

mercurial