diff options
Diffstat (limited to 'comm/suite/components/helpviewer')
-rw-r--r-- | comm/suite/components/helpviewer/content/contextHelp.js | 68 | ||||
-rw-r--r-- | comm/suite/components/helpviewer/content/help.js | 856 | ||||
-rw-r--r-- | comm/suite/components/helpviewer/content/help.xul | 284 | ||||
-rw-r--r-- | comm/suite/components/helpviewer/content/helpContextOverlay.xul | 58 | ||||
-rw-r--r-- | comm/suite/components/helpviewer/content/platformClasses.css | 13 | ||||
-rw-r--r-- | comm/suite/components/helpviewer/jar.mn | 11 | ||||
-rw-r--r-- | comm/suite/components/helpviewer/moz.build | 7 |
7 files changed, 1297 insertions, 0 deletions
diff --git a/comm/suite/components/helpviewer/content/contextHelp.js b/comm/suite/components/helpviewer/content/contextHelp.js new file mode 100644 index 0000000000..151cd777a9 --- /dev/null +++ b/comm/suite/components/helpviewer/content/contextHelp.js @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +var { AppConstants } = + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + +// Set the default content pack to the Mozilla content pack. Use the +// setHelpFileURI function to set this value. +var helpFileURI; + +// openHelp - Opens up the Mozilla Help Viewer with the specified +// topic and content pack. +// see http://www.mozilla.org/projects/help-viewer/content_packs.html +function openHelp(topic, contentPack) +{ + // helpFileURI is the content pack to use in this function. If contentPack is defined, + // use that and set the helpFileURI to that value so that it will be the default. + helpFileURI = contentPack || helpFileURI; + + // Try to find previously opened help. + var topWindow = locateHelpWindow(helpFileURI); + + if ( topWindow ) { + // Open topic in existing window. + topWindow.focus(); + topWindow.displayTopic(topic); + } else { + // Open topic in new window. + const params = Cc["@mozilla.org/embedcomp/dialogparam;1"] + .createInstance(Ci.nsIDialogParamBlock); + params.SetNumberStrings(2); + params.SetString(0, helpFileURI); + params.SetString(1, topic); + + let openFeatures = "chrome,all,dialog=no"; + + if (AppConstants.platform == "win") { + openFeatures += ",alwaysRaised"; + } + Services.ww.openWindow(null, "chrome://help/content/help.xul", "_blank", + openFeatures, params); + } +} + +// setHelpFileURI - Sets the default content pack to use in the Help Viewer +function setHelpFileURI(rdfURI) +{ + helpFileURI = rdfURI; +} + +// Locate existing help window for this content pack. +function locateHelpWindow(contentPack) { + const iterator = Services.wm.getEnumerator("suite:help"); + var topWindow = null; + var aWindow; + + // Loop through help windows looking for one with selected content + // pack. + while (iterator.hasMoreElements()) { + aWindow = iterator.getNext(); + if (!aWindow.closed && aWindow.getHelpFileURI() == contentPack) { + topWindow = aWindow; + } + } + return topWindow; +} diff --git a/comm/suite/components/helpviewer/content/help.js b/comm/suite/components/helpviewer/content/help.js new file mode 100644 index 0000000000..4a7d0b1cbb --- /dev/null +++ b/comm/suite/components/helpviewer/content/help.js @@ -0,0 +1,856 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +var { AppConstants } = + ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + +// Global Variables +var helpExternal; +var helpBrowser; +var helpSearchPanel; +var emptySearch; +var emptySearchText; +var emptySearchLink = "about:blank"; +var helpTocPanel; +var helpIndexPanel; +var helpGlossaryPanel; +var strBundle; +var gTocDSList = ""; + +// Namespaces +const NC = "http://home.netscape.com/NC-rdf#"; +const MAX_LEVEL = 40; // maximum depth of recursion in search datasources. +const MAX_HISTORY_MENU_ITEMS = 6; + +const platform = getCurrentPlatform(); + +// Resources +const RDF = Cc["@mozilla.org/rdf/rdf-service;1"] + .getService(Ci.nsIRDFService); +const RDF_ROOT = RDF.GetResource("urn:root"); +const NC_PANELLIST = RDF.GetResource(NC + "panellist"); +const NC_PANELID = RDF.GetResource(NC + "panelid"); +const NC_EMPTY_SEARCH_TEXT = RDF.GetResource(NC + "emptysearchtext"); +const NC_EMPTY_SEARCH_LINK = RDF.GetResource(NC + "emptysearchlink"); +const NC_DATASOURCES = RDF.GetResource(NC + "datasources"); +const NC_PLATFORM = RDF.GetResource(NC + "platform"); +const NC_SUBHEADINGS = RDF.GetResource(NC + "subheadings"); +const NC_NAME = RDF.GetResource(NC + "name"); +const NC_CHILD = RDF.GetResource(NC + "child"); +const NC_LINK = RDF.GetResource(NC + "link"); +const NC_TITLE = RDF.GetResource(NC + "title"); +const NC_BASE = RDF.GetResource(NC + "base"); +const NC_DEFAULTTOPIC = RDF.GetResource(NC + "defaulttopic"); + +var RDFContainer = Cc["@mozilla.org/rdf/container;1"] + .createInstance(Ci.nsIRDFContainer); + +var RE; + +var helpFileURI; +var helpFileDS; +// Set from nc:base attribute on help rdf file. It may be used for prefix +// reduction on all links within the current help set. +var helpBaseURI; + +/* defaultTopic is either set + 1. in the openHelp() call, passed as an argument to the Help window and + evaluated in init(), or + 2. in nc:defaulttopic in the content pack (e.g. firebirdhelp.rdf), + evaluated in loadHelpRDF(), or + 3. "welcome" as a fallback, specified in loadHelpRDF() as well; + displayTopic() then uses defaultTopic because topic is null. */ +var defaultTopic; + +const NSRESULT_RDF_SYNTAX_ERROR = 0x804e03f7; + +// Translate the current application platform to one the +// help viewer understands. +function getCurrentPlatform() { + + // The supported platforms are defined in + // suite/locales/en-US/chrome/common/help/suitehelp.rdf. + // We can't just return the current platform 1:1 because + // this would need l10n changes for all languages. + if (AppConstants.platform == "win") { + return "win"; + } + + if (AppConstants.platform == "macosx") { + return "mac"; + } + + if (AppConstants.platform == "linux") { + return "unix"; + } + + // We never end up here in official builds. + return "---"; +} + +// This function is called by dialogs/windows that want to display +// context-sensitive help +// These dialogs/windows should include the script +// chrome://help/content/contextHelp.js +function displayTopic(topic) { + // Get the page to open. + var uri = getLink(topic); + // Use default topic if specified topic is not found. + if (!uri) { + uri = getLink(defaultTopic); + } + // Load the page. + if (uri) + loadURI(uri); +} + +// Initialize the Help window +function init() { + // Cache panel references. + helpSearchPanel = document.getElementById("help-search-panel"); + helpTocPanel = document.getElementById("help-toc-panel"); + helpIndexPanel = document.getElementById("help-index-panel"); + helpGlossaryPanel = document.getElementById("help-glossary-panel"); + helpBrowser = document.getElementById("help-content"); + + // Turn off unnecessary features for security + helpBrowser.docShell.allowJavascript = false; + helpBrowser.docShell.allowPlugins = false; + helpBrowser.docShell.allowSubframes = false; + helpBrowser.docShell.allowMetaRedirects = false; + + strBundle = document.getElementById("bundle_help"); + emptySearchText = strBundle.getString("emptySearchText"); + + // Get the content pack, base URL, and help topic + var helpTopic = defaultTopic; + if ("arguments" in window && + window.arguments[0] instanceof Ci.nsIDialogParamBlock) { + helpFileURI = window.arguments[0].GetString(0); + // trailing "/" included. + helpBaseURI = helpFileURI.substring(0, helpFileURI.lastIndexOf("/")+1); + helpTopic = window.arguments[0].GetString(1); + } + + loadHelpRDF(); + displayTopic(helpTopic); + + // Move to Center of Screen + const width = document.documentElement.getAttribute("width"); + const height = document.documentElement.getAttribute("height"); + window.moveTo((screen.availWidth - width) / 2, (screen.availHeight - height) / 2); + + // Initialize history. + getWebNavigation().sessionHistory = + Cc["@mozilla.org/browser/shistory;1"].createInstance(Ci.nsISHistory); + window.XULBrowserWindow = new nsHelpStatusHandler(); + + //Start the status handler. + window.XULBrowserWindow.init(); + + // Hook up UI through Progress Listener + const interfaceRequestor = helpBrowser.docShell.QueryInterface(Ci.nsIInterfaceRequestor); + const webProgress = interfaceRequestor.getInterface(Ci.nsIWebProgress); + + webProgress.addProgressListener(window.XULBrowserWindow, Ci.nsIWebProgress.NOTIFY_ALL); + + var searchBox = document.getElementById("findText"); + searchBox.clickSelectsAll = Services.prefs.getBoolPref("browser.urlbar.clickSelectsAll", true); + + setTimeout(focusSearch, 0); + + helpExternal = document.getElementById("help-external"); + helpExternal.docShell.useErrorPages = false; + helpExternal + .docShell + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIURIContentListener) + .parentContentListener = helpContentListener; + helpExternal.addProgressListener(window.XULBrowserWindow, Ci.nsIWebProgress.NOTIFY_ALL); + +} +function contentClick(event) { + // is this a left click on a link? + if (event.shiftKey || event.ctrlKey || event.altKey || event.metaKey || event.button != 0) + return true; + + // is this a link? + var target = event.target; + while (!(target instanceof HTMLAnchorElement)) + if (!(target = target.parentNode)) + return true; + + // is this an internal link? + if (target.href.lastIndexOf("chrome:", 0) == 0) + return true; + + var uri = target.href; + if (/^x-moz-url-link:/.test(uri)) + uri = Services.urlFormatter.formatURLPref(RegExp.rightContext); + + try { + helpExternal.webNavigation + .loadURI(uri, + Ci.nsIWebNavigation.LOAD_FLAGS_IS_LINK, + null, null, null, + Services.scriptSecurityManager.getSystemPrincipal()); + } catch (e) {} + return false; +} + +function showSidebar() { + document.getElementById("help-sidebar-splitter").setAttribute("state", "open"); +} + +// needed by findUtils.js +var gFindInstData; +function getFindInstData() +{ + if (!gFindInstData) { + gFindInstData = new nsFindInstData(); + gFindInstData.browser = getBrowser(); + // defaults for rootSearchWindow and currentSearchWindow are fine here + } + return gFindInstData; +} + +function showSearchSidebar() { + // if you tab too quickly, you end up with stuck focus, revert focus to the searchbar + var searchTree = document.getElementById("help-toc-panel"); + if (searchTree.treeBoxObject.focused) { + focusSearch(); + } + + var tableOfContents = document.getElementById("help-toc-sidebar"); + tableOfContents.setAttribute("hidden", "true"); + + var sidebar = document.getElementById("help-search-sidebar"); + sidebar.removeAttribute("hidden"); +} + +function hideSearchSidebar(aEvent) { + // if we're focused in the search results, focus content + var searchTree = document.getElementById("help-search-tree"); + if (searchTree.treeBoxObject.focused) { + content.focus(); + } + + var sidebar = document.getElementById("help-search-sidebar"); + sidebar.setAttribute("hidden", "true"); + + var tableOfContents = document.getElementById("help-toc-sidebar"); + tableOfContents.removeAttribute("hidden"); +} + +// loadHelpRDF +// Parse the provided help content pack RDF file, and use it to +// populate the datasources attached to the trees in the viewer. +// Filter out any information not applicable to the user's platform. +function loadHelpRDF() { + if (!helpFileDS) { + try { + helpFileDS = RDF.GetDataSourceBlocking(helpFileURI); + } catch (e) { + if (e.result == NSRESULT_RDF_SYNTAX_ERROR) { + log("Help file: " + helpFileURI + " contains a syntax error."); + } else { + log("Help file: " + helpFileURI + " was not found."); + } + } + + try { + document.title = getAttribute(helpFileDS, RDF_ROOT, NC_TITLE, ""); + helpBaseURI = getAttribute(helpFileDS, RDF_ROOT, NC_BASE, helpBaseURI); + // if there's no nc:defaulttopic in the content pack, set "welcome" + // as the default topic + defaultTopic = getAttribute(helpFileDS, + RDF_ROOT, NC_DEFAULTTOPIC, "welcome"); + + var panelDefs = helpFileDS.GetTarget(RDF_ROOT, NC_PANELLIST, true); + RDFContainer.Init(helpFileDS, panelDefs); + var iterator = RDFContainer.GetElements(); + while (iterator.hasMoreElements()) { + var panelDef = iterator.getNext(); + + var panelID = getAttribute(helpFileDS, panelDef, NC_PANELID, null); + var datasources = getAttribute(helpFileDS, panelDef, NC_DATASOURCES, ""); + var panelPlatforms = getAttribute(helpFileDS, panelDef, NC_PLATFORM, null); + + if (panelPlatforms && !panelPlatforms.split(/\s+/).includes(platform)) + continue; // ignore datasources for other platforms + + // empty datasources are valid on search panel definitions + // convert them to "rdf:null" which can be filtered and ignored + if (!datasources) + datasources = "rdf:null"; + + datasources = normalizeLinks(helpBaseURI, datasources); + + var datasourceArray = datasources.split(/\s+/) + .filter(function(x) { return x != "rdf:null"; }) + .map(RDF.GetDataSourceBlocking); + + // Cache Additional Datasources to Augment Search Datasources. + if (panelID == "search") { + emptySearchText = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_TEXT, emptySearchText); + emptySearchLink = getAttribute(helpFileDS, panelDef, NC_EMPTY_SEARCH_LINK, emptySearchLink); + + datasourceArray.forEach(helpSearchPanel.database.AddDataSource, + helpSearchPanel.database); + if (!panelPlatforms) + filterDatasourceByPlatform(helpSearchPanel.database); + + continue; // to next panel definition + } + + // cache toc datasources list for use in getLink() + if (panelID == "toc") + gTocDSList += " " + datasources; + + var tree = document.getElementById("help-" + panelID + "-panel"); + + // add each datasource to the current tree + datasourceArray.forEach(tree.database.AddDataSource, + tree.database); + + // filter and display the current tree + if (!panelPlatforms) + filterDatasourceByPlatform(tree.database); + tree.builder.rebuild(); + } + } catch (e) { + log(e + ""); + } + } +} + +// filterDatasourceByPlatform +// Remove statements for other platforms from a datasource. +function filterDatasourceByPlatform(aDatasource) { + filterNodeByPlatform(aDatasource, RDF_ROOT, 0); +} + +// filterNodeByPlatform +// Remove statements for other platforms from the provided datasource. +function filterNodeByPlatform(aDatasource, aCurrentResource, aCurrentLevel) { + if (aCurrentLevel > MAX_LEVEL) { + log("Datasources over " + MAX_LEVEL + " levels deep are unsupported."); + return; + } + + // get the subheadings under aCurrentResource and filter them + var nodes = aDatasource.GetTargets(aCurrentResource, NC_SUBHEADINGS, true); + while (nodes.hasMoreElements()) { + var node = nodes.getNext(); + node = node.QueryInterface(Ci.nsIRDFResource); + // should we test for rdf:Seq here? see also doFindOnDatasource + filterSeqByPlatform(aDatasource, node, aCurrentLevel+1); + } +} + +// filterSeqByPlatform +// Go through the children of aNode, if any, removing statements applicable +// only on other platforms. +function filterSeqByPlatform(aDatasource, aNode, aCurrentLevel) { + // get nc:subheading children into an enumerator + var RDFC = Cc["@mozilla.org/rdf/container;1"] + .createInstance(Ci.nsIRDFContainer); + RDFC.Init(aDatasource, aNode); + var targets = RDFC.GetElements(); + + // process items in the rdf:Seq + while (targets.hasMoreElements()) { + var currentTarget = targets.getNext(); + + // find out on which platforms this node is meaningful + var nodePlatforms = getAttribute(aDatasource, + currentTarget.QueryInterface(Ci.nsIRDFResource), + NC_PLATFORM, + platform); + + if (!nodePlatforms.split(/\s+/).includes(platform)) { // node is for another platform + var currentNode = currentTarget.QueryInterface(Ci.nsIRDFNode); + // "false" because we don't want to renumber elements in the container + RDFC.RemoveElement(currentNode, false); + + // move to next node - ignore the children, because 1) they might be + // needed elsewhere and 2) nodes not connected to RDF_ROOT are ignored + continue; + } + + // filter any children + filterNodeByPlatform(aDatasource, currentTarget, aCurrentLevel+1); + } +} + +// Prepend helpBaseURI to list of space separated links if they don't start with +// "chrome:" +function normalizeLinks(helpBaseURI, links) { + if (!helpBaseURI) { + return links; + } + var ls = links.split(/\s+/); + if (ls.length == 0) { + return links; + } + for (var i=0; i < ls.length; ++i) { + if (ls[i] == "") + continue; + + if (ls[i].substr(0,7) != "chrome:" && ls[i].substr(0,4) != "rdf:") + ls[i] = helpBaseURI + ls[i]; + } + return ls.join(" "); +} + +function getLink(ID) { + if (!ID) + return null; + + var tocDS = document.getElementById("help-toc-panel").database; + if (!tocDS) + return null; + + // URIs include both the ID part and the base file name, + // so we need to check for a matching ID in each datasource + var tocDSArray = gTocDSList.split(/\s+/) + .filter(function(x) { return x != "rdf:null"; }); + + for (var i = 0; i < tocDSArray.length; i++) { + var resource = RDF.GetResource(tocDSArray[i] + "#" + ID); + var link = tocDS.GetTarget(resource, NC_LINK, true); + if (!link) // no such rdf:ID found + continue; + return link.QueryInterface(Ci.nsIRDFLiteral).Value; + } + return null; +} + +// Called by contextHelp.js to determine if this window is displaying the +// requested help file. +function getHelpFileURI() { + return helpFileURI; +} + +function getBrowser() { + return helpBrowser; +} + +function getWebNavigation() { + try { + return helpBrowser.webNavigation; + } catch (e) + { + return null; + } +} + +function loadURI(uri) { + if (uri.substr(0,7) != "chrome:") { + uri = helpBaseURI + uri; + } + getWebNavigation().loadURI(uri, + Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + null, null, null, + Services.scriptSecurityManager.getSystemPrincipal()); +} + +function goBack() { + try + { + getWebNavigation().goBack(); + } catch (e) + { + } +} + +function goForward() { + try + { + getWebNavigation().goForward(); + } catch(e) + { + } +} + +function goHome() { + // Load "Welcome" page + displayTopic(defaultTopic); +} + +function print() { + try { + _content.print(); + } catch (e) { + } +} + +function FillHistoryMenu(aParent, aMenu) + { + // Remove old entries if any + deleteHistoryItems(aParent); + + var sessionHistory = getWebNavigation().sessionHistory; + + var count = sessionHistory.count; + var index = sessionHistory.index; + var end; + var j; + var entry; + + switch (aMenu) + { + case "back": + end = (index > MAX_HISTORY_MENU_ITEMS) ? index - MAX_HISTORY_MENU_ITEMS : 0; + if ((index - 1) < end) return false; + for (j = index - 1; j >= end; j--) + { + entry = sessionHistory.getEntryAtIndex(j); + if (entry) + createMenuItem(aParent, j, entry.title); + } + break; + case "forward": + end = ((count-index) > MAX_HISTORY_MENU_ITEMS) ? index + MAX_HISTORY_MENU_ITEMS : count - 1; + if ((index + 1) > end) return false; + for (j = index + 1; j <= end; j++) + { + entry = sessionHistory.getEntryAtIndex(j); + if (entry) + createMenuItem(aParent, j, entry.title); + } + break; + } + return true; + } + +function createMenuItem( aParent, aIndex, aLabel) + { + var menuitem = document.createElement( "menuitem" ); + menuitem.setAttribute( "label", aLabel ); + menuitem.setAttribute( "index", aIndex ); + aParent.appendChild( menuitem ); + } + +function deleteHistoryItems(aParent) +{ + var children = aParent.childNodes; + for (var i = children.length - 1; i >= 0; --i) + { + var index = children[i].getAttribute("index"); + if (index) + aParent.removeChild(children[i]); + } +} + +function createBackMenu(event) { + return FillHistoryMenu(event.target, "back"); +} + +function createForwardMenu(event) { + return FillHistoryMenu(event.target, "forward"); +} + +function gotoHistoryIndex(aEvent) { + var index = aEvent.target.getAttribute("index"); + if (!index) { + return false; + } + try { + getWebNavigation().gotoIndex(index); + } catch(ex) { + return false; + } + return true; +} + +function nsHelpStatusHandler() { + this.init(); +} + +nsHelpStatusHandler.prototype = { + + onStateChange : function(aWebProgress, aRequest, aStateFlags, aStatus) {}, + onProgressChange : function(aWebProgress, aRequest, aCurSelfProgress, + aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress) {}, + onStatusChange : function(aWebProgress, aRequest, aStatus, aMessage) {}, + onSecurityChange : function(aWebProgress, aRequest, state) {}, + onLocationChange : function(aWebProgress, aRequest, aLocation, aFlags) { + UpdateBackForwardButtons(); + }, + QueryInterface : function(aIID) { + if (aIID.equals(Ci.nsIWebProgressListener) || + aIID.equals(Ci.nsISupportsWeakReference) || + aIID.equals(Ci.nsIXULBrowserWindow) || + aIID.equals(Ci.nsISupports)) { + return this; + } + throw Cr.NS_NOINTERFACE; + }, + + init : function() {}, + + destroy : function() {}, + + setJSStatus : function(status) {}, + setOverLink : function(link, context) {}, + onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {} +} + +function UpdateBackForwardButtons() { + var backBroadcaster = document.getElementById("canGoBack"); + var forwardBroadcaster = document.getElementById("canGoForward"); + var webNavigation = getWebNavigation(); + + // Avoid setting attributes on broadcasters if the value hasn't changed! + // Remember, guys, setting attributes on elements is expensive! They + // get inherited into anonymous content, broadcast to other widgets, etc.! + // Don't do it if the value hasn't changed! - dwh + + var backDisabled = (backBroadcaster.getAttribute("disabled") == "true"); + var forwardDisabled = (forwardBroadcaster.getAttribute("disabled") == "true"); + + if (backDisabled == webNavigation.canGoBack) { + if (backDisabled) + backBroadcaster.removeAttribute("disabled"); + else + backBroadcaster.setAttribute("disabled", true); + } + + if (forwardDisabled == webNavigation.canGoForward) { + if (forwardDisabled) + forwardBroadcaster.removeAttribute("disabled"); + else + forwardBroadcaster.setAttribute("disabled", true); + } +} + +function onselect_loadURI(tree) { + try { + var resource = tree.view.getResourceAtIndex(tree.currentIndex); + var link = tree.database.GetTarget(resource, NC_LINK, true); + if (link) { + link = link.QueryInterface(Ci.nsIRDFLiteral); + loadURI(link.Value); + } + } catch (e) { + }// when switching between tabs a spurious row number is returned. +} + +function focusSearch() { + var searchBox = document.getElementById("findText"); + searchBox.focus(); +} + +// doFind - Searches the help files for what is located in findText and outputs into +// the find search tree. +function doFind() { + if (document.getElementById("help-search-sidebar").hidden) + showSearchSidebar(); + + var searchTree = document.getElementById("help-search-tree"); + var findText = document.getElementById("findText"); + + // clear any previous results. + clearDatabases(searchTree.database); + + // if the search string is empty or contains only whitespace, purge the results tree and return + RE = findText.value.match(/\S+/g); + if (!RE) { + searchTree.builder.rebuild(); + hideSearchSidebar(); + return; + } + + // compile the search string, which has already been split up above, into regexps + for (var i=0; i < RE.length; ++i) { + RE[i] = new RegExp(RE[i], "i"); + } + emptySearch = true; + + // search TOC + var resultsDS = Cc["@mozilla.org/rdf/datasource;1?name=in-memory-datasource"] + .createInstance(Ci.nsIRDFDataSource); + var sourceDS = helpTocPanel.database; + doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); + + // search glossary. + sourceDS = helpGlossaryPanel.database; + doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); + + // search index + sourceDS = helpIndexPanel.database; + doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); + + // search additional search datasources + sourceDS = helpSearchPanel.database; + doFindOnDatasource(resultsDS, sourceDS, RDF_ROOT, 0); + + if (emptySearch) + assertSearchEmpty(resultsDS); + // Add the datasource to the search tree + searchTree.database.AddDataSource(resultsDS); + searchTree.builder.rebuild(); +} + +function clearDatabases(compositeDataSource) { + var enumDS = compositeDataSource.GetDataSources() + while (enumDS.hasMoreElements()) { + var ds = enumDS.getNext(); + compositeDataSource.RemoveDataSource(ds); + } +} + +function doFindOnDatasource(resultsDS, sourceDS, resource, level) { + if (level > MAX_LEVEL) { + try { + log("Recursive reference to resource: " + resource.Value + "."); + } catch (e) { + log("Recursive reference to unknown resource."); + } + return; + } + // find all SUBHEADING children of current resource. + var targets = sourceDS.GetTargets(resource, NC_SUBHEADINGS, true); + while (targets.hasMoreElements()) { + var target = targets.getNext().QueryInterface(Ci.nsIRDFResource); + // The first child of a rdf:subheading should (must) be a rdf:seq. + // Should we test for a SEQ here? + doFindOnSeq(resultsDS, sourceDS, target, level+1); + } +} + +function doFindOnSeq(resultsDS, sourceDS, resource, level) { + // load up an RDFContainer so we can access the contents of the current + // rdf:seq. + RDFContainer.Init(sourceDS, resource); + var targets = RDFContainer.GetElements(); + while (targets.hasMoreElements()) { + var target = targets.getNext(); + var link = sourceDS.GetTarget(target, NC_LINK, true); + var name = sourceDS.GetTarget(target, NC_NAME, true); + + if (link && name instanceof Ci.nsIRDFLiteral && isMatch(name.Value)) { + // we have found a search entry - add it to the results datasource. + var urn = RDF.GetAnonymousResource(); + resultsDS.Assert(urn, NC_NAME, name, true); + resultsDS.Assert(urn, NC_LINK, link, true); + resultsDS.Assert(RDF_ROOT, NC_CHILD, urn, true); + + emptySearch = false; + } + // process any nested rdf:seq elements. + doFindOnDatasource(resultsDS, sourceDS, target, level+1); + } +} + +function assertSearchEmpty(resultsDS) { + var resSearchEmpty = RDF.GetResource("urn:emptySearch"); + resultsDS.Assert(RDF_ROOT, + NC_CHILD, + resSearchEmpty, + true); + resultsDS.Assert(resSearchEmpty, + NC_NAME, + RDF.GetLiteral(emptySearchText), + true); + resultsDS.Assert(resSearchEmpty, + NC_LINK, + RDF.GetLiteral(emptySearchLink), + true); +} + +function isMatch(text) { + for (var i=0; i < RE.length; ++i ) { + if (!RE[i].test(text)) { + return false; + } + } + return true; +} + +function getAttribute(datasource, resource, attributeResourceName, + defaultValue) { + var literal = datasource.GetTarget(resource, attributeResourceName, true); + if (!literal) { + return defaultValue; + } + return getLiteralValue(literal, defaultValue); +} + +function getLiteralValue(literal, defaultValue) { + if (literal) { + literal = literal.QueryInterface(Ci.nsIRDFLiteral); + if (literal) { + return literal.Value; + } + } + if (defaultValue) { + return defaultValue; + } + return null; +} + +// Write debug string to error console. +function log(aText) { + Services.console.logStringMessage(aText); +} + +// getXulWin - Returns the current Help window as a nsIXULWindow. +function getXulWin() +{ + window.QueryInterface(Ci.nsIInterfaceRequestor); + var webnav = window.getInterface(Ci.nsIWebNavigation); + var dsti = webnav.QueryInterface(Ci.nsIDocShellTreeItem); + var treeowner = dsti.treeOwner; + var ifreq = treeowner.QueryInterface(Ci.nsIInterfaceRequestor); + + return ifreq.getInterface(Ci.nsIXULWindow); +} + +// toggleZLevel - Toggles whether or not the window will always appear on top. Because +// alwaysRaised is not supported on an OS other than Windows, this code will not +// be used in those builds. +// +// element - The DOM node that persists the checked state. +function toggleZLevel(element) +{ + if (AppConstants.platform != "win") { + return; + } + + var xulwin = getXulWin(); + + // Now we can flip the zLevel, and set the attribute so that it persists correctly + if (xulwin.zLevel > xulwin.normalZ) { + xulwin.zLevel = xulwin.normalZ; + element.setAttribute("checked", "false"); + } else { + xulwin.zLevel = xulwin.raisedZ; + element.setAttribute("checked", "true"); + } +} + +var helpContentListener = { + doContent: function(aContentType, aIsContentPreferred, aRequest, aContentHandler) { + throw Cr.NS_ERROR_UNEXPECTED; + }, + isPreferred: function(aContentType, aDesiredContentType) { + return false; + }, + canHandleContent: function(aContentType, aIsContentPreferred, aDesiredContentType) { + return false; + }, + loadCookie: null, + parentContentListener: null, + QueryInterface: function (aIID) { + if (aIID.equals(Ci.nsIURIContentListener) || + aIID.equals(Ci.nsISupportsWeakReference) || + aIID.equals(Ci.nsISupports)) + return this; + + throw Cr.NS_ERROR_NO_INTERFACE; + } +}; diff --git a/comm/suite/components/helpviewer/content/help.xul b/comm/suite/components/helpviewer/content/help.xul new file mode 100644 index 0000000000..514d0ebb1b --- /dev/null +++ b/comm/suite/components/helpviewer/content/help.xul @@ -0,0 +1,284 @@ +<?xml version="1.0" encoding="UTF-8"?> +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +<?xml-stylesheet href="chrome://communicator/skin/helpviewer/help.css" type="text/css"?> + +<?xul-overlay href="chrome://help/content/helpContextOverlay.xul"?> +<!DOCTYPE window [ + <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> + %brandDTD; + <!ENTITY % helpDTD SYSTEM "chrome://help/locale/help.dtd"> + %helpDTD; +]> + +<window id="help" + windowtype="suite:help" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + width="700" + height="550" +#ifdef XP_WIN + persist="width height screenX screenY zlevel" +#else + persist="width height screenX screenY" +#endif + onload="init();" + onunload="window.XULBrowserWindow.destroy();"> + + <script src="chrome://help/content/help.js"/> + <script src="chrome://global/content/viewZoomOverlay.js"/> + <script src="chrome://global/content/globalOverlay.js"/> + <script src="chrome://communicator/content/findUtils.js"/> + + <menupopup id="backMenu" position="after_start" + onpopupshowing="return createBackMenu(event);" + oncommand="gotoHistoryIndex(event);"/> + <menupopup id="forwardMenu" position="after_start" + onpopupshowing="return createForwardMenu(event);" + oncommand="gotoHistoryIndex(event);"/> + <popupset id="contentAreaContextSet"/> + + <broadcasterset id="helpBroadcasters"> + <broadcaster id="canGoBack" disabled="true"/> + <broadcaster id="canGoForward" disabled="true"/> + </broadcasterset> + <commandset id="globalEditMenuItems"/> + <commandset id="selectEditMenuItems"> + <command id="cmd_close" oncommand="close();"/> + <command id="Help:Home" oncommand="goHome();"/> + <command id="Help:Back" oncommand="goBack();" observes="canGoBack"/> + <command id="Help:Forward" oncommand="goForward();" observes="canGoForward"/> + <command id="Help:ToggleSidebar" oncommand="toggleSidebar();"/> + <command id="cmd_closeWindow" oncommand="close();"/> + <command id="cmd_fullZoomReduce" oncommand="ZoomManager.reduce();"/> + <command id="cmd_fullZoomEnlarge" oncommand="ZoomManager.enlarge();"/> + <command id="cmd_fullZoomReset" oncommand="ZoomManager.reset();"/> + <command id="cmd_find" + oncommand="findInPage(getFindInstData());"/> + <command id="cmd_findAgain" + oncommand="findAgainInPage(getFindInstData(), false);"/> + <command id="cmd_findPrevious" + oncommand="findAgainInPage(getFindInstData(), true);"/> + <command id="cmd_copy" oncommand="goDoCommand('cmd_copy')" disabled="true"/> + <command id="cmd_selectAll" oncommand="goDoCommand('cmd_selectAll')"/> + </commandset> + <keyset id="keys"> + <key id="goHome" keycode="VK_HOME" command="Help:Home" modifiers="alt"/> +#ifdef XP_UNIX + <key key="&goBackCmd.commandkey;" command="Help:Back" modifiers="accel"/> + <key key="&goForwardCmd.commandkey;" command="Help:Forward" modifiers="accel"/> +#endif +#ifdef XP_MACOSX + <key id="goBackKb" keycode="VK_LEFT" command="Help:Back" modifiers="accel"/> + <key id="goForwardKb" keycode="VK_RIGHT" command="Help:Forward" modifiers="accel"/> +#else + <key id="goBackKb" keycode="VK_LEFT" command="Help:Back" modifiers="alt"/> + <key id="goForwardKb" keycode="VK_RIGHT" command="Help:Forward" modifiers="alt"/> + <key keycode="VK_BACK" command="Help:Back"/> + <key keycode="VK_BACK" command="Help:Forward" modifiers="shift"/> +#endif + <key id="printKb" key="&printCmd.commandkey;" oncommand="print();" + modifiers="accel"/> + <key id="key_find" key="&findOnCmd.commandkey;" command="cmd_find" modifiers="accel"/> + <key id="key_findAgain" key="&findAgainCmd.commandkey;" command="cmd_findAgain" modifiers="accel"/> + <key id="key_findPrevious" key="&findAgainCmd.commandkey;" command="cmd_findPrevious" modifiers="accel,shift"/> + <key keycode="&findAgainCmd.commandkey2;" command="cmd_findAgain"/> + <key keycode="&findAgainCmd.commandkey2;" command="cmd_findPrevious" modifiers="shift"/> + <key id="key_closeWindow" key="&closeWindow.commandkey;" + command="cmd_closeWindow" modifiers="accel"/> + <key id="key_closeSearchSidebar" keycode="VK_ESCAPE" + oncommand="hideSearchSidebar(event)"/> + <key id="key_fullZoomEnlarge" key="&fullZoomEnlargeCmd.commandkey;" + command="cmd_fullZoomEnlarge" modifiers="accel"/> + <key id="key_fullZoomEnlarge2" key="&fullZoomEnlargeCmd.commandkey2;" + command="cmd_fullZoomEnlarge" modifiers="accel"/> + <key id="key_fullZoomEnlarge3" key="&fullZoomEnlargeCmd.commandkey3;" + command="cmd_fullZoomEnlarge" modifiers="accel"/> + <key id="key_fullZoomReduce" key="&fullZoomReduceCmd.commandkey;" + command="cmd_fullZoomReduce" modifiers="accel"/> + <key id="key_fullZoomReduce2" key="&fullZoomReduceCmd.commandkey2;" + command="cmd_fullZoomReduce" modifiers="accel"/> + <key id="key_fullZoomReset" key="&fullZoomResetCmd.commandkey;" + command="cmd_fullZoomReset" modifiers="accel"/> + <key id="key_fullZoomReset2" key="&fullZoomResetCmd.commandkey2;" + command="cmd_fullZoomReset" modifiers="accel"/> + <key id="key_focusSearch" key="&helpSearch.commandkey;" + oncommand="focusSearch()" modifiers="accel"/> + + </keyset> + <stringbundle id="bundle_viewZoom"/> + <stringbundle id="findBundle" + src="chrome://global/locale/finddialog.properties"/> + <stringbundle id="bundle_help" + src="chrome://help/locale/help.properties"/> + + <toolbox id="help-toolbox"> + <toolbar id="HelpToolbar" class="chromeclass-toolbar"> + <toolbarbutton id="help-back-button" type="menu-button" + label="&backButton.label;" + oncommand="if (event.target == this) goBack(); else gotoHistoryIndex(event);" + observes="canGoBack" context="backMenu" + tooltiptext="&backButton.tooltip;"> + <menupopup context="" onpopupshowing="createBackMenu(event);"/> + </toolbarbutton> + <toolbarbutton id="help-forward-button" type="menu-button" + oncommand="if (event.target == this) goForward(); else gotoHistoryIndex(event);" + tooltiptext="&forwardButton.tooltip;" + observes="canGoForward"> + <menupopup context="" onpopupshowing="createForwardMenu(event);"/> + </toolbarbutton> + <toolbarbutton id="help-home-button" + tooltiptext="&homeButton.tooltip;" + command="Help:Home"/> + <toolbarseparator/> + <toolbarbutton id="help-print-button" + label="&printButton.label;" + oncommand="print();" + tooltiptext="&printButton.tooltip;"/> + <toolbarspring flex="1"/> + <toolbaritem id="search-box" + align="center" pack="center"> + <textbox id="findText" + type="search" + placeholder="&search.emptytext;" + aria-controls="help-toc-panel" + oncommand="showSidebar(); doFind();"/> + </toolbaritem> + </toolbar> + </toolbox> + + <hbox flex="1"> + <vbox id="help-sidebar" persist="width"> + <vbox flex="1" id="help-toc-sidebar"> + <sidebarheader align="center"> + <label id="help-toc-sidebar-header" flex="1" crop="end" value="&toctab.label;" + accesskey="&toctab.accesskey;" control="help-toc-panel"/> + </sidebarheader> + <tree id="help-toc-panel" class="focusring" + flex="1" treelines="true" hidecolumnpicker="true" + datasources="rdf:null" + containment="http://home.netscape.com/NC-rdf#subheadings" + ref="urn:root" flags="dont-build-content" + onselect="onselect_loadURI(this)"> + <template> + <rule> + <conditions> + <content uri="?uri"/> + <triple subject="?uri" + predicate="http://home.netscape.com/NC-rdf#subheadings" + object="?subheadings"/> + <member container="?subheadings" + child="?subheading"/> + <triple subject="?subheading" + predicate="http://home.netscape.com/NC-rdf#name" + object="?name"/> + </conditions> + <action> + <treechildren> + <treeitem uri="?subheading"> + <treerow> + <treecell label="?name"/> + </treerow> + </treeitem> + </treechildren> + </action> + </rule> + </template> + <treecols> + <treecol id="NameColumn" flex="1" hideheader="true" + primary="true"/> + </treecols> + </tree> + </vbox> + <vbox id="help-search-sidebar" hidden="true" flex="1"> + <sidebarheader align="center"> + <label id="help-search-sidebar-header" flex="1" crop="end" + value="&searchHeader.label;"/> + </sidebarheader> + <tree id="help-search-tree" class="focusring" + flex="1" hidecolumnpicker="true" + datasources="rdf:null" + containment="http://home.netscape.com/NC-rdf#child" + ref="urn:root" flags="dont-build-content" + onselect="onselect_loadURI(this)"> + <template> + <rule> + <conditions> + <content uri="?uri"/> + <member container="?uri" + child="?subheading"/> + </conditions> + <bindings> + <binding subject="?subheading" + predicate="http://home.netscape.com/NC-rdf#name" + object="?name"/> + </bindings> + <action> + <treechildren> + <treeitem uri="?subheading"> + <treerow> + <treecell label="?name"/> + </treerow> + </treeitem> + </treechildren> + </action> + </rule> + </template> + <treecols> + <treecol id="ResultsColumn" flex="1" + hideheader="true" primary="true" + sortActive="true" sortDirection="ascending" + sort="?name"/> + </treecols> + </tree> + </vbox> + + <!-- BEGIN hidden trees used for searching --> + <!-- xxxmpc: we need a better solution for this --> + + <vbox id="help-sidebar-hidden-trees" hidden="true"> + <tree id="help-glossary-panel" + flex="1" hidecolumnpicker="true" + datasources="rdf:null" + containment="http://home.netscape.com/NC-rdf#subheadings" + ref="urn:root" flags="dont-build-content"/> + <tree id="help-index-panel" + flex="1" datasources="rdf:null" + hidecolumnpicker="true" + containment="http://home.netscape.com/NC-rdf#subheadings" + ref="urn:root" + flags="dont-build-content dont-test-empty"/> + <tree id="help-search-panel" + flex="1" hidecolumnpicker="true" + datasources="rdf:null" + containment="http://home.netscape.com/NC-rdf#subheadings" + ref="urn:root" flags="dont-build-content"/> + </vbox> + + <!-- END HIDDEN ITEMS --> + </vbox> + + <splitter id="help-sidebar-splitter" collapse="before"> + <grippy/> + </splitter> + + <vbox id="appcontent" flex="3"> + <!-- type attribute is used by frame construction to locate + iframes intended to hold (html) content --> + <browser context="contentAreaContextMenu" + type="content" + primary="true" + id="help-content" + src="about:blank" + flex="1" + onclick="return contentClick(event);"/> + <findbar id="FindToolbar" browserid="help-content"/> + <browser type="content" + id="help-external" + collapsed="true"/> + + </vbox> + </hbox> + +</window> diff --git a/comm/suite/components/helpviewer/content/helpContextOverlay.xul b/comm/suite/components/helpviewer/content/helpContextOverlay.xul new file mode 100644 index 0000000000..60cdaf69ca --- /dev/null +++ b/comm/suite/components/helpviewer/content/helpContextOverlay.xul @@ -0,0 +1,58 @@ +<?xml version="1.0"?> +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +<!DOCTYPE overlay [ + <!ENTITY % helpDTD SYSTEM "chrome://help/locale/help.dtd"> + %helpDTD; +]> +<overlay id="contentAreaContextOverlay" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + +# Help Window's right-click menu + <popupset id="contentAreaContextSet"> + <menupopup id="contentAreaContextMenu" + onpopupshowing="goUpdateCommand('cmd_copy')"> + <menuitem id="context-back" + label="&backButton.label;" + accesskey="&backButton.accesskey;" + observes="canGoBack" + oncommand="goBack()"/> + <menuitem id="context-forward" + label="&forwardButton.label;" + accesskey="&forwardButton.accesskey;" + observes="canGoForward" + oncommand="goForward()"/> + <menuseparator/> + <menuitem id="context-copy" + label="©Cmd.label;" + accesskey="©Cmd.accesskey;" + command="cmd_copy" + disabled="true"/> + <menuitem id="context-selectall" + label="&selectAllCmd.label;" + accesskey="&selectAllCmd.accesskey;" + command="cmd_selectAll"/> + <menuseparator/> + <menuitem id="zoom-in" + label="&fullZoomEnlargeBtn.label;" + accesskey="&fullZoomEnlargeBtn.accesskey;" + oncommand="ZoomManager.enlarge();"/> + <menuitem id="zoom-out" + label="&fullZoomReduceBtn.label;" + accesskey="&fullZoomReduceBtn.accesskey;" + oncommand="ZoomManager.reduce();"/> +#ifdef XP_WIN + <menuseparator/> + <menuitem id="context-zlevel" + type="checkbox" + checked="true" + persist="checked" + label="&zLevel.label;" + accesskey="&zLevel.accesskey;" + oncommand="toggleZLevel(this);"/> +#endif + </menupopup> + </popupset> +</overlay> diff --git a/comm/suite/components/helpviewer/content/platformClasses.css b/comm/suite/components/helpviewer/content/platformClasses.css new file mode 100644 index 0000000000..30332fdef3 --- /dev/null +++ b/comm/suite/components/helpviewer/content/platformClasses.css @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +%ifdef XP_WIN +.noWin, .mac, .unix { display: none; } +%else +%ifdef XP_MACOSX +.noMac, .win, .unix { display: none; } +%else +.noUnix, .win, .mac { display: none; } +%endif +%endif diff --git a/comm/suite/components/helpviewer/jar.mn b/comm/suite/components/helpviewer/jar.mn new file mode 100644 index 0000000000..d536245fef --- /dev/null +++ b/comm/suite/components/helpviewer/jar.mn @@ -0,0 +1,11 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +comm.jar: +% content help %content/communicator/helpviewer/ +* content/communicator/helpviewer/help.xul (content/help.xul) + content/communicator/helpviewer/contextHelp.js (content/contextHelp.js) + content/communicator/helpviewer/help.js (content/help.js) +* content/communicator/helpviewer/helpContextOverlay.xul (content/helpContextOverlay.xul) +* content/communicator/helpviewer/platformClasses.css (content/platformClasses.css) diff --git a/comm/suite/components/helpviewer/moz.build b/comm/suite/components/helpviewer/moz.build new file mode 100644 index 0000000000..d988c0ff9b --- /dev/null +++ b/comm/suite/components/helpviewer/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +JAR_MANIFESTS += ["jar.mn"] |