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