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