Add the banner for OrgCamp Paris 2011
[Worg.git] / code / org-info-js / org-info-src.js
blob2e49e9c9880d959ba62c734b8992094421482cab
1 /**
2  * @file
3  * org-info.js
4  *
5  * Version: 0.1.7.1
6  *
7  * @author Sebastian Rose, Hannover, Germany - sebastian_rose at gmx dot de
8  *
9  *
10  * This software is subject to the GNU General Public Licens version 3:
11  * see: http://www.gnu.org/licenses/
12  *
13  * Requirements:
14  *
15  *   Org-mode >= 6.12a
16  *
17  *   Org-mode > 6.23 (commit a68eb4b1e64cbe6e495fdd2c1eaf8ae597bf8602):
18  *     You'll need at least org-info.js v.0.1.0.1
19  *
20  * Usage:
21  *
22  * Include this scipt into the Header of your HTML-exported org files by
23  * customizing the variable org-export-html-style (TODO: add file local export
24  * Options here).
25  * You will also need this here somewhere in the HTML-page:
26  *
27  * <script type="text/javascript" language="JavaScript" src="org-info.js"></script>
28  * <script type="text/javascript" language="JavaScript">
29  *  <![CDATA[ // comment around this one
30  *  org_html_manager.set("LOCAL_TOC", "1");
31  *  org_html_manager.set("VIEW", "info");
32  *  org_html_manager.set("VIEW_BUTTONS", "true");
33  *  org_html_manager.set("LINK_UP", "http://full/path/to/index/of/this/directory.html");
34  *  org_html_manager.set("LINK_HOME", "http://full/path/to/homepage.html");
35  *  org_html_manager.set("MOUSE_HINT", "underline"); // or a color like '#eeeeee'
36  *  org_html_manager.setup ();
37  *  ]]> // comment around this one
38  * </script>
39  *
40  *
41  * The script is now roughly devided in sections by form-feeds. Editors can
42  * move section wise using the common emacs commands for this purpos ('C-x ]'
43  * and  'C-x ]').
44  *
45  * The sections are:
46  *    1. This comment block.
47  *    2. Everything around =OrgNodes=.
48  *    3. =org_html_manager= constructor and setup.
49  *    4. =org_html_manager= folding and view related stuff.
50  *    5. =org_html_manager= history related methods.
51  *    6. =org_html_manager= minibuffer handling.
52  *    7. =org_html_manager= user input.
53  *    8. =org_html_manager= search functonality.
54  *    9. =org_html_manager= misc.
55  *    10. Global functions.
56  */
62 /**
63  * Creates a new OrgNode.
64  * An OrgOutline stores some refs to its assoziated node in the document tree
65  * along with some additional properties.
66  */
67 function OrgNode ( _div, _heading, _link, _depth, _parent, _base_id, _toc_anchor)
69   var t = this;
70   t.DIV = _div;
71   t.BASE_ID = _base_id;                // The suffix that's common to the heading and the diffs.
72   t.IDX = -1;                          // The index in OrgHtmlManager::SECS[]
73   t.HEADING = _heading;
74   t.L = _link;
75   t.HAS_HIGHLIGHT = false;             // Node highlighted (search)
76   t.PARENT = _parent;
77   t.DIRTY = false;                     // Node is dirty, when children get
78                                        // folded seperatly.
79   t.STATE = OrgNode.STATE_FOLDED;
80   t.TOC   = _toc_anchor;
81   t.DEPTH = _depth;                    // The Rootelement will have
82                                        // the depth 0. All other
83                                        // Nodes get the depth from
84                                        // their h-level (h1, h2...)
85   t.FOLDER = null;
86   t.CHILDREN = new Array();
87   t.NAV = "";                          // The info navigation
88   t.BUTTONS = null;
90   if(null != t.PARENT) {
91     t.PARENT.addChild(this);
92     t.hide();
93   }
95   var folder = document.getElementById("text-"+t.BASE_ID);
96   if(null == folder && _base_id) {
97     var fid =  _base_id.substring(4);
98     folder = document.getElementById("text-"+fid); // try old schema
99   }
100   if(null != folder)
101     t.FOLDER = folder;
103   t.isTargetFor = new Object();
104   t.isTargetFor['#' + t.BASE_ID] = 2;
105   OrgNode.findTargetsIn(t.isTargetFor, t.HEADING, 1); // 1 == prefere this one as section link.
106   OrgNode.findTargetsIn(t.isTargetFor, t.FOLDER, 3);
109 // static variables
110 OrgNode.STATE_FOLDED = 0;
111 OrgNode.STATE_HEADLINES = 1;
112 OrgNode.STATE_UNFOLDED = 2;
117 // static functions
120 OrgNode.findTargetsIn = function(safe, container, priority)
122   if(container) {
123     var a = container.getElementsByTagName("a");
124     if(a) {
125       for(var i=0;i<a.length;++i) {
126         var n =  a[i].getAttribute('id');
127         if(n) safe['#' + n] = priority;
128         else {
129           n = a[i].getAttribute('name');
130           if(n) safe['#' + n] = priority;
131         }}}}};
133 OrgNode.hideElement = function (e)
135   if(e && e['style']) { // test for e['style'] is just quick fix for error elsewhere (fixed toc and title)
136     e.style.display = 'none';
137     e.style.visibility = 'hidden';
138   }
141 OrgNode.showElement = function (e)
143   if(e && e['style']) {
144     e.style.display = 'block';
145     e.style.visibility = 'visible';
146   }
149 OrgNode.unhideElement = function (e)
151   e.style.display="";
152   e.style.visibility="";
155 OrgNode.isHidden = function(e)
157   if(e.style.display=='none' || e.style.visibility=='hidden')
158     return true;
159   return false;
162 OrgNode.toggleElement = function (e)
164   if(e.style.display == 'none') {
165     e.style.display = 'block';
166     e.style.visibility = 'visible';
167   } else {
168     e.style.display = 'none';
169     e.style.visibility = 'hidden';
170   }
174  * Find the OrgNode containing a DOM-text-node.
175  * @param dom The text node.
176  * @param org The OrgNode containing the OrgNode in question.
177  */
178 OrgNode.textNodeToIdx = function (dom, org)
180   while(dom.nodeType !=  1 /* IE has no Node.ELEMENT_NODE... */
181         || -1 == dom.attributes["id"].value.indexOf("outline-container-")) {
182     dom = dom.parentNode;
183   }
184   var base_id = dom.attributes["id"].value.substr(18);
185   return OrgNode.idxForBaseId(base_id, org);
189  * Find an OrgNode with base_id inside an OrgNode and return it's idx.
190  * @param base The base_id.
191  * @param org The OrgNode.
192  */
193 OrgNode.idxForBaseId = function(base, org)
195   if(org.BASE_ID == base) return org;
196   for(var i = 0; i < org.CHILDREN.length; ++i) {
197     var o = OrgNode.idxForBaseId(idx, org.CHILDREN[i]);
198     if(null != o) return o;
199   }
200   return null;
204 // member functions
207 OrgNode.prototype.addChild = function (child)
209   this.CHILDREN.push(child);
210   return this.PARENT;
215 // OrgNode methods for paging (info mode)
218 OrgNode.prototype.hide = function ()
220     OrgNode.hideElement(this.DIV);
221     if(this.PARENT)
222       this.PARENT.hide();
225 OrgNode.prototype.show = function ()
227   OrgNode.showElement(this.DIV);
228   if(this.DEPTH > 2)
229     this.PARENT.show();
232 OrgNode.prototype.showAllChildren = function ()
234   for(var i=0;i<this.CHILDREN.length;++i) { this.CHILDREN[i].showAllChildren(); }
235   this.show();
238 OrgNode.prototype.hideAllChildren = function ()
240   for(var i=0;i<this.CHILDREN.length;++i) { this.CHILDREN[i].hideAllChildren(); }
241   this.hide();
245  * Set class for links to current page to current and visited pages to visited_after_load
246  * Note: visited pages will be reset after reload!
247  */
248 OrgNode.prototype.setLinkClass = function (on)
250   if(this.TOC) {
251     if(on) this.TOC.className = "current";
252     else this.TOC.className = "visited_after_load";
253   }
257 //  OrgNode methods for folding
261  * This one is called onclick() to toggle the folding state of the node.
262  * This one sets it's parent dirty, since node is folded individually. Hence the
263  * next folding of parent has to collapse all.
264  * @param show_childrens_folders Boolean. This is only used for the special way
265  * of toggling of the ROOT element. If true, prevents this OrgNode from showing
266  * the folder.
267  */
268 OrgNode.prototype.fold = function (hide_folder)
270   if(this.PARENT)
271     this.PARENT.DIRTY = true;
272   if(this.DIRTY) {
273     this.DIRTY = false;
274     this.STATE = OrgNode.STATE_UNFOLDED; // so next state is FOLDED. See below.
275   }
277   if(null != this.FOLDER) {
279     if(this.STATE == OrgNode.STATE_FOLDED) {
280       // I was folded but one could click on me. So now show Headlines
281       // recursive.
282       if(this.CHILDREN.length) {
283         this.STATE = OrgNode.STATE_HEADLINES;
284         OrgNode.hideElement(this.FOLDER);
285         for(var i=0;i<this.CHILDREN.length;++i) { this.CHILDREN[i].setState(OrgNode.STATE_HEADLINES); }
286       } else if (! hide_folder) {
287         // without children jump to unfolded state:
288         this.STATE = OrgNode.STATE_UNFOLDED;
289         OrgNode.showElement(this.FOLDER);
290       }
291     }
292     else if(this.STATE == OrgNode.STATE_HEADLINES) {
293       // show all content recursive
294       this.STATE = OrgNode.STATE_UNFOLDED;
295       OrgNode.showElement(this.FOLDER);
296       for(var i=0;i<this.CHILDREN.length;++i) { this.CHILDREN[i].setState(OrgNode.STATE_UNFOLDED); }
297     }
298     else {
299       // collapse. Show only own headline
300       this.STATE = OrgNode.STATE_FOLDED;
301       OrgNode.hideElement(this.FOLDER);
302       for(var i=0;i<this.CHILDREN.length;++i) { this.CHILDREN[i].setState(OrgNode.STATE_FOLDED); }
303     }
304   }
308  * Recursive state switching. This functions folds children of activated
309  * parents. The states have a slightly different meaning here. Here the
310  * surrounding div (outline-container-id) gets hidden too.
311  * Maybe add OrgNode.STATE_HIDDEN with same value?
312  */
313 OrgNode.prototype.setState = function (state)
315   var t = this;
316   for(var i=0;i<t.CHILDREN.length;++i) {
317     t.CHILDREN[i].setState(state);
318   }
319   switch (state)
320     {
321       case OrgNode.STATE_FOLDED:
322         OrgNode.hideElement(t.FOLDER);
323         OrgNode.hideElement(t.DIV);
324       break;
325       case OrgNode.STATE_HEADLINES:
326         OrgNode.hideElement(t.FOLDER);
327         OrgNode.showElement(t.DIV);
328       break;
329       default:
330         OrgNode.showElement(t.FOLDER);
331         OrgNode.showElement(t.DIV);
332     }
333   t.STATE = state;
341  * OrgManager manages OrgNodes.
342  * We don't create anything in the constructor, since the document is not loaded
343  * yet.
344  */
345 var org_html_manager = {
346   // Option
347   MOUSE_HINT: 0,               // Highlight heading under mouse?
348   BODY:null,                   // The container all the contents live in.
349   PLAIN_VIEW: 0,               // We're in plain view mode. On startup:= overview
350   CONTENT_VIEW: 1,             // plain view show structure
351   ALL_VIEW: 2,                 // plain view show all
352   INFO_VIEW: 3,                // We're in info view mode
353   SLIDE_VIEW: 4,               // Slidemode.
354   VIEW: this.CONTENT_VIEW,     // Default view mode (s. setup())
355   LOCAL_TOC: false,            // Create sub indexes (s. setup()): "0", "1" "above", "below" (==1, default)
356   LINK_HOME: 0,                // Link to this.LINK_HOME?
357   LINK_UP: 0,                  // Link to this.LINK_UP?
358   LINKS: "",                   // Prepare the links for later use (see setup),
359   RUN_MAX: 1200,               // Max attempts to scan (results in ~2 minutes)
360   RUN_INTERVAL: 100,           // Interval of scans in milliseconds.
361   HIDE_TOC: false,             // Hide the table of contents.
362   TOC_DEPTH: 0,                // Level to cut the table of contents. No cutting if 0.
363   STARTUP_MESSAGE: 0,          // Show info at startup?
364   POSTAMBLE: null,             // cache the 'postamble' element.
365   // Private
366   BASE_URL: document.URL,      // URL without '#sec-x.y.z'
367   Q_PARAM: "",                 // A query param like `?VIEW=content'
368   ROOT: null,                  // Root element or our OrgNode tree
369   NODE: null,                  // The current node
370   TITLE: null,                 // Save the title for hide/show
371   INNER_TITLE: false,           // The cloned title in sec-1.
372   LOAD_CHECK: null,            // Saves the setTimeout()'s value
373   WINDOW: null,                // A div to display info view mode
374   SECS: new Array(),           // The OrgNode tree
375   REGEX: /(#)(.*$)/,           // identify a section link in toc
376   SID_REGEX: /(^#)(sec-\d+([._]\d+)*$)/, // identify a plain section ID
377   UNTAG_REGEX: /<[^>]+>/i,     // Remove HTML tags
378   ORGTAG_REGEX: /^(.*)<span\s+class=[\'\"]tag[\'\"]>(<span[^>]+>[^<]+<\/span>)+<\/span>/i, // Remove Org tags
379   TRIMMER: /^(\s*)([^\s].*)(\s*)$/, // Trim
380   // FNREF_REGEX: /(fnr\.*)/,     // Footnote ref FIXME: not in use!?!
381   TOC: null,                   // toc.
382   RUNS: 0,                     // Count the scan runs.
383   HISTORY: new Array(50),      // Save navigation history.
384   HIST_INDEX: 0,
385   SKIP_HISTORY: false,         // popHistory() set's this to true.
386   FIXED_TOC: false,            // Leave toc alone if position=[fixed|absolute]?
387   // Commands:
388   CONSOLE: null,               // The div containing the minibuffer.
389   CONSOLE_INPUT: null,
390   CONSOLE_LABEL: null,
391   CONSOLE_OFFSET: "50px",
392   OCCUR: "",                   // The search string.
393   SEARCH_REGEX: "",
394   SEARCH_HL_REGEX: new RegExp('(<span class="org-info-js_search-highlight">)([^<]*?)(<\/span>)', "gi"),
395   MESSAGING: 0,                // Is there a message in the console?
396   MESSAGING_INPLACE: 1,
397   MESSAGING_TOP: 2,
398   // show help:
399   HELPING: false,
400   // console in read mode?
401   READING: false,
402   // if yes, which command caused the readmode?
403   READ_COMMAND: "",
404   // numerical commands are internal commands.
405   READ_COMMAND_NULL: "_0",
406   READ_COMMAND_HTML_LINK: "_1",
407   READ_COMMAND_ORG_LINK: "_2",
408   READ_COMMAND_PLAIN_URL_LINK: "_03",
409   LAST_VIEW_MODE:0,
410   TAB_INDEX: 1000,             // Users could have defined tabindexes!
411   SEARCH_HIGHLIGHT_ON: false,
412   TAGS: {},                    // Tags: {tag:[index,index2...],tag2:[index1,index2...]}
413   SORTED_TAGS: new Array(),    // Sorted tags
414   TAGS_INDEX: null,            // Caches the tags-index screen
415   CLICK_TIMEOUT: null,         // Mousehandling
416   SECNUM_MAP: {},              // Map section numbers to OrgNodes
417   TOC_LINK: null,              // Last link used in TOC
418   HOOKS: { run_hooks: false,   // Hoooks. run_hooks is false until onReady() is run.
419            onShowSection: [],
420            onReady: [] },
422   /**
423    * Setup the OrgHtmlManager for scanning.
424    * Here the timeout func gets set, that tells the wakes up org_html_mager
425    * for the next attempt to scan the document.
426    * All user setable config vars (the documented ones) are checked and adjusted
427    * to a legal value.
428    */
429   setup: function ()
430   {
431     var t = this;
432     if(window['orgInfoHooks']) {
433       for(var i in orgInfoHooks) {
434         t.HOOKS[i] = orgInfoHooks[i];
435       }
436       t.HOOKS['run_hooks'] = false;
437     }
439     if(location.search) { // enable overwriting of settings
440       var sets = location.search.substring(1).split('&');
441       for(var i = 0; i < sets.length; ++i) {
442         var pos = sets[i].indexOf('=');
443         if(-1 != pos) {
444           var v = sets[i].substring(pos+1);
445           var k = sets[i].substring(0, pos);
446           switch(k) {
447             // Explicitely allow overwrites.
448             // Fall through:
449           case 'TOC':
450           case 'TOC_DEPTH':
451           case 'MOUSE_HINT':
452           case 'HELP':
453           case 'VIEW':
454           case 'HIDE_TOC':
455           case 'LOCAL_TOC':
456           case 'OCCUR':
457             t.set(k, decodeURIComponent(v));
458             break;
459           default: break;
460           }
461         }
462       }
463     }
464     t.VIEW  = t.VIEW ? t.VIEW : t.PLAIN_VIEW;
465     t.VIEW_BUTTONS = (t.VIEW_BUTTONS && t.VIEW_BUTTONS != "0") ? true : false;
466     t.STARTUP_MESSAGE = (t.STARTUP_MESSAGE && t.STARTUP_MESSAGE != "0") ? true : false;
467     t.LOCAL_TOC = (t.LOCAL_TOC && t.LOCAL_TOC != "0") ? t.LOCAL_TOC : false;
468     t.HIDE_TOC = (t.TOC && t.TOC != "0") ? false : true;
469     t.INNER_TITLE = (t.INNER_TITLE && t.INNER_TITLE != "title_above") ? false : true;
470     if(t.FIXED_TOC && t.FIXED_TOC != "0") {
471       t.FIXED_TOC = true;
472       t.HIDE_TOC = false;
473     }
474     else t.FIXED_TOC = false;
476     t.LINKS +=
477     ((t.LINK_UP && t.LINK_UP != document.URL) ? '<a href="'+t.LINK_UP+'">Up</a> / ' : "") +
478     ((t.LINK_HOME && t.LINK_HOME != document.URL) ? '<a href="'+t.LINK_HOME+'">HOME</a> / ' : "") +
479     '<a href="javascript:org_html_manager.showHelp();">HELP</a> / ';
481     t.LOAD_CHECK = window.setTimeout("OrgHtmlManagerLoadCheck()", 50);
482   },
484   trim: function(s)
485   {
486     var r = this.TRIMMER.exec(s);
487     return RegExp.$2;
488   },
490   removeTags: function (s)
491   {
492     if(s) {
493       while(s.match(this.UNTAG_REGEX)) {
494         s = s.substr(0, s.indexOf('<')) + s.substr(s.indexOf('>') + 1);
495       }}
496     return s;
497   },
499   /**
500    * Remove tags from headline's inner HTML.
501    * @param s The headline's inner HTML.
502    * @return @c s with all tags stripped.
503    */
504   removeOrgTags: function (s)
505   {
506     if(s.match(this.ORGTAG_REGEX)) {
507       var matches = this.ORGTAG_REGEX.exec(s);
508       return matches[1];
509     }
510     return s;
511   },
513   init: function ()
514   {
515     var t = this;
516     t.RUNS++;
517     t.BODY = document.getElementById("content");
518     if(null == t.BODY) {
519       if(5 > t.RUNS) {
520         t.LOAD_CHECK = window.setTimeout("OrgHtmlManagerLoadCheck()", t.RUN_INTERVAL);
521         return;
522       } else { // be backward compatible
523         t.BODY = document.getElementsByTagName("body")[0];
524       }}
525     if(! t.WINDOW) {
526       t.WINDOW = document.createElement("div");
527       t.WINDOW.style.marginBottom = "40px";
528       t.WINDOW.id = "org-info-js-window";
529     }
530     var theIndex = document.getElementById('table-of-contents');
532     if(! t.initFromTOC()) {
533       if( t.RUNS < t.RUN_MAX ) {
534         t.LOAD_CHECK = window.setTimeout("OrgHtmlManagerLoadCheck()", t.RUN_INTERVAL);
535         return;
536       }
537       // CANCELED: warn if not scanned_all ??
538     }
540     var start_section = 0;
541     var start_section_explicit = false;
543     if("" != location.hash) {
544       t.BASE_URL = t.BASE_URL.substring(0, t.BASE_URL.indexOf('#'));
545       // Search for the start section:
546       for(var i=0;i<t.SECS.length;++i) {
547         if(t.SECS[i].isTargetFor[location.hash]) {
548           start_section = i;
549           start_section_explicit = 1;
550           break;
551         }
552       }
553     }
554     if("" != location.search) {
555       t.Q_PARAM =  t.BASE_URL.substring(t.BASE_URL.indexOf('?'));
556       t.BASE_URL = t.BASE_URL.substring(0, t.BASE_URL.indexOf('?'));
557     }
559     t.convertLinks(); // adjust internal links. BASE_URL has to be stripped.
561     var pa=document.getElementById('postamble');
562     if(pa) t.POSTAMBLE=pa;
563     // Temporary FIX for missing P element if skip:nil
564     var b = t.BODY;
565     var n = b.firstChild;
566     if(3 == n.nodeType) { // IE has no ....
567       var neu = n.cloneNode(true);
568       var p = document.createElement("p");
569       p.id = "text-before-first-headline";
570       p.appendChild(neu);
571       b.replaceChild(p, n);
572     }
573     // END OF temporary FIX.
575     t.CONSOLE = document.createElement("div");
576     t.CONSOLE.innerHTML = '<form action="" style="margin:0px;padding:0px;" onsubmit="org_html_manager.evalReadCommand(); return false;">'
577       +'<table id="org-info-js_console" style="width:100%;margin:0px 0px 0px 0px;border-style:none;" cellpadding="0" cellspacing="0" summary="minibuffer">'
578       +'<tbody><tr><td id="org-info-js_console-icon" style="padding:0px 0px 0px 0px;border-style:none;">&#160;</td><td style="width:100%;vertical-align:middle;padding:0px 0px 0px 0px;border-style:none;">'
579       +'<table style="width:100%;margin:0px 0px 0px 0px;border-style:none;" cellpadding="0" cellspacing="2">'
580       +'<tbody><tr><td id="org-info-js_console-label" style="white-space:nowrap;padding:0px 0px 0px 0px;border-style:none;"></td></tr>'
581       +'<tr><td style="width:100%;vertical-align:middle;padding:0px 0px 0px 0px;border-style:none;">'
582       +'<input type="text" id="org-info-js_console-input" onkeydown="org_html_manager.getKey();"'
583       +' onclick="this.select();" maxlength="150" style="width:100%;padding:0px;margin:0px 0px 0px 0px;border-style:none;"'
584       +' value=""/></td></tr></tbody></table></td><td style="padding:0px 0px 0px 0px;border-style:none;">&#160;</td></tr></tbody></table>'
585       +'</form>';
586     t.CONSOLE.style.position = 'relative';
587     t.CONSOLE.style.marginTop =  "-" + t.CONSOLE_OFFSET;
588     t.CONSOLE.style.top = "-" + t.CONSOLE_OFFSET;
589     t.CONSOLE.style.left = '0px';
590     t.CONSOLE.style.width = '100%';
591     t.CONSOLE.style.height = '40px';
592     t.CONSOLE.style.overflow = 'hidden';
593     t.CONSOLE.style.verticalAlign = 'middle';
594     t.CONSOLE.style.zIndex = '9';
595     t.CONSOLE.style.border = "1px solid #cccccc";
596     t.CONSOLE.id = 'org-info-js_console-container';
598     t.BODY.insertBefore(t.CONSOLE, t.BODY.firstChild);
599     t.MESSAGING = false;
600     t.CONSOLE_LABEL = document.getElementById("org-info-js_console-label");
601     t.CONSOLE_INPUT = document.getElementById("org-info-js_console-input");
602     document.onkeypress=OrgHtmlManagerKeyEvent;
604     if(t.VIEW == t.INFO_VIEW) {
605       t.infoView(start_section);
606       t.showSection(start_section);
607       // For Opera 10 - want to see the title and buttons on (re-)load.
608       window.setTimeout(function(){window.scrollTo(0, 0);}, 100);
609     }
610     else if(t.VIEW == t.SLIDE_VIEW) {
611       t.slideView(start_section);
612       t.showSection(start_section);
613     }
614     else {
615       var v = t.VIEW; // will be changed in t.plainView()!
616       t.plainView(start_section, 1);
617       t.ROOT.DIRTY = true;
618       t.ROOT_STATE = OrgNode.STATE_UNFOLDED;
619       t.toggleGlobaly();
620       if(v > t.PLAIN_VIEW)
621         t.toggleGlobaly();
622       if (v == t.ALL_VIEW)
623         t.toggleGlobaly();
624       if(start_section_explicit) // Unfold the requested section
625         t.showSection(start_section);
626     }
628     if("" != t.OCCUR) {
629       t.CONSOLE_INPUT.value = t.OCCUR;
630       t.READ_COMMAND = 'o';
631       t.evalReadCommand();
632     }
634     if(t.STARTUP_MESSAGE) {
635       t.warn("This page uses org-info.js. Press '?' for more information.", true);
636     }
637     t.HOOKS.run_hooks = true;                    // Unblock all hooks.
638     t.runHooks('onReady', this.NODE);
639   },
642   initFromTOC: function ()
643   {
644     var t = this;
645     // scan the document for sections. We do it by scanning the toc,
646     // so we do what is customized for orgmode (depth of sections in toc).
647     if(t.RUNS == 1 || ! t.ROOT) {
648       var toc = document.getElementById("table-of-contents");
650       if(null != toc) {
651         var heading = null;
652         var i = 0;
653         for(i;heading == null && i < 7;++i)
654           heading = toc.getElementsByTagName("h"+i)[0];
655         heading.onclick = function() {org_html_manager.fold(0);};
656         heading.style.cursor = "pointer";
657         if(t.MOUSE_HINT) {
658           heading.onmouseover = function(){org_html_manager.highlightHeadline(0);};
659           heading.onmouseout = function(){org_html_manager.unhighlightHeadline(0);};
660         }
662         if(t.FIXED_TOC) {
663           heading.setAttribute('onclick', 'org_html_manager.toggleGlobaly();');
664           t.ROOT = new OrgNode( null,
665                                 t.BODY.getElementsByTagName("h1")[0],
666                                 'javascript:org_html_manager.navigateTo(0);',
667                                 0,
668                                 null ); // the root node
669           t.TOC = new OrgNode( toc,
670                                heading,
671                                'javascript:org_html_manager.navigateTo(0);',
672                                i,
673                                null ); // the root node
674           t.NODE = t.ROOT;
675         }
676         else {
677           t.ROOT = new OrgNode( null,
678                                 t.BODY.getElementsByTagName("h1")[0],
679                                 'javascript:org_html_manager.navigateTo(0);',
680                                 0,
681                                 null ); // the root node
682           if(t.HIDE_TOC) {
683             t.TOC = new OrgNode( toc,
684                                  "",
685                                  'javascript:org_html_manager.navigateTo(0);',
686                                  i,
687                                  null );
688             t.NODE = t.ROOT;
689             OrgNode.hideElement(toc);
690           }
691           else {
692             t.TOC = new OrgNode( toc,
693                                  heading,
694                                  'javascript:org_html_manager.navigateTo(0);',
695                                  i,
696                                  t.ROOT ); // the root node
697             t.TOC.IDX = 0;
698             t.NODE = t.TOC;
699             t.SECS.push(t.TOC);
700           }
701         }
702         if(t.TOC) t.TOC.FOLDER = document.getElementById("text-table-of-contents");
703       }
704       else
705         return false;
706     }
708     var theIndex = t.TOC.FOLDER.getElementsByTagName("ul")[0]; // toc
710     // Could we scan the document all the way down?
711     // Return false if not.
712     if(! t.ulToOutlines(theIndex))
713       return false;
715     var fn = document.getElementById('footnotes');
716     if(fn) {
717       var fnheading = null;
718       var c = fn.childNodes;
719       for(var i=0;i<c.length;++i) {
720         if("footnotes"== c[i].className) {
721           fnheading=c[i];
722           break;}}
723       var sec = t.SECS.length;
724       fnheading.onclick = function() {org_html_manager.fold("" + sec);};
725       fnheading.style.cursor = "pointer";
726       if(t.MOUSE_HINT) {
727         fnheading.onmouseover = function() {org_html_manager.highlightHeadline("" + sec);};
728         fnheading.onmouseout = function() {org_html_manager.unhighlightHeadline("" + sec);};
729       }
730       var link = 'javascript:org_html_manager.navigateTo(' + sec + ')';
731       var fnsec= new OrgNode ( fn, fnheading, link, 1, t.ROOT, "footnotes");
732       t.SECS.push(fnsec);
733     }
735     if(t.TOC_DEPTH) {
736       t.cutToc(theIndex, 1);
737     }
739     // Move the title into the first visible section.
740     // TODO: show title above everything if FIXED_TOC !!!
741     t.TITLE = t.BODY.getElementsByTagName("h1")[0];
742     if(t.INNER_TITLE && !t.FIXED_TOC && t.VIEW != t.SLIDE_VIEW) {
743       t.INNER_TITLE = t.TITLE.cloneNode(true);
744       /* TODO: this is still based on wrong behaviour of browsers (same id for two elements)
745        * But this here does not work:
746        * t.INNER_TITLE.style = t.TITLE.style;
747        * t.INNER_TITLE.id = "org-info-js-inner-title";
748        */
749       t.SECS[0].DIV.insertBefore(t.INNER_TITLE, t.SECS[0].DIV.firstChild);
750       OrgNode.hideElement(t.TITLE);
751     }
753     // Create all the navigation links:
754     t.build();
755     t.NODE = t.SECS[0];
757     t.BODY.insertBefore(t.WINDOW, t.NODE.DIV);
759     return true;
760   },
762   /**
763    * Used by OrgHtmlManager::initFromToc
764    */
765   ulToOutlines: function (ul)
766   {
767     if(ul.hasChildNodes() && ! ul.scanned_for_org) {
768       for(var i=0; i<ul.childNodes.length; ++i) {
769         if(false == this.liToOutlines(ul.childNodes[i])) {
770           return false;
771         }
772       }
773       ul.scanned_for_org = 1;
774     }
775     return true;
776   },
778   /**
779    * Used by OrgHtmlManager::initFromToc
780    */
781   liToOutlines: function (li)
782   {
783     if(! li.scanned_for_org) {
784       for(var i=0; i<li.childNodes.length; ++i) {
785         var c = li.childNodes[i];
786         switch (c.nodeName) {
787         case "A":
788           var newHref = this.mkNodeFromHref(c);
789           if(false == newHref) {
790             return false;
791           }
792           else {
793             c.href = newHref;
794             c.tabIndex = this.TAB_INDEX;
795             c.onfocus=function(){org_html_manager.TOC_LINK=this;void 0;};
796             if(null==this.TOC_LINK) this.TOC_LINK=c;
797             this.TAB_INDEX++;
798           }
799           break;
800         case "UL":
801           return this.ulToOutlines(c);
802           break;
803         }
804       }
805       li.scanned_for_org = 1;
806     }
807     return true;
808   },
810   /**
811    * Used by OrgHtmlManager::initFromToc
812    */
813   cutToc: function (ul, cur_depth)
814   {
815     cur_depth++;
816     if(ul.hasChildNodes()) {
817       for(var i=0; i < ul.childNodes.length; ++i) {
818         var li = ul.childNodes[i];
819         for(var j=0; j < li.childNodes.length; ++j) {
820           var c = li.childNodes[j];
821           if(c.nodeName == "UL") {
822             if(cur_depth > this.TOC_DEPTH)
823               li.removeChild(c);
824             else
825               this.cutToc(c, cur_depth); }}}}
826   },
828   /**
829    * Used by OrgHtmlManager::liToOutlines
830    * @param anchor <a...> element in the TOC, that links to a section.
831    */
832   mkNodeFromHref: function (anchor)
833   {
834     s = anchor.href;
835     if(s.match(this.REGEX)) {
836       var matches = this.REGEX.exec(s);
837       var id = matches[2];
838       var h = document.getElementById(id);
839       // This heading could be null, if the document is not yet entirely loaded.
840       // So we stop scanning and set the timeout func in caller.
841       // We could even count the <ul> and <li> elements above to speed up the next
842       // scan.
843       if(null == h) {
844         return(false);
845       }
846       var div = h.parentNode;
847       var sec = this.SECS.length;
848       var depth = div.className.substr(8);
849       h.onclick = function() {org_html_manager.fold("" + sec);};
850       h.style.cursor = "pointer";
851       if(this.MOUSE_HINT) {
852         h.onmouseover = function() {org_html_manager.highlightHeadline("" + sec);};
853         h.onmouseout = function() {org_html_manager.unhighlightHeadline("" + sec);};
854       }
855       var link = 'javascript:org_html_manager.navigateTo(' + sec + ')';
856       if(depth > this.NODE.DEPTH) {
857         this.NODE = new OrgNode ( div, h, link, depth, this.NODE, id, anchor);
858       }
859       else if (depth == 2) {
860         this.NODE = new OrgNode ( div, h, link, depth, this.ROOT, id, anchor);
861       }
862       else {
863         var p = this.NODE;
864         while(p.DEPTH > depth) p = p.PARENT;
865         this.NODE = new OrgNode ( div, h, link, depth, p.PARENT, id, anchor);
866       }
867       this.SECS.push(this.NODE);
868       // Prepare the tags-index:
869       var spans = h.getElementsByTagName("span");
870       if(spans) {
871         for(var i = 0; i < spans.length; ++i) {
872           if(spans[i].className == "tag") {
873             var tags = spans[i].innerHTML.split("&nbsp;");
874             for(var j = 0; j < tags.length; ++j) {
875               var t = this.removeTags(tags[j]);
876               if(! this.TAGS[t]) {
877                 this.TAGS[t] = new Array();
878                 this.SORTED_TAGS.push(t);
879               }
880               this.TAGS[t].push(sec);
881             }
882           }
883           else if(spans[i].className.match(this.SECNUM_REGEX)) {
884             this.SECNUM_MAP[this.trim(spans[i].innerHTML)] = this.NODE;
885           }
886         }
887       }
888       this.NODE.hide();
889       return (link);
890     }
891     // return the link as it was, if no section link:
892     return (s);
893   },
895   /**
896    * Creates all the navigation links for this.SECS.
897    * This is called from initFromStructure() and initFromToc() as well.
898    *
899    * @todo Apply style classes to the generated links.
900    */
901   build: function ()
902   {
903     var index_name =  this.TITLE.innerHTML;
904     var min_subindex_sec = 0;
906     for(var i = 0; i < this.SECS.length; ++i)
907     {
908       this.SECS[i].IDX = i;
909       var html = '<table class="org-info-js_info-navigation" width="100%" border="0" style="border-bottom:1px solid black;">'
910         +'<tr><td colspan="3" style="text-align:left;border-style:none;vertical-align:bottom;">'
911         +'<span style="float:left;display:inline;text-align:left;">'
912         +'Top: <a accesskey="t" href="javascript:org_html_manager.navigateTo(0);">'+index_name+'</a></span>'
913         +'<span style="float:right;display:inline;text-align:right;font-size:70%;">'
914         + this.LINKS
915         +'<a accesskey="m" href="javascript:org_html_manager.toggleView('+i+');">toggle view</a></span>'
916         +'</td></tr><tr><td style="text-align:left;border-style:none;vertical-align:bottom;width:22%">';
918       if(i>0)
919         html += '<a accesskey="p" href="'+this.SECS[i-1].L
920         +'" title="Go to: '+this.removeTags(this.SECS[i-1].HEADING.innerHTML)+'">Previous</a> | ';
921       else
922         html += 'Previous | ';
924       if(i < this.SECS.length - 1)
925         html += '<a accesskey="n" href="'+this.SECS[i+1].L
926         +'" title="Go to: '+this.removeTags(this.SECS[i+1].HEADING.innerHTML)+'">Next</a>';
927       else
928         html += 'Next';
930       html += '</td><td style="text-align:center;vertical-align:bottom;border-style:none;width:56%;">';
932       if(i>0 && this.SECS[i].PARENT.PARENT) // != this.ROOT)
933         html += '<a href="'+this.SECS[i].PARENT.L
934         +'" title="Go to: '+this.removeTags(this.SECS[i].PARENT.HEADING.innerHTML)+'">'
935         +'<span style="font-variant:small-caps;font-style:italic;">'
936         +this.SECS[i].PARENT.HEADING.innerHTML+'</span></a>';
937       else
938         html += '<span style="font-variant:small-caps;font-style:italic;">'+this.SECS[i].HEADING.innerHTML+'</span>';
940       // Right:
941       html += '</td><td style="text-align:right;vertical-align:bottom;border-style:none;width:22%">';
942       html += (i + 1) +'</td></tr></table>';
944       // buttons:
945       this.SECS[i].BUTTONS = document.createElement("div");
946       this.SECS[i].BUTTONS.innerHTML = '<div class="org-info-js_header-navigation" style="display:inline;float:right;text-align:right;font-size:70%;font-weight:normal;">'
947         + this.LINKS
948         + '<a accesskey="m" href="javascript:org_html_manager.toggleView('+i+');">toggle view</a></div>';
949       if(this.SECS[i].FOLDER)
950         // this.SECS[i].HEADING.appendChild(this.SECS[i].BUTTONS);
951         this.SECS[i].DIV.insertBefore(this.SECS[i].BUTTONS, this.SECS[i].HEADING); //div.firstChild.nextSibling);
952       else if(this.SECS[i].DIV.hasChildNodes()) {
953         this.SECS[i].DIV.insertBefore(this.SECS[i].BUTTONS, this.SECS[i].DIV.firstChild);
954       }
955       if(!this.VIEW_BUTTONS) OrgNode.hideElement(this.SECS[i].BUTTONS);
956       this.SECS[i].NAV = html;
958       // subindex for sections containing subsections:
959       if(0 < this.SECS[i].CHILDREN.length && this.LOCAL_TOC)
960       {
961         var navi2 = document.createElement("div");
962         navi2.className="org-info-js_local-toc";
963         html = 'Contents:<br /><ul>';
964         for(var k=0; k < this.SECS[i].CHILDREN.length; ++k) {
965           html += '<li><a href="'
966             +this.SECS[i].CHILDREN[k].L+'">'
967             +this.removeTags(this.removeOrgTags(this.SECS[i].CHILDREN[k].HEADING.innerHTML))+'</a></li>';
968         }
969         html += '</ul>';
970         navi2.innerHTML = html;
971         if("above" == this.LOCAL_TOC) {
972           if(this.SECS[i].FOLDER)
973             this.SECS[i].FOLDER.insertBefore(navi2, this.SECS[i].FOLDER.firstChild);
974           else
975             this.SECS[i].DIV.insertBefore(
976               navi2, this.SECS[i].DIV.getElementsByTagName("h"+this.SECS[i].DEPTH)[0].nextSibling);
977         } else {
978           if(this.SECS[i].FOLDER)
979             this.SECS[i].FOLDER.appendChild(navi2);
980           else
981             this.SECS[i].DIV.appendChild(navi2);
982         }
983       }
984     }
985     // Setup the Tags for sorted output:
986     this.SORTED_TAGS.sort();
987   },
989   /**
990    * Execute arbitrary JavaScript code. Used for configuration.
991    */
992   set: function (eval_key, eval_val)
993   {
994     if("VIEW" == eval_key) {
995       var pos = eval_val.indexOf('_');
996       if(-1 != pos) {
997         this.INNER_TITLE=eval_val.substr(pos + 1); // might be info_title_above now.
998         eval_val=eval_val.substr(0, pos);
999       }
1000       var overview = this.PLAIN_VIEW;
1001       var content = this.CONTENT_VIEW;
1002       var showall = this.ALL_VIEW;
1003       var info = this.INFO_VIEW;
1004       var info_title_above = this.INFO_VIEW;
1005       var slide = this.SLIDE_VIEW;
1006       eval("this."+eval_key+"="+eval_val+";");
1007     }
1008     else if("HELP" == eval_key)
1009       eval("this.STARTUP_MESSAGE="+eval_val+";");
1010     else {
1011       if(eval_val)
1012         eval("this."+eval_key+"='"+eval_val+"';");
1013       else
1014         eval("this."+eval_key+"=0;");
1015     }
1016   },
1018   convertLinks: function ()
1019   {
1020     var i = (this.HIDE_TOC ? 0 : 1);
1021     var j;
1022     var foot_sec = this.SECS.length - 1;
1023     // for(i; i < this.SECS.length; ++i) {
1024     var links = document.getElementsByTagName("a"); // must be document!
1025     for(j=0; j<links.length; ++j) {
1026       var href = links[j].href.replace(this.BASE_URL, '');
1027       // could use quicksort like search here:
1028       for(var k = 0; k < this.SECS.length; ++k) {
1029         if(this.SECS[k].isTargetFor[href]) {
1030           links[j].href="javascript:org_html_manager.navigateTo("+k+")";
1031           break;
1032         }}}},
1037   /**
1038    * Show a certain section.
1039    *
1040    * NOTE: Replacing window.location might change the view mode, if the mode was
1041    * requested using an URL like "?VIEW=...&param=value" and the mode was
1042    * different from the one specified in the <head> section. The solution is, to
1043    * track the query parameter until the user changes the view mode for the
1044    * first time.
1045    *
1046    * You can avoid the URL-replacing by setting @c org_html_manager.NODE to the
1047    * same node you want to display before calling this function. This
1048    * <u>should</u> be the case on startup.
1049    *
1050    * @param sec   The section to show. This is the index
1051    *              in @c SECS.
1052    */
1053   showSection: function (sec)
1054   {
1055     var t = this;
1056     var section = parseInt(sec);
1057     var last_node = t.NODE;
1058     var hook = 'onShowSection';
1059     if(t.HIDE_TOC && t.NODE == t.TOC && !t.FIXED_TOC) {
1060       OrgNode.hideElement(t.TOC.DIV);
1061       if(t.PLAIN_VIEW == t.VIEW) {
1062         t.ROOT.showAllChildren();
1063         for(var i=0;i<t.ROOT.CHILDREN.length;++i) {
1064           t.ROOT.CHILDREN[i].STATE = OrgNode.STATE_UNFOLDED;
1065           t.ROOT.CHILDREN[i].fold();
1066         }
1067       }
1068     }
1069     if('?/toc/?' != sec && null != t.TOC_LINK) t.TOC_LINK.blur();
1070     if('?/toc/?' == sec || (!isNaN(section) && t.SECS[section])) {
1071       if('?/toc/?' == sec && t.HIDE_TOC)
1072         {
1073           hook = 'onShowToc';
1074           t.NODE = t.TOC;
1075           t.ROOT.hideAllChildren();
1076           if(t.INFO_VIEW == t.VIEW)
1077             t.WINDOW.innerHTML = t.NODE.DIV.innerHTML;
1078           else
1079             t.NODE.setState(OrgNode.STATE_UNFOLDED);
1080           window.scrollTo(0, 0);
1081         }
1082       else
1083         {
1084           t.NODE = t.SECS[section];
1085           if(t.SLIDE_VIEW == t.VIEW || t.INFO_VIEW == t.VIEW) {
1086             OrgNode.hideElement(t.NODE.BUTTONS);
1087             t.NODE.setState(OrgNode.STATE_UNFOLDED);
1088             for(var i=0;i<t.NODE.CHILDREN.length; ++i)
1089               t.NODE.CHILDREN[i].hide();
1090             if(t.SLIDE_VIEW == t.VIEW) t.WINDOW.innerHTML = t.NODE.DIV.innerHTML;
1091             else t.WINDOW.innerHTML = t.NODE.NAV + t.NODE.DIV.innerHTML;
1092             t.NODE.hide();
1093             // Hide the body, to avoid jumping page when replacing the
1094             // location. Unfortunatly we cannot do this with a fixed TOC,
1095             // because the fixed TOC will jump then, causing links towards the
1096             // bottom to disapear again.
1097             if(! t.FIXED_TOC) OrgNode.hideElement(document.body);
1098             if(last_node.IDX != t.NODE.IDX)
1099               if('?/toc/?' != sec) window.location.replace(t.BASE_URL + t.Q_PARAM + t.getDefaultTarget());
1100             if(! t.FIXED_TOC) OrgNode.showElement(document.body);
1101           }
1102           else {
1103             if(! t.VIEW_BUTTONS) OrgNode.hideElement(last_node.BUTTONS);
1104             OrgNode.showElement(t.NODE.BUTTONS);
1105             t.NODE.setState(OrgNode.UNFOLDED);
1106             t.NODE.show();
1107             if(last_node.IDX != t.NODE.IDX)
1108               window.location.replace(t.BASE_URL + t.Q_PARAM + t.getDefaultTarget());
1109             if(t.NODE.IDX == 0) window.scrollTo(0, 0);
1110             else t.NODE.DIV.scrollIntoView(true);
1111           }
1112         }
1113     }
1114     last_node.setLinkClass();
1115     t.NODE.setLinkClass(true);
1116     t.runHooks(hook, {'last': last_node, 'current': t.NODE});
1117   },
1119   plainView: function (sec, skip_show_section)
1120   {
1121     var t = this;
1122     document.onclick = null;
1123     document.ondblclick = null;
1124     t.VIEW = t.PLAIN_VIEW;
1125     OrgNode.hideElement(t.WINDOW);
1126     if(t.INNER_TITLE) OrgNode.hideElement(t.INNER_TITLE);
1127     OrgNode.showElement(t.TITLE);
1128     // For Opera and accesskeys we have to remove the navigation here to get it
1129     // working when toggeling back to info view again:
1130     if(t.WINDOW.firstChild) // might not be set after init
1131       t.WINDOW.removeChild(t.WINDOW.firstChild);
1132     t.ROOT.showAllChildren();
1133     for(var i=0;i<t.ROOT.CHILDREN.length;++i) {
1134       t.ROOT.CHILDREN[i].STATE = OrgNode.STATE_UNFOLDED;
1135       t.ROOT.CHILDREN[i].fold();
1136     }
1137     if(!skip_show_section)
1138       t.showSection(sec);
1139     if(t.POSTAMBLE) OrgNode.showElement(t.POSTAMBLE);
1140     if(t.NODE.IDX == 0) window.scrollTo(0, 0);
1141     else t.NODE.DIV.scrollIntoView(true);
1142   },
1144   infoView: function (sec, skip_show_section)
1145   {
1146     var t = this;
1147     document.onclick = null;
1148     document.ondblclick = null;
1149     t.VIEW = t.INFO_VIEW;
1150     t.unhighlightHeadline(t.NODE.IDX);
1151     if(t.INNER_TITLE && !t.FIXED_TOC) {
1152       OrgNode.showElement(t.INNER_TITLE);
1153       OrgNode.hideElement(t.TITLE);
1154     }
1155     OrgNode.showElement(t.WINDOW);
1156     t.ROOT.hideAllChildren();
1157     if(t.TOC && !t.FIXED_TOC) OrgNode.hideElement(t.TOC.DIV);
1158     if(t.POSTAMBLE) OrgNode.showElement(t.POSTAMBLE);
1159     if(!skip_show_section)
1160       t.showSection(sec);
1161     window.scrollTo(0, 0);
1162   },
1164   slideView: function (sec, skip_show_section)
1165   {
1166     var t = this;
1167     t.VIEW = t.SLIDE_VIEW;
1168     t.unhighlightHeadline(t.NODE.IDX);
1169     OrgNode.hideElement(t.TITLE);
1170     if(t.INNER_TITLE) OrgNode.hideElement(t.INNER_TITLE);
1171     if(t.TOC) OrgNode.hideElement(t.TOC.DIV);
1172     OrgNode.showElement(t.TITLE);
1173     OrgNode.showElement(t.WINDOW);
1174     t.ROOT.hideAllChildren();
1175     OrgNode.hideElement(t.TOC.DIV);
1176     if(t.POSTAMBLE) OrgNode.hideElement(t.POSTAMBLE);
1177     t.adjustSlide(sec);
1178     if(!skip_show_section) t.showSection(sec);
1179   },
1181   // hide/show List-items. show > 0: show next listitem, < 0 hide last listitem. null means new section.
1182   adjustSlide: function(sec, show)
1183   {
1184     var nextForward = true;
1185     var nextBack = true;
1186     var next = false;
1187     if(sec > this.NODE.IDX) next = true;
1188     if(null == show) next = true;
1190     if(next) {
1191       for(var n=this.SECS[sec].FOLDER.firstChild;null != n;n=n.nextSibling){
1192         if("UL" == n.nodeName){
1193           var lis=n.getElementsByTagName("li");
1194           for(var i=1;i<lis.length;++i) {
1195             var l = lis[i];
1196             OrgNode.hideElement(l); nextForward = false;
1197           }
1198         }
1199       }
1200     }
1201     else {
1202       var lists = this.WINDOW.getElementsByTagName("ul");
1203       for(var n=0; n < lists.length; ++n){
1204         var lis=lists[n].getElementsByTagName("li");
1205         for(var i=1;i<lis.length;++i) {
1206           var l = lis[i];
1207           if(show > 0){
1208             if(OrgNode.isHidden(l)) {
1209               OrgNode.unhideElement(l);
1210               if(i< (lis.length-1)) nextForward=false;
1211               if(0<i) nextBack=false;
1212               break;
1213             }
1214           }
1215           else { // show < 0
1216             if(!OrgNode.isHidden(l)) {
1217               if(1<i) {
1218                 nextBack=false;
1219                 OrgNode.hideElement(lis[i - 1]);
1220                 break;
1221               }
1222             }
1223           }
1224         }
1225       }
1226     }
1228     if(nextForward)
1229       document.onclick = function(){org_html_manager.scheduleClick("org_html_manager.nextSection(org_html_manager.NODE.IDX + 1)");};
1230     else
1231       document.onclick = function(){org_html_manager.scheduleClick("org_html_manager.adjustSlide(org_html_manager.NODE.IDX, +1)");};
1232     if(nextBack)
1233       document.ondblclick = function(){org_html_manager.scheduleClick("org_html_manager.previousSection()");};
1234     else
1235       document.ondblclick = function(){org_html_manager.scheduleClick("org_html_manager.adjustSlide("+this.NODE.IDX+", -1)");};
1236   },
1238   /**
1239    * Toggle the view mode.
1240    * This also resets the <code>Q_PARAM</code> to an empty string.
1241    * @param sec The section index to show.
1242    */
1243   toggleView: function (sec)
1244   {
1245     var t = this;
1246     t.Q_PARAM="";
1247     t.removeWarning();
1248     if(t.VIEW == t.INFO_VIEW)
1249       t.plainView(sec);
1250     else
1251       t.infoView(sec);
1252   },
1254   fold: function (sec)
1255   {
1256     var t = this;
1257     t.removeWarning();
1258     var section = parseInt(sec);
1259     t.SECS[section].fold();
1260     if(! t.VIEW_BUTTONS) OrgNode.hideElement(t.NODE.BUTTONS);
1261     t.NODE = t.SECS[section];
1262     OrgNode.showElement(t.NODE.BUTTONS);
1263   },
1265   toggleGlobaly: function ()
1266   {
1267     var t = this;
1268     if(t.ROOT.DIRTY) {
1269       t.ROOT.STATE = OrgNode.STATE_UNFOLDED;
1270     }
1272     if(OrgNode.STATE_UNFOLDED == t.ROOT.STATE) {
1273       for(var i=0;i<t.ROOT.CHILDREN.length;++i) {
1274         // Pretend they are unfolded. They will toggle to FOLDED then:
1275         t.ROOT.CHILDREN[i].STATE = OrgNode.STATE_UNFOLDED;
1276         t.ROOT.CHILDREN[i].fold(true);
1277       }
1278       t.ROOT.STATE = OrgNode.STATE_UNFOLDED;
1279       t.ROOT.STATE = OrgNode.STATE_FOLDED;
1280     }
1281     else if(OrgNode.STATE_FOLDED == t.ROOT.STATE) {
1282       for(var i=0;i<t.ROOT.CHILDREN.length;++i)
1283         t.ROOT.CHILDREN[i].fold(true);
1284       t.ROOT.STATE = OrgNode.STATE_HEADLINES;
1285     }
1286     else {
1287       for(var i=0;i<t.ROOT.CHILDREN.length;++i)
1288         t.ROOT.CHILDREN[i].fold();
1289       t.ROOT.STATE = OrgNode.STATE_UNFOLDED;
1290     }
1292     // All this sets ROOT dirty again. So clean it:
1293     t.ROOT.DIRTY = false;
1294   },
1298   executeClick: function(func)
1299   {
1300     var t = this;
1301     if     (t.READING)   { t.endRead(); t.hideConsole(); }
1302     else if(t.MESSAGING) { t.removeWarning(); }
1303     eval(func);
1304     if(null != t.CLICK_TIMEOUT) t.CLICK_TIMEOUT = null;
1305   },
1307   scheduleClick: function(func, when)
1308   {
1309     if(null == when) when = 250;
1310     if(null == this.CLICK_TIMEOUT) {
1311       this.CLICK_TIMEOUT = window.setTimeout("org_html_manager.executeClick(" + func + ")", when);
1312     }
1313     else {
1314       window.clearTimeout(this.CLICK_TIMEOUT);
1315       this.CLICK_TIMEOUT = null;
1316     }
1317   },
1321   nextSection: function()
1322   {
1323     var T = this;
1324     var i = T.NODE.IDX + 1;
1325     if(i<T.SECS.length) T.navigateTo(i);
1326     else T.warn("Already last section.");
1327   },
1329   previousSection: function()
1330   {
1331     var t = this;
1332     var i = t.NODE.IDX;
1333     if(i>0) t.navigateTo(i-1);
1334     else t.warn("Already first section.");
1335   },
1338   /**
1339    * This one is just here, because we might want to push different than
1340    * navigational commands on the history in the future. Is this true?
1341    */
1342   navigateTo: function (sec)
1343   {
1344     var t = this;
1345     if     (t.READING)   { t.endRead(); t.hideConsole(); }
1346     else if(t.MESSAGING) { t.removeWarning(); }
1347     if(t.VIEW == t.SLIDE_VIEW) t.adjustSlide(sec);
1348     t.pushHistory(sec, t.NODE.IDX);
1349     t.showSection(sec);
1350   },
1353   /**
1354    *  All undoable navigation commands should push the oposit here
1355    */
1356   pushHistory: function (command, undo)
1357   {
1358     var t = this;
1359     if(! t.SKIP_HISTORY) {
1360       t.HISTORY[t.HIST_INDEX] = new Array(command, undo);
1361       t.HIST_INDEX = (t.HIST_INDEX + 1) % 50;
1362     }
1363     t.SKIP_HISTORY = false;
1364     t.CONSOLE_INPUT.value = "";
1365   },
1367  /**
1368   * only 'b' and 'B' trigger this one
1369   */
1370   popHistory: function (foreward)
1371   {
1372     var t = this;
1373     if(foreward) {
1374       if(t.HISTORY[t.HIST_INDEX]) {
1375         var s = parseInt(t.HISTORY[t.HIST_INDEX][0]);
1376         if(! isNaN(s) || '?/toc/?' == t.HISTORY[t.HIST_INDEX][0]) {
1377           t.showSection(t.HISTORY[t.HIST_INDEX][0]);
1378           t.CONSOLE_INPUT.value = "";
1379         }
1380         else {
1381           t.SKIP_HISTORY = true;
1382           t.CONSOLE_INPUT.value = t.HISTORY[t.HIST_INDEX][0];
1383           t.getKey();
1384         }
1385         t.HIST_INDEX = (t.HIST_INDEX + 1) % 50;
1386         t.HBO=0;
1387       }
1388       else if(t.HFO && history.length) history.forward();
1389       else {
1390         t.HFO=1;
1391         t.warn("History: No where to foreward go from here. Any key and `B' to move to next file in history.");
1392       }
1393     } else {
1394       if(t.HISTORY[t.HIST_INDEX - 1]) {
1395         t.HIST_INDEX = t.HIST_INDEX == 0 ? 49 : t.HIST_INDEX - 1;
1396         var s = parseInt(t.HISTORY[t.HIST_INDEX][1]);
1397         if(! isNaN(s) || '?/toc/?' == t.HISTORY[t.HIST_INDEX][1]) {
1398           t.showSection(t.HISTORY[t.HIST_INDEX][1]);
1399           t.CONSOLE_INPUT.value = "";
1400         }
1401         else {
1402           t.SKIP_HISTORY = true;
1403           t.CONSOLE_INPUT.value = t.HISTORY[t.HIST_INDEX][1];
1404           t.getKey();
1405         }
1406         t.HFO=0;
1407       }
1408       else if(t.HBO && history.length) history.back();
1409       else {
1410         t.HBO=1;
1411         t.warn("History: No where to back go from here. Any key and `b' to move to previous file in history.");
1412       }
1413     }
1414   },
1420   warn: function (what, harmless, value)
1421   {
1422     var t = this;
1423     if(null == value) value = "";
1424     t.CONSOLE_INPUT.value = value;
1425     if(! harmless) t.CONSOLE_LABEL.style.color = "red";
1426     t.CONSOLE_LABEL.innerHTML = "<span style='float:left;'>"+what +"</span>"+
1427     "<span style='float:right;color:#aaaaaa;font-weight:normal;'>(press any key to proceed)</span>";
1428     t.showConsole();
1429     // wait until keyup was processed:
1430     window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.value=value;}, 50);
1431   },
1433   startRead: function (command, label, value, shortcuts)
1434   {
1435     var t = this;
1436     if(null == value) value = "";
1437     if(null == shortcuts) shortcuts = "";
1438     t.READ_COMMAND = command;
1439     t.READING = true;
1440     t.CONSOLE_LABEL.innerHTML = "<span style='float:left;'>"+label+"</span>"+
1441     "<span style='float:right;color:#aaaaaa;font-weight:normal;'>("+shortcuts+"RET to close)</span>";
1442     t.showConsole();
1443     document.onkeypress=null;
1444     t.CONSOLE_INPUT.focus();
1445     t.CONSOLE_INPUT.onblur = function() {org_html_manager.CONSOLE_INPUT.focus();};
1446     // wait until keyup was processed:
1447     window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.value=value;}, 50);
1448   },
1450   endRead: function (command, label)
1451   {
1452     var t = this;
1453     t.READING = false;
1454     t.READ_COMMAND = "";
1455     t.CONSOLE_INPUT.onblur = null;
1456     t.CONSOLE_INPUT.blur();
1457     document.onkeypress=OrgHtmlManagerKeyEvent;
1458   },
1460   removeWarning: function()
1461   {
1462     var t = this;
1463     t.CONSOLE_LABEL.style.color = "#333333";
1464     t.hideConsole();
1465   },
1467   showConsole: function()
1468   {
1469     var t = this;
1470     if(!t.MESSAGING) {
1471       if(t.VIEW == t.PLAIN_VIEW) {
1472         // Maybe clone the CONSOLE?
1473         t.BODY.removeChild(t.BODY.firstChild);
1474         t.NODE.DIV.insertBefore(t.CONSOLE, t.NODE.DIV.firstChild);
1475         t.NODE.DIV.scrollIntoView(true);
1476         t.MESSAGING = t.MESSAGING_INPLACE;
1477       } else {
1478         t.MESSAGING = t.MESSAGING_TOP;
1479         window.scrollTo(0, 0);
1480       }
1481       t.CONSOLE.style.marginTop = '0px';
1482       t.CONSOLE.style.top = '0px';
1483     }
1484   },
1486   hideConsole: function()
1487   {
1488     var t = this;
1489     if(t.MESSAGING) {
1490       t.CONSOLE.style.marginTop = "-" + t.CONSOLE_OFFSET;
1491       t.CONSOLE.style.top = "-" + t.CONSOLE_OFFSET;
1492       t.CONSOLE_LABEL.innerHTML = "";
1493       t.CONSOLE_INPUT.value = "";
1494       if(t.MESSAGING_INPLACE == t.MESSAGING) {
1495         t.NODE.DIV.removeChild(t.NODE.DIV.firstChild);
1496         t.BODY.insertBefore(t.CONSOLE, t.BODY.firstChild);
1497         if(t.NODE.IDX != 0) t.NODE.DIV.scrollIntoView();
1498       }
1499       t.MESSAGING = false;
1500     }
1501   },
1507   /**
1508    * All commands that add something to the history should return.
1509    */
1510   getKey: function ()
1511   {
1512     var t = this;
1513     var s = t.CONSOLE_INPUT.value;
1514     // return, if s is empty:
1515     if(0 == s.length) {
1516       if(t.HELPING) { t.showHelp(); return; }
1517       if(t.MESSAGING && !t.READING) t.removeWarning();
1518         return;
1519     }
1521     // the easiest is to just drop everything and clean the console.
1522     // User has to retype again.
1523     if(t.MESSAGING && !t.READING) {
1524       t.removeWarning();
1525       return;
1526     }
1527     else if(t.HELPING) {
1528       t.showHelp();
1529       t.CONSOLE_INPUT.value = "";
1530       return;
1531     }
1532     else if(t.READING) {
1533       return;
1534     }
1536     t.CONSOLE_INPUT.value = "";
1537     t.CONSOLE_INPUT.blur();
1539     // Always remove TOC from history, if HIDE_TOC
1540     if(t.HIDE_TOC && t.TOC == t.NODE && "v" != s && "V" != s && "\t" != s) {
1541       s = "b";
1542     }
1543     else if("\t" == s) {
1544       return true;
1545     }
1546     else {
1547       s = t.trim(s);
1548     }
1550     // SINGLE KEY COMMANDS GO HERE //
1552     if (1 == s.length)    // one char wide commands
1553       {
1554         if ('b' == s) {
1555           t.popHistory();
1556         }
1557         else if ('B' == s) {
1558           t.popHistory(true);
1559         }
1560         else if ('c' == s) {
1561           t.removeSearchHighlight();
1562           if(t.VIEW == t.INFO_VIEW || t.VIEW == t.SLIDE_VIEW) {
1563             // redisplay in info view mode:
1564             t.showSection(t.NODE.IDX);
1565           }
1566         }
1567         else if ('i' == s) {
1568           if(! t.FIXED_TOC) {
1569             if (t.HIDE_TOC) t.navigateTo('?/toc/?');
1570             // No cloning here:
1571             else if(0 != t.NODE.IDX) t.navigateTo(0);
1572           }
1573           if(null != t.TOC_LINK) t.TOC_LINK.focus();
1574         }
1575         else if ('m' == s) {
1576           t.toggleView(t.NODE.IDX);
1577           return;
1578         }
1579         else if ('x' == s) {
1580           t.slideView(t.NODE.IDX);
1581         }
1582         else if ('n' == s) {
1583           if(t.NODE.STATE == OrgNode.STATE_FOLDED && t.VIEW == t.PLAIN_VIEW) {
1584             t.showSection(t.NODE.IDX);
1585           }
1586           else if(t.NODE.IDX < t.SECS.length - 1) {
1587             t.navigateTo(t.NODE.IDX + 1);
1588           } else {
1589             t.warn("Already last section.");
1590             return;                          // rely on what happends if messaging
1591           }
1592         }
1593         else if ('N' == s) {
1594           if(t.NODE.IDX < t.SECS.length - 1) {
1595             var d = t.NODE.DEPTH;
1596             var idx = t.NODE.IDX + 1;
1597             while(idx < t.SECS.length - 1 && t.SECS[idx].DEPTH >= d) {
1598               if(t.SECS[idx].DEPTH == d) {
1599                 t.navigateTo(idx);
1600                 return;
1601               }
1602               ++idx;
1603             }
1604           }
1605           t.warn("No next sibling.");
1606           return;                          // rely on what happends if messaging
1607         }
1608         else if ('p' == s) {
1609           if(t.NODE.IDX > 0) {
1610             t.navigateTo(t.NODE.IDX - 1);
1611           } else {
1612             t.warn("Already first section.");
1613             return;                          // rely on what happends if messaging
1614           }
1615         }
1616         else if ('P' == s) {
1617           if(t.NODE.IDX > 0) {
1618             var d = t.NODE.DEPTH;
1619             var idx = t.NODE.IDX - 1;
1620             while(idx >= 0 && t.SECS[idx].DEPTH >= d) {
1621               if(t.SECS[idx].DEPTH == d) {
1622                 t.navigateTo(idx);
1623                 return;
1624               }
1625               --idx;
1626             }
1627           }
1628           t.warn("No previous sibling.");
1629         }
1630         else if ('q' == s) {
1631           if(window.confirm("Really close this file?")) {
1632             window.close();
1633           }
1634         }
1635         else if ('<' == s || 't' == s) {
1636           if(0 != t.NODE.IDX) t.navigateTo(0);
1637           else window.scrollTo(0,0);
1638         }
1639         else if ('>' == s || 'E' == s || 'e' == s) {
1640           if((t.SECS.length - 1) != t.NODE.IDX) t.navigateTo(t.SECS.length - 1);
1641           else t.SECS[t.SECS.length - 1].DIV.scrollIntoView(true);
1642         }
1643         else if ('v' == s) {
1644           if(window.innerHeight)
1645             window.scrollBy(0, window.innerHeight - 30);
1646           else if(document.documentElement.clientHeight)
1647             window.scrollBy(0, document.documentElement.clientHeight - 30);
1648           else
1649             window.scrollBy(0, document.body.clientHeight - 30);
1650         }
1651         else if ('V' == s) {
1652           if(window.innerHeight)
1653             window.scrollBy(0, -(window.innerHeight - 30));
1654           else if(document.documentElement.clientHeight)
1655             window.scrollBy(0, -(document.documentElement.clientHeight - 30));
1656           else
1657             window.scrollBy(0, -(document.body.clientHeight - 30));
1658         }
1659         else if ('u' == s) {
1660           if(t.NODE.PARENT != t.ROOT) {
1661             t.NODE = t.NODE.PARENT;
1662             t.showSection(t.NODE.IDX);
1663           }
1664         }
1665         else if ('W' == s) {
1666           t.plainView(t.NODE.IDX);
1667           t.ROOT.DIRTY = true;
1668           t.ROOT_STATE = OrgNode.STATE_UNFOLDED;
1669           t.toggleGlobaly();
1670           t.toggleGlobaly();
1671           t.toggleGlobaly();
1672           window.print();
1673         }
1674         else if ('f' == s) {
1675           if(t.VIEW != t.INFO_VIEW) {
1676             t.NODE.fold();
1677             t.NODE.DIV.scrollIntoView(true);
1678           }
1679         }
1680         else if ('F' == s) {
1681           if(t.VIEW != t.INFO_VIEW) {
1682             t.toggleGlobaly();
1683             t.NODE.DIV.scrollIntoView(true);
1684           }
1685         }
1686         else if ('?' == s || '¿' == s) {
1687           t.showHelp();
1688         }
1689         else if ('C' == s) {
1690           if(t.SORTED_TAGS.length) t.showTagsIndex();
1691           else t.warn("No Tags found.");
1692         }
1693         else if ('H' == s && t.LINK_HOME) {
1694           window.document.location.href = t.LINK_HOME;
1695         }
1696         else if ('h' == s && t.LINK_UP) {
1697           window.document.location.href = t.LINK_UP;
1698         }
1700         /* === READ COMMANDS === */
1702         else if ('l' == s) {
1703           if("" != t.OCCUR) {
1704             t.startRead(t.READ_COMMAND_HTML_LINK, "Choose HTML-link type: 's' = section, 'o' = occur");
1705           } else {
1706             t.startRead(s, "HTML-link:",
1707                            '<a href="' + t.BASE_URL +  t.getDefaultTarget() + '">' +
1708                            document.title + ", Sec. '" + t.removeTags(t.NODE.HEADING.innerHTML) + "'</a>",
1709                            "C-c to copy, ");
1710             window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1711           }
1712           return;
1713         }
1714         else if ('L' == s) {
1715           if("" != t.OCCUR) {
1716             t.startRead(t.READ_COMMAND_ORG_LINK, "Choose Org-link type: 's' = section, 'o' = occur");
1717           } else {
1718             t.startRead(s, "Org-link:",
1719                            '[[' + t.BASE_URL + t.getDefaultTarget() + '][' +
1720                            document.title + ", Sec. '" + t.removeTags(t.NODE.HEADING.innerHTML) + "']]",
1721                            "C-c to copy, ");
1722             window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1723           }
1724           return;
1725         }
1726         else if ('U' == s) {
1727           if("" != t.OCCUR) {
1728             t.startRead(t.READ_COMMAND_PLAIN_URL_LINK, "Choose Org-link type: 's' = section, 'o' = occur");
1729           } else {
1730               t.startRead(s, "Plain URL Link:", t.BASE_URL + t.getDefaultTarget(),
1731                              "C-c to copy, ");
1732             window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1733           }
1734           return;
1735         }
1736         else if ('g' == s) {
1737           t.startRead(s, "Enter section number:");
1738           return;
1739         }
1740         else if ('o' == s) {
1741           if("" != t.OCCUR) t.startRead(s, "Occur:", t.OCCUR, "RET to use previous, DEL ");
1742           else t.startRead(s, "Occur:", t.OCCUR);
1743           window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.value=org_html_manager.OCCUR;org_html_manager.CONSOLE_INPUT.select();}, 100);
1744           return;
1745         }
1746         else if ('s' == s) {
1747           if("" != t.OCCUR) t.startRead(s, "Search forward:", t.OCCUR, "RET to use previous, DEL ");
1748           else t.startRead(s, "Search forward:", t.OCCUR);
1749           window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.value=org_html_manager.OCCUR;org_html_manager.CONSOLE_INPUT.select();}, 100);
1750           return;
1751         }
1752         else if ('S' == s) {
1753           if("" == t.OCCUR) {
1754             s = "s";
1755             t.startRead(s, "Search forward:");
1756           }
1757           else {
1758             t.READ_COMMAND = s;
1759             t.evalReadCommand();
1760           }
1761           return;
1762         }
1763         else if ('r' == s) {
1764           if("" != t.OCCUR) t.startRead(s, "Search backwards:", t.OCCUR, "RET to use previous, DEL ");
1765           else t.startRead(s, "Search backwards:", t.OCCUR);
1766           window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.value=org_html_manager.OCCUR;org_html_manager.CONSOLE_INPUT.select();}, 100);
1767           return;
1768         }
1769         else if ('R' == s) {
1770           if("" == t.OCCUR) {
1771             s = "r";
1772             t.startRead(s, "Search backwards:");
1773           }
1774           else {
1775             t.READ_COMMAND = s;
1776             t.evalReadCommand();
1777           }
1778           return;
1779         }
1780       }
1782     return;
1783   },
1785   /**
1786    * Please return, if you want the minibuffer to stay on screen.
1787    * Remember to call this.endRead()!
1788    */
1789   evalReadCommand: function()
1790   {
1791     var t = this;
1792     var command = t.READ_COMMAND;
1793     var result  = t.trim(t.CONSOLE_INPUT.value);
1795     t.endRead();
1797     if("" == command || "" == result) {
1798       t.hideConsole();
1799       return;
1800     }
1802     // VALID INPUT? COMMANDS FOLLOW HERE
1804     if(command == 'g') { // goto section
1805       var sec = t.SECNUM_MAP[result];
1806       if(null != sec) {
1807         t.hideConsole();
1808         t.navigateTo(sec.IDX);
1809         return;
1810       }
1811       t.warn("Goto section: no such section.", false, result);
1812       return;
1813     }
1815     else if(command == 's') { // search
1816       if("" == result) return false;
1817       if(t.SEARCH_HIGHLIGHT_ON) t.removeSearchHighlight();
1818       var restore = t.OCCUR;
1819       var plus = 0;
1820       if(result == t.OCCUR) plus++;
1821       t.OCCUR = result;
1822       t.makeSearchRegexp();
1823       for(var i = t.NODE.IDX + plus; i < t.SECS.length; ++i) {
1824         if(t.searchTextInOrgNode(i)) {
1825           t.OCCUR = result;
1826           t.hideConsole();
1827           t.navigateTo(t.SECS[i].IDX);
1828           return;
1829         }
1830       }
1831       t.warn("Search forwards: text not found.", false, t.OCCUR);
1832       t.OCCUR = restore;
1833       return;
1834     }
1836     else if(command == 'S') { // repeat search
1837       for(var i = t.NODE.IDX + 1; i < t.SECS.length; ++i) {
1838         if(t.searchTextInOrgNode(i)) {
1839           t.hideConsole();
1840           t.navigateTo(t.SECS[i].IDX);
1841           return;
1842         }
1843       }
1844       t.warn("Search forwards: text not found.", false, t.OCCUR);
1845       return;
1846     }
1848     else if(command == 'r') { // search backwards
1849       if("" == result) return false;
1850       if(t.SEARCH_HIGHLIGHT_ON) t.removeSearchHighlight();
1851       var restore = t.OCCUR;
1852       t.OCCUR = result;
1853       var plus = 0;
1854       if(result == t.OCCUR) plus++;
1855       t.makeSearchRegexp();
1856       for(var i = t.NODE.IDX - plus; i > -1; --i) {
1857         if(t.searchTextInOrgNode(i)) {
1858           t.hideConsole();
1859           t.navigateTo(t.SECS[i].IDX);
1860           return;
1861         }
1862       }
1863       t.warn("Search backwards: text not found.", false, t.OCCUR);
1864       t.OCCUR = restore;
1865       return;
1866     }
1868     else if(command == 'R') { // repeat search backwards
1869       for(var i = t.NODE.IDX - 1; i > -1; --i) {
1870         result = t.removeTags(t.SECS[i].HEADING.innerHTML);
1871         if(t.searchTextInOrgNode(i)) {
1872           t.hideConsole();
1873           t.navigateTo(t.SECS[i].IDX);
1874           return;
1875         }
1876       }
1877       t.warn("Search backwards: text not found.", false, t.OCCUR);
1878       return;
1879     }
1881     else if(command == 'o') { // occur
1882       if("" == result) return false;
1883       if(t.SEARCH_HIGHLIGHT_ON) t.removeSearchHighlight();
1884       var restore = t.OCCUR;
1885       t.OCCUR = result;
1886       t.makeSearchRegexp();
1887       var occurs = new Array();
1888       for(var i = 0; i < t.SECS.length; ++i) {
1889         if(t.searchTextInOrgNode(i)) {
1890           occurs.push(i);
1891         }
1892       }
1893       if(0 == occurs.length) {
1894         t.warn("Occur: text not found.", false, t.OCCUR);
1895         t.OCCUR = restore;
1896         return;
1897       }
1899       t.hideConsole();
1900       if(t.PLAIN_VIEW != t.VIEW) t.plainView();
1901       t.ROOT.DIRTY = true;
1902       t.toggleGlobaly();
1903       for(var i = 0; i < t.SECS.length; ++i) {
1904         OrgNode.showElement(t.SECS[i].DIV);
1905         OrgNode.hideElement(t.SECS[i].FOLDER);
1906       }
1907       for(var i = (occurs.length - 1); i >= 1; --i) {
1908         OrgNode.showElement(t.SECS[occurs[i]].FOLDER);
1909       }
1910       t.showSection(occurs[0]);
1911     }
1913     else if(command == t.READ_COMMAND_ORG_LINK) {
1914       var c = result.charAt(0);
1915       if('s' == c) {
1916         t.startRead(t.READ_COMMAND_NULL, "Org-link to this section:",
1917                        '[[' + t.BASE_URL + t.getDefaultTarget() + '][' +
1918                        document.title + ", Sec. '" +  t.removeTags(t.NODE.HEADING.innerHTML) + "']]",
1919                        "C-c to copy, ");
1920         window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1921       } else if('o' == c) {
1922         t.startRead(t.READ_COMMAND_NULL, "Org-link, occurences of <i>&quot;"+t.OCCUR+"&quot;</i>:",
1923                        '[[' + t.BASE_URL + "?OCCUR=" + t.OCCUR + '][' +
1924                        document.title + ", occurences of '" + t.OCCUR + "']]",
1925                        "C-c to copy, ");
1926         window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1927       } else {
1928         t.warn(c + ": No such link type!");
1929       }
1930     }
1932     else if(command == t.READ_COMMAND_HTML_LINK) {
1933       var c = result.charAt(0);
1934       if('s' == c) {
1935         t.startRead(t.READ_COMMAND_NULL, "HTML-link to this section:",
1936                        '<a href="' + t.BASE_URL + t.getDefaultTarget() + '">' +
1937                        document.title + ", Sec. '" +  t.removeTags(t.NODE.HEADING.innerHTML) + "'</a>",
1938                        "C-c to copy, ");
1939         window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1940       } else if('o' == c) {
1941         t.startRead(t.READ_COMMAND_NULL, "HTML-link, occurences of <i>&quot;"+t.OCCUR+"&quot;</i>:",
1942                        '<a href="' + t.BASE_URL + "?OCCUR=" + t.OCCUR + '">' +
1943                        document.title + ", occurences of '" + t.OCCUR + "'</a>",
1944                        "C-c to copy, ");
1945         window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1946       } else {
1947         t.warn(c + ": No such link type!");
1948       }
1949     }
1951     else if(command == t.READ_COMMAND_PLAIN_URL_LINK) {
1952       var c = result.charAt(0);
1953       if('s' == c) {
1954         t.startRead(t.READ_COMMAND_NULL, "Plain-link to this section:",
1955                        t.BASE_URL + t.getDefaultTarget(),
1956                        "C-c to copy, ");
1957         window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1958       } else if('o' == c) {
1959         t.startRead(t.READ_COMMAND_NULL, "Plain-link, occurences of <i>&quot;"+t.OCCUR+"&quot;</i>:",
1960                        t.BASE_URL + "?OCCUR=" + t.OCCUR,
1961                        "C-c to copy, ");
1962         window.setTimeout(function(){org_html_manager.CONSOLE_INPUT.select();}, 100);
1963       } else {
1964         t.warn(c + ": No such link type!");
1965       }
1966     }
1968   },
1970   getDefaultTarget: function(node)
1971   {
1972     if(null == node) node = this.NODE;
1973     var loc = "#" + this.NODE.BASE_ID;
1974     for(var s in node.isTargetFor) {
1975       if(! s.match(this.SID_REGEX)){loc = s; break;}
1976     }
1977     return loc;
1978   },
1984   makeSearchRegexp: function()
1985   {
1986     var tmp = this.OCCUR.replace(/>/g, "&gt;").
1987       replace(/</g, "&lt;").
1988       replace(/=/g, "\\=").
1989       replace(/\\/g, "\\\\").
1990       replace(/\?/g, "\\?").
1991       replace(/\)/g, "\\)").
1992       replace(/\(/g, "\\(").
1993       replace(/\./g, "[^<>]").
1994       replace(/\"/g, "&quot;");
1995     this.SEARCH_REGEX = new RegExp(">([^<]*)?("+tmp+")([^>]*)?<","ig");
1996   },
1998   searchTextInOrgNode: function(i)
1999   {
2000     var t = this;
2001     var ret = false;
2002     if(null != t.SECS[i]) {
2003       if(t.SEARCH_REGEX.test(t.SECS[i].HEADING.innerHTML)) {
2004         ret = true;
2005         t.setSearchHighlight(t.SECS[i].HEADING);
2006         t.SECS[i].HAS_HIGHLIGHT = true;
2007         t.SEARCH_HIGHLIGHT_ON = true;
2008       }
2009       if(t.SEARCH_REGEX.test(t.SECS[i].FOLDER.innerHTML)) {
2010         ret = true;
2011         t.setSearchHighlight(t.SECS[i].FOLDER);
2012         t.SECS[i].HAS_HIGHLIGHT = true;
2013         t.SEARCH_HIGHLIGHT_ON = true;
2014       }
2015       return ret;
2016     }
2017     return false;
2018   },
2020   setSearchHighlight: function(dom)
2021   {
2022     var tmp = dom.innerHTML;
2023     dom.innerHTML = tmp.replace(this.SEARCH_REGEX,
2024       '>$1<span class="org-info-js_search-highlight">$2</span>$3<');
2025   },
2027   removeSearchHighlight: function()
2028   {
2029     var t = this;
2030     for(var i = 0; i < t.SECS.length; ++i) {
2031       if(t.SECS[i].HAS_HIGHLIGHT) {
2032         while(t.SEARCH_HL_REGEX.test(t.SECS[i].HEADING.innerHTML)) {
2033           var tmp = t.SECS[i].HEADING.innerHTML;
2034           t.SECS[i].HEADING.innerHTML = tmp.replace(t.SEARCH_HL_REGEX, '$2');
2035         }
2036         while(t.SEARCH_HL_REGEX.test(t.SECS[i].FOLDER.innerHTML)) {
2037           var tmp = t.SECS[i].FOLDER.innerHTML;
2038           t.SECS[i].FOLDER.innerHTML = tmp.replace(t.SEARCH_HL_REGEX, '$2');
2039         }
2040         t.SECS[i].HAS_HIGHLIGHT = false;
2041       }
2042     }
2043     t.SEARCH_HIGHLIGHT_ON = false;
2044   },
2050   highlightHeadline: function(h)
2051   {
2052     var i = parseInt(h);
2053     if(this.PLAIN_VIEW == this.VIEW && this.MOUSE_HINT) {
2054       if('underline' == this.MOUSE_HINT)
2055         this.SECS[i].HEADING.style.borderBottom = "1px dashed #666666";
2056       else
2057         this.SECS[i].HEADING.style.backgroundColor = this.MOUSE_HINT;
2058     }
2059   },
2061   unhighlightHeadline: function(h)
2062   {
2063     var i = parseInt(h);
2064     if('underline' == this.MOUSE_HINT) {
2065       this.SECS[i].HEADING.style.borderBottom = "";
2066     }
2067     else
2068       this.SECS[i].HEADING.style.backgroundColor = "";
2069   },
2071   showHelp: function ()
2072   {
2073     var t = this;
2074     if     (t.READING)   { t.endRead(); }
2075     else if(t.MESSAGING) { t.removeWarning(); }
2076     /* This is an OrgMode version of the table. Turn on orgtbl-mode in
2077        this buffer, edit the table, then press C-c C-c with the cursor
2078        in the table.  The table will then be translated an inserted below.
2079 #+ORGTBL: SEND Shortcuts orgtbl-to-generic :splice t :skip 2 :lstart "\t+'<tr>" :lend "</tr>'" :fmt (1 "<td><code><b>%s</b></code></td>" 2 "<td>%s</td>") :hline "\t+'</tbody><tbody>'"
2080       | Key          | Function                                                |
2081       |--------------+---------------------------------------------------------|
2082       | ? / &iquest; | show this help screen                                   |
2083       |--------------+---------------------------------------------------------|
2084       |              | <b>Moving around</b>                                    |
2085       | n / p        | goto the next / previous section                        |
2086       | N / P        | goto the next / previous sibling                        |
2087       | t / E        | goto the first / last section                           |
2088       | g            | goto section...                                         |
2089       | u            | go one level up (parent section)                        |
2090       | i / C        | show table of contents / tags index                     |
2091       | b / B        | go back to last / forward to next visited section.      |
2092       | h / H        | go to main index in this directory / link HOME page     |
2093       |--------------+---------------------------------------------------------|
2094       |              | <b>View</b>                                             |
2095       | m / x        | toggle the view mode between info and plain / slides    |
2096       | f / F        | fold current section / whole document (plain view only) |
2097       |--------------+---------------------------------------------------------|
2098       |              | <b>Searching</b>                                        |
2099       | s / r        | search forward / backward....                           |
2100       | S / R        | search again forward / backward                         |
2101       | o            | occur-mode                                              |
2102       | c            | clear search-highlight                                  |
2103       |--------------+---------------------------------------------------------|
2104       |              | <b>Misc</b>                                             |
2105       | l / L / U    | display HTML link / Org link / Plain-URL                |
2106       | v / V        | scroll down / up                                        |
2107       | W            | Print                                                   |
2108       */
2109     t.HELPING = t.HELPING ? 0 : 1;
2110     if (t.HELPING) {
2111       t.LAST_VIEW_MODE = t.VIEW;
2112       if(t.PLAIN_VIEW == t.VIEW) t.infoView(true);
2113       t.WINDOW.innerHTML = 'Press any key or <a href="javascript:org_html_manager.showHelp();">click here</a> to proceed.'
2114         +'<h2>Keyboard Shortcuts</h2>'
2115         +'<table cellpadding="3" rules="groups" frame="hsides" style="caption-side:bottom;margin:20px;border-style:none;" border="0";>'
2116         +'<caption><small>org-info.js, v.###VERSION###</small></caption>'
2117     +'<tbody>'
2118       // BEGIN RECEIVE ORGTBL Shortcuts
2119         +'<tr><td><code><b>? / &iquest;</b></code></td><td>show this help screen</td></tr>'
2120         +'</tbody><tbody>'
2121         +'<tr><td><code><b></b></code></td><td><b>Moving around</b></td></tr>'
2122         +'<tr><td><code><b>n / p</b></code></td><td>goto the next / previous section</td></tr>'
2123         +'<tr><td><code><b>N / P</b></code></td><td>goto the next / previous sibling</td></tr>'
2124         +'<tr><td><code><b>t / E</b></code></td><td>goto the first / last section</td></tr>'
2125         +'<tr><td><code><b>g</b></code></td><td>goto section...</td></tr>'
2126         +'<tr><td><code><b>u</b></code></td><td>go one level up (parent section)</td></tr>'
2127         +'<tr><td><code><b>i / C</b></code></td><td>show table of contents / tags index</td></tr>'
2128         +'<tr><td><code><b>b / B</b></code></td><td>go back to last / forward to next visited section.</td></tr>'
2129         +'<tr><td><code><b>h / H</b></code></td><td>go to main index in this directory / link HOME page</td></tr>'
2130         +'</tbody><tbody>'
2131         +'<tr><td><code><b></b></code></td><td><b>View</b></td></tr>'
2132         +'<tr><td><code><b>m / x</b></code></td><td>toggle the view mode between info and plain / slides</td></tr>'
2133         +'<tr><td><code><b>f / F</b></code></td><td>fold current section / whole document (plain view only)</td></tr>'
2134         +'</tbody><tbody>'
2135         +'<tr><td><code><b></b></code></td><td><b>Searching</b></td></tr>'
2136         +'<tr><td><code><b>s / r</b></code></td><td>search forward / backward....</td></tr>'
2137         +'<tr><td><code><b>S / R</b></code></td><td>search again forward / backward</td></tr>'
2138         +'<tr><td><code><b>o</b></code></td><td>occur-mode</td></tr>'
2139         +'<tr><td><code><b>c</b></code></td><td>clear search-highlight</td></tr>'
2140         +'</tbody><tbody>'
2141         +'<tr><td><code><b></b></code></td><td><b>Misc</b></td></tr>'
2142         +'<tr><td><code><b>l / L / U</b></code></td><td>display HTML link / Org link / Plain-URL</td></tr>'
2143         +'<tr><td><code><b>v / V</b></code></td><td>scroll down / up</td></tr>'
2144         +'<tr><td><code><b>W</b></code></td><td>Print</td></tr>'
2145       // END RECEIVE ORGTBL Shortcuts
2146        +'</tbody>'
2147        +'</table><br />Press any key or <a href="javascript:org_html_manager.showHelp();">click here</a> to proceed.';
2148       window.scrollTo(0, 0);
2149     }
2150     else {
2151       if(t.PLAIN_VIEW == t.LAST_VIEW_MODE) {
2152         t.plainView();
2153       }
2154       else if(t.SLIDE_VIEW == t.LAST_VIEW_MODE) {
2155         t.slideView();
2156       }
2157       t.showSection(t.NODE.IDX);
2158     }
2159   },
2162   showTagsIndex: function ()
2163   {
2164     var t = this;
2165     if     (t.READING)   { t.endRead(); }
2166     else if(t.MESSAGING) { t.removeWarning(); }
2167     t.HELPING = t.HELPING ? 0 : 1;
2168     if (t.HELPING) {
2169       t.LAST_VIEW_MODE = t.VIEW;
2170       if(t.PLAIN_VIEW == t.VIEW) t.infoView(true);
2171       if(null == t.TAGS_INDEX) {
2172         t.TAGS_INDEX = 'Press any key or <a href="javascript:org_html_manager.showTagsIndex();">click here</a> to proceed.'
2173           +'<br /><br />Click the headlines to expand the contents.'
2174           +'<h2>Index of Tags</h2>';
2175         for(var i = 0; i < t.SORTED_TAGS.length; ++i) {
2176           var tag = t.SORTED_TAGS[i];
2177           var fid = 'org-html-manager-sorted-tags-' + tag;
2178           t.TAGS_INDEX += '<a href="javascript:OrgNode.toggleElement(document.getElementById(\''
2179             + fid + '\'));"><h3>' + tag + '</h3></a>'
2180             + '<div id="' + fid + '" style="visibility:hidden;display:none;"><ul>';
2181           for(var j = 0; j < t.TAGS[tag].length; ++j) {
2182             var idx = t.TAGS[tag][j];
2183             t.TAGS_INDEX += '<li><a href="javascript:org_html_manager.showSection('
2184               + idx + ');">'
2185               + t.SECS[idx].HEADING.innerHTML +'</a></li>';
2186           }
2187           t.TAGS_INDEX += '</ul></div>';
2189         }
2190         t.TAGS_INDEX += '<br />Press any key or <a href="javascript:org_html_manager.showTagsIndex();">click here</a> to proceed.';
2191       }
2192       t.WINDOW.innerHTML = t.TAGS_INDEX;
2193       window.scrollTo(0, 0);
2194     }
2195     else {
2196       if(t.PLAIN_VIEW == t.LAST_VIEW_MODE) {
2197         t.plainView();
2198       }
2199       else if(t.SLIDE_VIEW == t.LAST_VIEW_MODE) {
2200         t.slideView();
2201       }
2202       t.showSection(t.NODE.IDX);
2203     }
2204   },
2207   /*
2208     HOOKs
2209   */
2211   /**
2212    * @private
2213    * Run hooks.
2214    * @param name Name of the hook to be executed.  One of the indicies in the
2215    *             <code>OrgHtmlManager.HOOKS</code> variable.
2216    * @param args The arguments to be passed to the hook function.
2217    *             E.g. <code>{an: "object"}</code> or <code>["array"]</code>.
2218    *             The first argument passed to the hook is the OrgHtmlManager
2219    *             itself.
2220    */
2221   runHooks: function(name, args)
2222   {
2223     if(this.HOOKS.run_hooks && this.HOOKS[name]) {
2224       for(var i=0; i<this.HOOKS[name].length; ++i) {
2225         this.HOOKS[name][i](this, args);
2226       }
2227     }
2228   },
2230   /**
2231    * Add Hooks.
2232    * If <code>this.HOOKS[name]</code> is not an array, it is created.
2233    * @param name Name of the hook, i.e. the index in <code>this.HOOKS</code>.
2234    * @param func The function object.
2235    */
2236   addHook: function(name, func)
2237   {
2238     if('run_hooks' != name) {
2239       this.HOOKS[name].push(func);
2240     }
2241   },
2243   /**
2244    * Remove Hooks.
2245    * @param name Name of the hook, i.e. the index in <code>this.HOOKS</code>.
2246    * @param func The function object to be removed from the hook.  JavaScript
2247    *             considers two functions written the same way identical.
2248    */
2249   removeHook: function(name, func)
2250   {
2251     if(this.HOOKS[name]) {
2252       for(var i = this.HOOKS[name].length - 1; i >= 0; --i) {
2253         if(this.HOOKS[name][i] == func) {
2254           this.HOOKS[name].splice(i, 1);
2255         }
2256       }
2257     }
2258   }
2268 function OrgHtmlManagerKeyEvent (e)
2270   var c;
2271   if (!e) e = window.event;
2272   if (e.which) c = e.which;
2273   else if (e.keyCode) c = e.keyCode;
2275   if(e.ctrlKey) return;
2277   var s = String.fromCharCode(c);
2278   if(e.shiftKey)
2279     org_html_manager.CONSOLE_INPUT.value = org_html_manager.CONSOLE_INPUT.value + s;
2280   else
2281     org_html_manager.CONSOLE_INPUT.value = org_html_manager.CONSOLE_INPUT.value + s.toLowerCase();
2283   org_html_manager.getKey();
2288  * Wait for document.body to be loaded and call org_html_manager.init().
2289  * In Opera document.body is true, even if not loaded (try with big big
2290  * file). This case is handled by the OrgHtmlManager class itself.
2291  */
2292 function OrgHtmlManagerLoadCheck()
2294   org_html_manager.init();