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.

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

mercurial