michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: # Global Variables michael@0: var helpBrowser; michael@0: var helpSearchPanel; michael@0: var emptySearch; michael@0: var emptySearchText; michael@0: var emptySearchLink = "about:blank"; michael@0: var helpTocPanel; michael@0: var helpIndexPanel; michael@0: var helpGlossaryPanel; michael@0: var strBundle; michael@0: var gTocDSList = ""; michael@0: michael@0: # Namespaces michael@0: const NC = "http://home.netscape.com/NC-rdf#"; michael@0: const MAX_LEVEL = 40; // maximum depth of recursion in search datasources. michael@0: const MAX_HISTORY_MENU_ITEMS = 6; michael@0: michael@0: # ifdef logic ripped from toolkit/components/help/content/platformClasses.css michael@0: #ifdef XP_WIN michael@0: const platform = "win"; michael@0: #else michael@0: #ifdef XP_MACOSX michael@0: const platform = "mac"; michael@0: #else michael@0: const platform = "unix"; michael@0: #endif michael@0: #endif michael@0: michael@0: # Resources michael@0: const RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"] michael@0: .getService(Components.interfaces.nsIRDFService); michael@0: const RDF_ROOT = RDF.GetResource("urn:root"); michael@0: const NC_PANELLIST = RDF.GetResource(NC + "panellist"); michael@0: const NC_PANELID = RDF.GetResource(NC + "panelid"); michael@0: const NC_EMPTY_SEARCH_TEXT = RDF.GetResource(NC + "emptysearchtext"); michael@0: const NC_EMPTY_SEARCH_LINK = RDF.GetResource(NC + "emptysearchlink"); michael@0: const NC_DATASOURCES = RDF.GetResource(NC + "datasources"); michael@0: const NC_PLATFORM = RDF.GetResource(NC + "platform"); michael@0: const NC_SUBHEADINGS = RDF.GetResource(NC + "subheadings"); michael@0: const NC_NAME = RDF.GetResource(NC + "name"); michael@0: const NC_CHILD = RDF.GetResource(NC + "child"); michael@0: const NC_LINK = RDF.GetResource(NC + "link"); michael@0: const NC_TITLE = RDF.GetResource(NC + "title"); michael@0: const NC_BASE = RDF.GetResource(NC + "base"); michael@0: const NC_DEFAULTTOPIC = RDF.GetResource(NC + "defaulttopic"); michael@0: michael@0: var RDFContainer = michael@0: Components.classes["@mozilla.org/rdf/container;1"] michael@0: .createInstance(Components.interfaces.nsIRDFContainer); michael@0: const CONSOLE_SERVICE = Components.classes['@mozilla.org/consoleservice;1'] michael@0: .getService(Components.interfaces.nsIConsoleService); michael@0: michael@0: var RE; michael@0: michael@0: var helpFileURI; michael@0: var helpFileDS; michael@0: # Set from nc:base attribute on help rdf file. It may be used for prefix michael@0: # reduction on all links within the current help set. michael@0: var helpBaseURI; michael@0: michael@0: /* defaultTopic is either set michael@0: 1. in the openHelp() call, passed as an argument to the Help window and michael@0: evaluated in init(), or michael@0: 2. in nc:defaulttopic in the content pack (e.g. firebirdhelp.rdf), michael@0: evaluated in loadHelpRDF(), or michael@0: 3. "welcome" as a fallback, specified in loadHelpRDF() as well; michael@0: displayTopic() then uses defaultTopic because topic is null. */ michael@0: var defaultTopic; michael@0: michael@0: const NSRESULT_RDF_SYNTAX_ERROR = 0x804e03f7; michael@0: michael@0: # This function is called by dialogs/windows that want to display michael@0: # context-sensitive help michael@0: # These dialogs/windows should include the script michael@0: # chrome://help/content/contextHelp.js michael@0: function displayTopic(topic) { michael@0: // Get the page to open. michael@0: var uri = getLink(topic); michael@0: // Use default topic if specified topic is not found. michael@0: if (!uri) { michael@0: uri = getLink(defaultTopic); michael@0: } michael@0: // Load the page. michael@0: if (uri) michael@0: loadURI(uri); michael@0: } michael@0: michael@0: # Initialize the Help window michael@0: function init() { michael@0: // Cache panel references. michael@0: helpSearchPanel = document.getElementById("help-search-panel"); michael@0: helpTocPanel = document.getElementById("help-toc-panel"); michael@0: helpIndexPanel = document.getElementById("help-index-panel"); michael@0: helpGlossaryPanel = document.getElementById("help-glossary-panel"); michael@0: helpBrowser = document.getElementById("help-content"); michael@0: michael@0: // Turn off unnecessary features for security michael@0: helpBrowser.docShell.allowJavascript = false; michael@0: helpBrowser.docShell.allowPlugins = false; michael@0: helpBrowser.docShell.allowSubframes = false; michael@0: helpBrowser.docShell.allowMetaRedirects = false; michael@0: michael@0: strBundle = document.getElementById("bundle_help"); michael@0: emptySearchText = strBundle.getString("emptySearchText"); michael@0: michael@0: // Get the content pack, base URL, and help topic michael@0: var helpTopic = defaultTopic; michael@0: if ("arguments" in window && michael@0: window.arguments[0] instanceof Components.interfaces.nsIDialogParamBlock) { michael@0: helpFileURI = window.arguments[0].GetString(0); michael@0: // trailing "/" included. michael@0: helpBaseURI = helpFileURI.substring(0, helpFileURI.lastIndexOf("/")+1); michael@0: helpTopic = window.arguments[0].GetString(1); michael@0: } michael@0: michael@0: loadHelpRDF(); michael@0: displayTopic(helpTopic); michael@0: michael@0: // Move to Center of Screen michael@0: const width = document.documentElement.getAttribute("width"); michael@0: const height = document.documentElement.getAttribute("height"); michael@0: window.moveTo((screen.availWidth - width) / 2, (screen.availHeight - height) / 2); michael@0: michael@0: // Initialize history. michael@0: getWebNavigation().sessionHistory = michael@0: Components.classes["@mozilla.org/browser/shistory;1"] michael@0: .createInstance(Components.interfaces.nsISHistory); michael@0: window.XULBrowserWindow = new nsHelpStatusHandler(); michael@0: michael@0: //Start the status handler. michael@0: window.XULBrowserWindow.init(); michael@0: michael@0: // Hook up UI through Progress Listener michael@0: const interfaceRequestor = helpBrowser.docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor); michael@0: const webProgress = interfaceRequestor.getInterface(Components.interfaces.nsIWebProgress); michael@0: michael@0: webProgress.addProgressListener(window.XULBrowserWindow, Components.interfaces.nsIWebProgress.NOTIFY_ALL); michael@0: michael@0: var searchBox = document.getElementById("findText"); michael@0: searchBox.clickSelectsAll = getBoolPref("browser.urlbar.clickSelectsAll", true); michael@0: michael@0: setTimeout(focusSearch, 0); michael@0: } michael@0: michael@0: function showSearchSidebar() { michael@0: // if you tab too quickly, you end up with stuck focus, revert focus to the searchbar michael@0: var searchTree = document.getElementById("help-toc-panel"); michael@0: if (searchTree.treeBoxObject.focused) { michael@0: focusSearch(); michael@0: } michael@0: michael@0: var tableOfContents = document.getElementById("help-toc-sidebar"); michael@0: tableOfContents.setAttribute("hidden", "true"); michael@0: michael@0: var sidebar = document.getElementById("help-search-sidebar"); michael@0: sidebar.removeAttribute("hidden"); michael@0: } michael@0: michael@0: function hideSearchSidebar(aEvent) { michael@0: // if we're focused in the search results, focus content michael@0: var searchTree = document.getElementById("help-search-tree"); michael@0: if (searchTree.treeBoxObject.focused) { michael@0: content.focus(); michael@0: } michael@0: michael@0: var sidebar = document.getElementById("help-search-sidebar"); michael@0: sidebar.setAttribute("hidden", "true"); michael@0: michael@0: var tableOfContents = document.getElementById("help-toc-sidebar"); michael@0: tableOfContents.removeAttribute("hidden"); michael@0: } michael@0: michael@0: # loadHelpRDF michael@0: # Parse the provided help content pack RDF file, and use it to michael@0: # populate the datasources attached to the trees in the viewer. michael@0: # Filter out any information not applicable to the user's platform. michael@0: function loadHelpRDF() { michael@0: if (!helpFileDS) { michael@0: try { michael@0: helpFileDS = RDF.GetDataSourceBlocking(helpFileURI); michael@0: } catch (e if (e.result == NSRESULT_RDF_SYNTAX_ERROR)) { michael@0: log("Help file: " + helpFileURI + " contains a syntax error."); michael@0: } catch (e) { michael@0: log("Help file: " + helpFileURI + " was not found."); michael@0: } michael@0: michael@0: try { michael@0: document.title = getAttribute(helpFileDS, RDF_ROOT, NC_TITLE, ""); michael@0: helpBaseURI = getAttribute(helpFileDS, RDF_ROOT, NC_BASE, helpBaseURI); michael@0: // if there's no nc:defaulttopic in the content pack, set "welcome" michael@0: // as the default topic michael@0: defaultTopic = getAttribute(helpFileDS, michael@0: RDF_ROOT, NC_DEFAULTTOPIC, "welcome"); michael@0: michael@0: var panelDefs = helpFileDS.GetTarget(RDF_ROOT, NC_PANELLIST, true); michael@0: RDFContainer.Init(helpFileDS, panelDefs); michael@0: var iterator = RDFContainer.GetElements(); michael@0: while (iterator.hasMoreElements()) { michael@0: var panelDef = iterator.getNext(); michael@0: michael@0: var panelID = getAttribute(helpFileDS, panelDef, NC_PANELID, null); michael@0: var datasources = getAttribute(helpFileDS, panelDef, NC_DATASOURCES, ""); michael@0: var panelPlatforms = getAttribute(helpFileDS, panelDef, NC_PLATFORM, null); michael@0: michael@0: if (panelPlatforms && panelPlatforms.split(/\s+/).indexOf(platform) == -1) michael@0: continue; // ignore datasources for other platforms michael@0: michael@0: // empty datasources are valid on search panel definitions michael@0: // convert them to "rdf:null" which can be filtered and ignored michael@0: if (!datasources) michael@0: datasources = "rdf:null"; michael@0: michael@0: datasources = normalizeLinks(helpBaseURI, datasources); michael@0: michael@0: var datasourceArray = datasources.split(/\s+/) michael@0: .filter(function(x) { return x != "rdf:null"; }) michael@0: .map(RDF.GetDataSourceBlocking); michael@0: michael@0: // Cache Additional Datasources to Augment Search Datasources. michael@0: if (panelID == "search") { michael@0: emptySearchText = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_TEXT, emptySearchText); michael@0: emptySearchLink = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_LINK, emptySearchLink); michael@0: michael@0: datasourceArray.forEach(helpSearchPanel.database.AddDataSource, michael@0: helpSearchPanel.database); michael@0: if (!panelPlatforms) michael@0: filterDatasourceByPlatform(helpSearchPanel.database); michael@0: michael@0: continue; // to next panel definition michael@0: } michael@0: michael@0: // cache toc datasources list for use in getLink() michael@0: if (panelID == "toc") michael@0: gTocDSList += " " + datasources; michael@0: michael@0: var tree = document.getElementById("help-" + panelID + "-panel"); michael@0: michael@0: // add each datasource to the current tree michael@0: datasourceArray.forEach(tree.database.AddDataSource, michael@0: tree.database); michael@0: michael@0: // filter and display the current tree michael@0: if (!panelPlatforms) michael@0: filterDatasourceByPlatform(tree.database); michael@0: tree.builder.rebuild(); michael@0: } michael@0: } catch (e) { michael@0: log(e + ""); michael@0: } michael@0: } michael@0: } michael@0: michael@0: # filterDatasourceByPlatform michael@0: # Remove statements for other platforms from a datasource. michael@0: function filterDatasourceByPlatform(aDatasource) { michael@0: filterNodeByPlatform(aDatasource, RDF_ROOT, 0); michael@0: } michael@0: michael@0: # filterNodeByPlatform michael@0: # Remove statements for other platforms from the provided datasource. michael@0: function filterNodeByPlatform(aDatasource, aCurrentResource, aCurrentLevel) { michael@0: if (aCurrentLevel > MAX_LEVEL) { michael@0: log("Datasources over " + MAX_LEVEL + " levels deep are unsupported."); michael@0: return; michael@0: } michael@0: michael@0: // get the subheadings under aCurrentResource and filter them michael@0: var nodes = aDatasource.GetTargets(aCurrentResource, NC_SUBHEADINGS, true); michael@0: while (nodes.hasMoreElements()) { michael@0: var node = nodes.getNext(); michael@0: node = node.QueryInterface(Components.interfaces.nsIRDFResource); michael@0: // should we test for rdf:Seq here? see also doFindOnDatasource michael@0: filterSeqByPlatform(aDatasource, node, aCurrentLevel+1); michael@0: } michael@0: } michael@0: michael@0: # filterSeqByPlatform michael@0: # Go through the children of aNode, if any, removing statements applicable michael@0: # only on other platforms. michael@0: function filterSeqByPlatform(aDatasource, aNode, aCurrentLevel) { michael@0: // get nc:subheading children into an enumerator michael@0: var RDFC = Components.classes["@mozilla.org/rdf/container;1"] michael@0: .createInstance(Components.interfaces.nsIRDFContainer); michael@0: RDFC.Init(aDatasource, aNode); michael@0: var targets = RDFC.GetElements(); michael@0: michael@0: // process items in the rdf:Seq michael@0: while (targets.hasMoreElements()) { michael@0: var currentTarget = targets.getNext(); michael@0: michael@0: // find out on which platforms this node is meaningful michael@0: var nodePlatforms = getAttribute(aDatasource, michael@0: currentTarget.QueryInterface(Components.interfaces.nsIRDFResource), michael@0: NC_PLATFORM, michael@0: platform); michael@0: michael@0: if (nodePlatforms.split(/\s+/).indexOf(platform) == -1) { // node is for another platform michael@0: var currentNode = currentTarget.QueryInterface(Components.interfaces.nsIRDFNode); michael@0: // "false" because we don't want to renumber elements in the container michael@0: RDFC.RemoveElement(currentNode, false); michael@0: michael@0: // move to next node - ignore the children, because 1) they might be michael@0: // needed elsewhere and 2) nodes not connected to RDF_ROOT are ignored michael@0: continue; michael@0: } michael@0: michael@0: // filter any children michael@0: filterNodeByPlatform(aDatasource, currentTarget, aCurrentLevel+1); michael@0: } michael@0: } michael@0: michael@0: # Prepend helpBaseURI to list of space separated links if they don't start with michael@0: # "chrome:" michael@0: function normalizeLinks(helpBaseURI, links) { michael@0: if (!helpBaseURI) { michael@0: return links; michael@0: } michael@0: var ls = links.split(/\s+/); michael@0: if (ls.length == 0) { michael@0: return links; michael@0: } michael@0: for (var i=0; i < ls.length; ++i) { michael@0: if (ls[i] == "") michael@0: continue; michael@0: michael@0: if (ls[i].substr(0,7) != "chrome:" && ls[i].substr(0,4) != "rdf:") michael@0: ls[i] = helpBaseURI + ls[i]; michael@0: } michael@0: return ls.join(" "); michael@0: } michael@0: michael@0: function getLink(ID) { michael@0: if (!ID) michael@0: return null; michael@0: michael@0: var tocDS = document.getElementById("help-toc-panel").database; michael@0: if (!tocDS) michael@0: return null; michael@0: michael@0: // URIs include both the ID part and the base file name, michael@0: // so we need to check for a matching ID in each datasource michael@0: var tocDSArray = gTocDSList.split(/\s+/) michael@0: .filter(function(x) { return x != "rdf:null"; }); michael@0: michael@0: for (var i = 0; i < tocDSArray.length; i++) { michael@0: var resource = RDF.GetResource(tocDSArray[i] + "#" + ID); michael@0: var link = tocDS.GetTarget(resource, NC_LINK, true); michael@0: if (!link) // no such rdf:ID found michael@0: continue; michael@0: return link.QueryInterface(Components.interfaces.nsIRDFLiteral).Value; michael@0: } michael@0: return null; michael@0: } michael@0: michael@0: # Called by contextHelp.js to determine if this window is displaying the michael@0: # requested help file. michael@0: function getHelpFileURI() { michael@0: return helpFileURI; michael@0: } michael@0: michael@0: function getBrowser() { michael@0: return helpBrowser; michael@0: } michael@0: michael@0: function getWebNavigation() { michael@0: try { michael@0: return helpBrowser.webNavigation; michael@0: } catch (e) michael@0: { michael@0: return null; michael@0: } michael@0: } michael@0: michael@0: function loadURI(uri) { michael@0: if (uri.substr(0,7) != "chrome:") { michael@0: uri = helpBaseURI + uri; michael@0: } michael@0: getWebNavigation().loadURI(uri, Components.interfaces.nsIWebNavigation.LOAD_FLAGS_NONE, michael@0: null, null, null); michael@0: } michael@0: michael@0: function goBack() { michael@0: try michael@0: { michael@0: getWebNavigation().goBack(); michael@0: } catch (e) michael@0: { michael@0: } michael@0: } michael@0: michael@0: function goForward() { michael@0: try michael@0: { michael@0: getWebNavigation().goForward(); michael@0: } catch(e) michael@0: { michael@0: } michael@0: } michael@0: michael@0: function goHome() { michael@0: // Load "Welcome" page michael@0: displayTopic(defaultTopic); michael@0: } michael@0: michael@0: function print() { michael@0: try { michael@0: _content.print(); michael@0: } catch (e) { michael@0: } michael@0: } michael@0: michael@0: function FillHistoryMenu(aParent, aMenu) michael@0: { michael@0: // Remove old entries if any michael@0: deleteHistoryItems(aParent); michael@0: michael@0: var sessionHistory = getWebNavigation().sessionHistory; michael@0: michael@0: var count = sessionHistory.count; michael@0: var index = sessionHistory.index; michael@0: var end; michael@0: var j; michael@0: var entry; michael@0: michael@0: switch (aMenu) michael@0: { michael@0: case "back": michael@0: end = (index > MAX_HISTORY_MENU_ITEMS) ? index - MAX_HISTORY_MENU_ITEMS : 0; michael@0: if ((index - 1) < end) return false; michael@0: for (j = index - 1; j >= end; j--) michael@0: { michael@0: entry = sessionHistory.getEntryAtIndex(j, false); michael@0: if (entry) michael@0: createMenuItem(aParent, j, entry.title); michael@0: } michael@0: break; michael@0: case "forward": michael@0: end = ((count-index) > MAX_HISTORY_MENU_ITEMS) ? index + MAX_HISTORY_MENU_ITEMS : count - 1; michael@0: if ((index + 1) > end) return false; michael@0: for (j = index + 1; j <= end; j++) michael@0: { michael@0: entry = sessionHistory.getEntryAtIndex(j, false); michael@0: if (entry) michael@0: createMenuItem(aParent, j, entry.title); michael@0: } michael@0: break; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: function createMenuItem( aParent, aIndex, aLabel) michael@0: { michael@0: var menuitem = document.createElement( "menuitem" ); michael@0: menuitem.setAttribute( "label", aLabel ); michael@0: menuitem.setAttribute( "index", aIndex ); michael@0: aParent.appendChild( menuitem ); michael@0: } michael@0: michael@0: function deleteHistoryItems(aParent) michael@0: { michael@0: var children = aParent.childNodes; michael@0: for (var i = children.length - 1; i >= 0; --i) michael@0: { michael@0: var index = children[i].getAttribute("index"); michael@0: if (index) michael@0: aParent.removeChild(children[i]); michael@0: } michael@0: } michael@0: michael@0: function createBackMenu(event) { michael@0: return FillHistoryMenu(event.target, "back"); michael@0: } michael@0: michael@0: function createForwardMenu(event) { michael@0: return FillHistoryMenu(event.target, "forward"); michael@0: } michael@0: michael@0: function gotoHistoryIndex(aEvent) { michael@0: var index = aEvent.target.getAttribute("index"); michael@0: if (!index) { michael@0: return false; michael@0: } michael@0: try { michael@0: getWebNavigation().gotoIndex(index); michael@0: } catch(ex) { michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: function nsHelpStatusHandler() { michael@0: this.init(); michael@0: } michael@0: michael@0: nsHelpStatusHandler.prototype = { michael@0: michael@0: onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) {}, michael@0: onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress, michael@0: aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {}, michael@0: onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) {}, michael@0: onSecurityChange : function(aWebProgress, aRequest, state) {}, michael@0: onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) { michael@0: UpdateBackForwardButtons(); michael@0: }, michael@0: QueryInterface : function(aIID) { michael@0: if (aIID.equals(Components.interfaces.nsIWebProgressListener) || michael@0: aIID.equals(Components.interfaces.nsISupportsWeakReference) || michael@0: aIID.equals(Components.interfaces.nsIXULBrowserWindow) || michael@0: aIID.equals(Components.interfaces.nsISupports)) { michael@0: return this; michael@0: } michael@0: throw Components.results.NS_NOINTERFACE; michael@0: }, michael@0: michael@0: init : function() {}, michael@0: michael@0: destroy : function() {}, michael@0: michael@0: setJSStatus : function(status) {}, michael@0: setOverLink : function(link, context) {}, michael@0: onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {} michael@0: } michael@0: michael@0: function UpdateBackForwardButtons() { michael@0: var backBroadcaster = document.getElementById("canGoBack"); michael@0: var forwardBroadcaster = document.getElementById("canGoForward"); michael@0: var webNavigation = getWebNavigation(); michael@0: michael@0: // Avoid setting attributes on broadcasters if the value hasn't changed! michael@0: // Remember, guys, setting attributes on elements is expensive! They michael@0: // get inherited into anonymous content, broadcast to other widgets, etc.! michael@0: // Don't do it if the value hasn't changed! - dwh michael@0: michael@0: var backDisabled = (backBroadcaster.getAttribute("disabled") == "true"); michael@0: var forwardDisabled = (forwardBroadcaster.getAttribute("disabled") == "true"); michael@0: michael@0: if (backDisabled == webNavigation.canGoBack) { michael@0: if (backDisabled) michael@0: backBroadcaster.removeAttribute("disabled"); michael@0: else michael@0: backBroadcaster.setAttribute("disabled", true); michael@0: } michael@0: michael@0: if (forwardDisabled == webNavigation.canGoForward) { michael@0: if (forwardDisabled) michael@0: forwardBroadcaster.removeAttribute("disabled"); michael@0: else michael@0: forwardBroadcaster.setAttribute("disabled", true); michael@0: } michael@0: } michael@0: michael@0: function onselect_loadURI(tree) { michael@0: try { michael@0: var resource = tree.view.getResourceAtIndex(tree.currentIndex); michael@0: var link = tree.database.GetTarget(resource, NC_LINK, true); michael@0: if (link) { michael@0: link = link.QueryInterface(Components.interfaces.nsIRDFLiteral); michael@0: loadURI(link.Value); michael@0: } michael@0: } catch (e) { michael@0: }// when switching between tabs a spurious row number is returned. michael@0: } michael@0: michael@0: function focusSearch() { michael@0: var searchBox = document.getElementById("findText"); michael@0: searchBox.focus(); michael@0: } michael@0: michael@0: # doFind - Searches the help files for what is located in findText and outputs into michael@0: # the find search tree. michael@0: function doFind() { michael@0: if (document.getElementById("help-search-sidebar").hidden) michael@0: showSearchSidebar(); michael@0: michael@0: var searchTree = document.getElementById("help-search-tree"); michael@0: var findText = document.getElementById("findText"); michael@0: michael@0: // clear any previous results. michael@0: clearDatabases(searchTree.database); michael@0: michael@0: // if the search string is empty or contains only whitespace, purge the results tree and return michael@0: RE = findText.value.match(/\S+/g); michael@0: if (!RE) { michael@0: searchTree.builder.rebuild(); michael@0: hideSearchSidebar(); michael@0: return; michael@0: } michael@0: michael@0: // compile the search string, which has already been split up above, into regexps michael@0: for (var i=0; i < RE.length; ++i) { michael@0: RE[i] = new RegExp(RE[i], "i"); michael@0: } michael@0: emptySearch = true; michael@0: michael@0: // search TOC michael@0: var resultsDS = Components.classes["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"] michael@0: .createInstance(Components.interfaces.nsIRDFDataSource); michael@0: var sourceDS = helpTocPanel.database; michael@0: doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); michael@0: michael@0: // search glossary. michael@0: sourceDS = helpGlossaryPanel.database; michael@0: doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); michael@0: michael@0: // search index michael@0: sourceDS = helpIndexPanel.database; michael@0: doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); michael@0: michael@0: // search additional search datasources michael@0: sourceDS = helpSearchPanel.database; michael@0: doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); michael@0: michael@0: if (emptySearch) michael@0: assertSearchEmpty(resultsDS); michael@0: // Add the datasource to the search tree michael@0: searchTree.database.AddDataSource(resultsDS); michael@0: searchTree.builder.rebuild(); michael@0: } michael@0: michael@0: function clearDatabases(compositeDataSource) { michael@0: var enumDS = compositeDataSource.GetDataSources() michael@0: while (enumDS.hasMoreElements()) { michael@0: var ds = enumDS.getNext(); michael@0: compositeDataSource.RemoveDataSource(ds); michael@0: } michael@0: } michael@0: michael@0: function doFindOnDatasource(resultsDS, sourceDS, resource, level) { michael@0: if (level > MAX_LEVEL) { michael@0: try { michael@0: log("Recursive reference to resource: " + resource.Value + "."); michael@0: } catch (e) { michael@0: log("Recursive reference to unknown resource."); michael@0: } michael@0: return; michael@0: } michael@0: // find all SUBHEADING children of current resource. michael@0: var targets = sourceDS.GetTargets(resource, NC_SUBHEADINGS, true); michael@0: while (targets.hasMoreElements()) { michael@0: var target = targets.getNext(); michael@0: target = target.QueryInterface(Components.interfaces.nsIRDFResource); michael@0: // The first child of a rdf:subheading should (must) be a rdf:seq. michael@0: // Should we test for a SEQ here? michael@0: doFindOnSeq(resultsDS, sourceDS, target, level+1); michael@0: } michael@0: } michael@0: michael@0: function doFindOnSeq(resultsDS, sourceDS, resource, level) { michael@0: // load up an RDFContainer so we can access the contents of the current michael@0: // rdf:seq. michael@0: RDFContainer.Init(sourceDS, resource); michael@0: var targets = RDFContainer.GetElements(); michael@0: while (targets.hasMoreElements()) { michael@0: var target = targets.getNext(); michael@0: var link = sourceDS.GetTarget(target, NC_LINK, true); michael@0: var name = sourceDS.GetTarget(target, NC_NAME, true); michael@0: michael@0: if (link && michael@0: name instanceof Components.interfaces.nsIRDFLiteral && michael@0: isMatch(name.Value)) { michael@0: // we have found a search entry - add it to the results datasource. michael@0: var urn = RDF.GetAnonymousResource(); michael@0: resultsDS.Assert(urn, NC_NAME, name, true); michael@0: resultsDS.Assert(urn, NC_LINK, link, true); michael@0: resultsDS.Assert(RDF_ROOT, NC_CHILD, urn, true); michael@0: michael@0: emptySearch = false; michael@0: } michael@0: // process any nested rdf:seq elements. michael@0: doFindOnDatasource(resultsDS, sourceDS, target, level+1); michael@0: } michael@0: } michael@0: michael@0: function assertSearchEmpty(resultsDS) { michael@0: var resSearchEmpty = RDF.GetResource("urn:emptySearch"); michael@0: resultsDS.Assert(RDF_ROOT, michael@0: NC_CHILD, michael@0: resSearchEmpty, michael@0: true); michael@0: resultsDS.Assert(resSearchEmpty, michael@0: NC_NAME, michael@0: RDF.GetLiteral(emptySearchText), michael@0: true); michael@0: resultsDS.Assert(resSearchEmpty, michael@0: NC_LINK, michael@0: RDF.GetLiteral(emptySearchLink), michael@0: true); michael@0: } michael@0: michael@0: function isMatch(text) { michael@0: for (var i=0; i < RE.length; ++i ) { michael@0: if (!RE[i].test(text)) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: function getAttribute(datasource, resource, attributeResourceName, michael@0: defaultValue) { michael@0: var literal = datasource.GetTarget(resource, attributeResourceName, true); michael@0: if (!literal) { michael@0: return defaultValue; michael@0: } michael@0: return getLiteralValue(literal, defaultValue); michael@0: } michael@0: michael@0: function getLiteralValue(literal, defaultValue) { michael@0: if (literal) { michael@0: literal = literal.QueryInterface(Components.interfaces.nsIRDFLiteral); michael@0: if (literal) { michael@0: return literal.Value; michael@0: } michael@0: } michael@0: if (defaultValue) { michael@0: return defaultValue; michael@0: } michael@0: return null; michael@0: } michael@0: michael@0: # Write debug string to error console. michael@0: function log(aText) { michael@0: CONSOLE_SERVICE.logStringMessage(aText); michael@0: } michael@0: michael@0: function getBoolPref (aPrefname, aDefault) michael@0: { michael@0: try { michael@0: var pref = Components.classes["@mozilla.org/preferences-service;1"] michael@0: .getService(Components.interfaces.nsIPrefBranch); michael@0: return pref.getBoolPref(aPrefname); michael@0: } michael@0: catch(e) { michael@0: return aDefault; michael@0: } michael@0: } michael@0: michael@0: # getXulWin - Returns the current Help window as a nsIXULWindow. michael@0: function getXulWin() michael@0: { michael@0: window.QueryInterface(Components.interfaces.nsIInterfaceRequestor); michael@0: var webnav = window.getInterface(Components.interfaces.nsIWebNavigation); michael@0: var dsti = webnav.QueryInterface(Components.interfaces.nsIDocShellTreeItem); michael@0: var treeowner = dsti.treeOwner; michael@0: var ifreq = treeowner.QueryInterface(Components.interfaces.nsIInterfaceRequestor); michael@0: michael@0: return ifreq.getInterface(Components.interfaces.nsIXULWindow); michael@0: } michael@0: michael@0: # toggleZLevel - Toggles whether or not the window will always appear on top. Because michael@0: # alwaysRaised is not supported on an OS other than Windows, this code will not michael@0: # appear in those builds. michael@0: # michael@0: # element - The DOM node that persists the checked state. michael@0: #ifdef XP_WIN michael@0: #define HELP_ALWAYS_RAISED_TOGGLE michael@0: #endif michael@0: #ifdef HELP_ALWAYS_RAISED_TOGGLE michael@0: function toggleZLevel(element) michael@0: { michael@0: var xulwin = getXulWin(); michael@0: michael@0: // Now we can flip the zLevel, and set the attribute so that it persists correctly michael@0: if (xulwin.zLevel > xulwin.normalZ) { michael@0: xulwin.zLevel = xulwin.normalZ; michael@0: element.setAttribute("checked", "false"); michael@0: } else { michael@0: xulwin.zLevel = xulwin.raisedZ; michael@0: element.setAttribute("checked", "true"); michael@0: } michael@0: } michael@0: #endif