// connect.js  4 june 1999//// THIS IS NOT AN OFFICIAL RELEASE BUT A CURRENT WORKING VERSION !!//// This library provides javascript tools for // hypertext literary writing in html.// // In particular, it defines javascript functions for// history-based conditional links and conditional writing in HTML.//// Important: this version is a prototype, functionalities may me // modified in future versions.//// Documentation: http://www.wordcircuits.com/connect// e-mail: connection@wordcircuits.com//// You can freely use and distribute this library provided that // this notice remains included. // (c) 1999 Jean-Hugues Rety and Robert Kendall.////// Parameters.//// The variable _hist_cookie_name_ below contains the name of the // cookie that contains the historical list of visited pages// of your hypertext.// If the history is long and requires the use of several cookies,// these cookies will have the same name but extended with // the suffixe: '2', '3',...// IMPORTANT. This feature is not implemented yet. At the moment, the// history is limited to one cookie, i.e., to 2000 characters.// In consequence, this current version of the library can manage up// to approximately 200-250 pages long histories.var hist_cookie_name = "Peggy";// the variable _dead_link_ below specifies how appears // links when the target file is "null".// (only valid when there is no popup or status text to be displayed)!! var dead_link_style = null;//var dead_link_style = "underline";//color of text written with hWrite var hWrite_color = document.fgColor;//var hWrite_color = document.linkColor;//var hWrite_color = document.vlinkColor;// color of dead links:var dead_link_color = document.fgColor;//var dead_link_color = document.linkColor;//var dead_link_color = document.vlinkColor;// default attributes for pop-up textvar popup_att_default = 'BGCOLOR="#FFFFCC"';//var popup_att_default = 'BGCOLOR="#FF6666"';var dead_link_popup = false;// default attributes for status textvar dead_link_status = false;// shall titles be poped up?var title_popup = false;// shall titles be displayed in the status bar?var title_status = true;//// Initializations//var h_hist = histValue ();var h_hist_empty = (h_hist == "");addHist();var h_no_link = true;var h_popnb = 1;var popupText = null;var statusText = null;var popupAtt = "";if (typeof(titleArray) == "undefined")    titleArray = new Array ();if (typeof(popupAttArray) == "undefined")    popupAttArray = new Array ();// Basic cookie manipulation functions.function h_cookieVal (name) // Returns the value of the cookie _name_.   {function h_cookieVal2 (offset)    {   var end = document.cookie.indexOf (";", offset);   if (end == -1)      end = document.cookie.length;   return unescape(document.cookie.substring(offset, end));   }   var prefix = name + "=";   var prefix_len = prefix.length;   var cookie_len = document.cookie.length;   var i = 0;   while (i < cookie_len )       {      var j = i + prefix_len;      if (document.cookie.substring(i, j) == prefix)         return h_cookieVal2 (j);      i = document.cookie.indexOf(" ", i) + 1;      if (i == 0) break;       }   return "";   }function h_setCookie (name, value) // Sets the cookie _name_ with value _value_.   {   var arg = h_setCookie.arguments;   var arg_len = h_setCookie.arguments.length;   var expires = (arg_len > 2) ? arg[2] : null;   var path = (arg_len > 3) ? arg[3] : null;   var domain = (arg_len > 4) ? arg[4] : null;   var secure = (arg_len > 5) ? arg[5] : false;   document.cookie = name + "=" + escape (value) +        ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +        ((path == null) ? "" : ("; path=" + path)) +        ((domain == null) ? "" : ("; domain=" + domain)) +        ((secure == true) ? "; secure" : "");   }function h_deleteCookie (name) // Deletes the cookie _name_.   {   var expires = new Date ();   expires.setTime (expires.getTime() - 1000000000);     var val = h_cookieVal (name);   document.cookie = name + "=" + val + "; expires=" + expires.toGMTString();   }// Other basic functionsfunction h_thisFile ()// Returns the file name of the current window location   {   var url = window.location.href;   var i = url.lastIndexOf ('/');   return (url.substring (i +1, url.length));   }function h_show(object) // Sets the visibility attribute to visible   {    if (document.layers && document.layers[object])       document.layers[object].visibility = 'visible';    else if (document.all)       { document.all[object].style.visibility = 'visible'; document.all[object].style.zIndex = 100; }    }function h_hide(object) // Sets the visibility attribute to hidden   {    if (document.layers && document.layers[object])       document.layers[object].visibility = 'hidden';    else if (document.all)       document.all[object].style.visibility = 'hidden';    }function h_member (ident, str)// Returns true if _ident_ belongs to the string _str_.   {   if (str.indexOf(ident) != -1) return (true);   else return(false);   }// Functions for identifiers manipulationfunction makeIdent (lfile)// Produces the identifier to be used in the history.   {   var i = lfile.lastIndexOf ('/');   var file = lfile.substring (i +1, lfile.length);   var dot = file.lastIndexOf ('.');   if (dot == -1) return (file + '?');   var suffix = file.substring (dot +1, file.length);   var prefix = file.substring (0, dot);   switch (suffix)       {      case "html" :          return (prefix);      case "htm" :          return (prefix + '|');      default :          return (file + '?');      }    }function makeFileName (ident)// Returns the file name corresponding to _ident_.   {   var end = ident.length -1;   switch (ident.charAt (end) )       {      case "?" :         return (ident.substring(0, end));      case "|" :         return (ident.substring(0, end) + ".htm");      default :         return (ident + ".html");      }   }// Functions for history manipulationfunction setHist (value)// Sets the history to  _value_.   {     var name = hist_cookie_name;   var exp_date = new Date ();    exp_date.setTime(exp_date.getTime() + (24 * 60 * 60 * 1000 * 365));    // The expiration date of the cookie (here: 1 year after it is set).   h_setCookie (name, value, exp_date);     return false;   }function histValue ()// Returns the value of the history.   {     var name = hist_cookie_name;   return h_cookieVal (name);   }function histArray ()// Returns an array containing the history.   {   h = new Array ();   var ind = 0;   var i = 0;   var j = h_hist.indexOf ('*', i+1);   while (j != -1)      {      h[ind] = makeFileName ( h_hist.substring( i+1, j));      ind++;      i = j;      j = h_hist.indexOf ('*', i+1);      }   return (h);}// End user functions for text or file (or whatever)  specification// These functions can also be used inside conditions.function firstCond (otherwise, items_and_conds)// _items_and_conds_ is of the form://     item1, cond1, item2, cond2, item3, cond3,...// items can be file names or text, or whatever// Returns the first item _itemi_ such that _condi_ holds.// If no condition is satisfied then returns _otherwise.   {   var arg = firstCond.arguments;   var arg_len = firstCond.arguments.length;   for (var i=1 ; i<arg_len ; i=i+2)      if ( arg[i+1] )         return (arg[i]);   return (arg[0]);   }function random (items)// Randomly selects an item in _items_.    {   var arg = random.arguments;   var arg_len = random.arguments.length;   var select = Math.floor (Math.random () * (arg_len) );   if (select == arg_len) select = arg_len - 1;   return (arg[select]);   }function randomCond (otherwise, items_and_conds)// Randomly selects an item _itemi_  such that _condi_ holds.// If no condition is satisfied then returns _otherwise__.   {   var arg = randomCond.arguments;   var arg_len = randomCond.arguments.length;   nv = new Array (arg_len - 1);   var nbnv = 0;   for (var i = 1 ; i < arg_len ; i=i+2)      if ( arg[i+1] )         {         nv[nbnv] = i;         nbnv++;         }   if (nbnv ==0) return (otherwise);   else      {      var select = Math.ceil (Math.random () * (nbnv) );      if (select == 0) select = 1;      return (arg[ nv[select -1] ]);      }      }// End user functions for file specification// These functions can also be used inside conditions.function hist (rank)// Returns the page (file name) element of rank _rank_ in the history.// If _rank_ = 0, Hist(rank) returns the current page // (last element of the history.// If _rank_ is negative, the rank is counted in reverse from the last element // in the history.   {   if (rank > 0)       {      var end = h_hist.length-1;      var j = 0;      var k = h_hist.indexOf ('*', j +1);      for (var i=rank ; i>1 ; i--)         {         if (j >= end) break;         j = k;         k = h_hist.indexOf ('*', j +1);         }      if (j >= end) return (null);      var ident = h_hist.substring (j+1, k);      return (makeFileName (ident) );      }   if (rank <= 0)       {      var j = h_hist.length -1;      var k = h_hist.lastIndexOf ('*', j-1);      for (var i=rank ; i<0 ; i++)         {         if (j <= 0) break;         j = k;         k = h_hist.lastIndexOf ('*', j-1);         }      if (j <= 0) return (null);      var ident = h_hist.substring (k+1, j);      return (makeFileName (ident) );      }   }function histRank(file)// Returns a javascript array containing the indices where // _file_ appears in the history.   {   var ident = makeIdent (file);   indarray = new Array ();   var i = 0;  var j = 0; var ind = 1;   var k = h_hist.indexOf ('*', j +1);      while (k != -1)      {      if (h_hist.substring (j+1, k) == ident)         {          indarray[i] = ind;          i++;          }      j = k;      k = h_hist.indexOf ('*', j +1);      ind++;      }   return (indarray);   }function firstVisited (files)// Returns the page (file name) in _files_ that was visited first.// Returns null if none of _files_ were visited.   {   var arg = firstVisited.arguments;   var arg_len = firstVisited.arguments.length;   var max_val = h_hist.length;   var max_file = null;   for (var i=0 ; i<arg_len ; i++)      {         var ident = makeIdent (arg[i]);      var j = h_hist.indexOf ('*' + ident + '*');      if (j != -1 && j < max_val)         {         max_val = j;         max_file = arg[i];         }      }   return (max_file);   }function lastVisited (files)// Returns the page (file name) in _files_ that was last visited.// Returns null if none of _files_ were visited.   {   var arg = lastVisited.arguments;   var arg_len = lastVisited.arguments.length;   var max_val = -1;   var max_file = null;   for (var i=0 ; i<arg_len ; i++)         {      var ident = makeIdent(arg[i]);      var j = h_hist.lastIndexOf('*' + ident + '*')      if (j > max_val)         {         max_val = j;         max_file = arg[i];         }      }   return (max_file);   }function firstNotVisited (otherwise_target, targets)// Returns the first page not visited in the arguments _targets_. // If all pages in _targets_ are visited then returns  _otherwise_target_.   {   var arg = firstNotVisited.arguments;   var arg_len = firstNotVisited.arguments.length;   for (var i=1 ; i<arg_len ; i++)      if ( ! (visited (arg[i]) ) )          return (arg[i]);   return (arg[0]);   }   function randomNotVisited (otherwise_file, files)// Randomly selects a non visited page in _files_.// If all pages in _targets_ are visited then returns  _otherwise_target_.   {   var arg = randomNotVisited.arguments;   var arg_len = randomNotVisited.arguments.length;   nv = new Array (arg_len - 1);   var nbnv = 0;   for (var i = 1 ; i < arg_len ; i++)      if (! visited(arg[i]))         {         nv[nbnv] = i;         nbnv++;         }   if (nbnv == 0) return (otherwise_file);   else      {      var select = Math.ceil (Math.random () * (nbnv) );      if (select == 0) select = 1;      return (arg[ nv[select -1] ]);      }      }function randomNotVisitedNotLinked (otherwise_file, files)// Randomly selects a non visited and non linked  page in _files_.// If all pages in _targets_ are visited then returns  _otherwise_target_.   {   var arg = randomNotVisitedNotLinked.arguments;   var arg_len = randomNotVisitedNotLinked.arguments.length;   nv = new Array (arg_len - 1);   var nbnv = 0;   for (var i = 1 ; i < arg_len ; i++)      if (! visited(arg[i]) && ! linked(arg[i]))         {         nv[nbnv] = i;         nbnv++;         }   if (nbnv == 0) return (otherwise_file);   else      {      var select = Math.ceil (Math.random () * (nbnv) );      if (select == 0) select = 1;      return (arg[ nv[select -1] ]);      }      }// Other end user functions for building conditionsfunction visited (files)// Returns true if all pages in _files_ belong to the history.   {   var arg = visited.arguments;   var arg_len = visited.arguments.length;   for (var i=0 ; i<arg_len ; i++)      {      var ident = makeIdent (arg[i]);      if ( ! h_member('*' + ident + '*', h_hist) )           return (false);      }   return (true);   }function orVisited (files)// Returns true if at least one of the pages in _files_ belong to the history.   {   var arg = orVisited.arguments;   var arg_len = orVisited.arguments.length;   for (var i=0 ; i<arg_len ; i++)      {      var ident = makeIdent (arg[i]);      if ( h_member('*' + ident + '*', h_hist) )           return (true);      }   return (false);   }function visitedFrom (file)// Returns true if _file_ was visited immediately after the current page.// if 2 arguments, tests _file_ was visited from the second file argument.   {   var arg = visitedFrom.arguments;   var arg_len = visitedFrom.arguments.length;   var offset = "*" + makeIdent (file) + "*";   if (arg_len == 1)      offset = "*" + makeIdent ( h_thisFile() ) + offset;   else      offset = "*" + makeIdent (arg[1]) + offset;   return ( h_member(offset, h_hist) );   }function linked (files)// Returns true if all pages in _files_ are linked above in the document.   {   var arg = linked.arguments;   var arg_len = linked.arguments.length;   var nb_links = document.links.length;   var l_list = "*";   for (var i=0 ; i<nb_links ; i++)      l_list = l_list + makeIdent(document.links[i].toString()) + "*";   for (var i=0 ; i<arg_len ; i++)      {      var ident = makeIdent (arg[i]);      if ( ! h_member('*' + ident + '*', l_list) )           return (false);      }   return (true);   }function nbVisits (file)// Returns how many times _page_ was already visited.   {   var nb_visits = 0;   var ident = makeIdent (file);   var i = h_hist.indexOf ('*' + ident + '*');   while (i != -1)      {      nb_visits++;      i = h_hist.indexOf ('*' + ident + '*',i+1);      }   return (nb_visits);   }        function nbDiffVisited ()// Returns the number of different pages already visited.   {   var nbpages = 0;   var i = 0;   while ( i < h_hist.length)      {      var next = h_hist.indexOf ('*', i+1);      if (next == -1) break;      var h_ident = h_hist.substring (i, next +1);      if (h_hist.indexOf(h_ident) == i)         nbpages++;      i = next;      }   return (nbpages);   }function nbVisited ()// Returns the number of pages already visited, // i.e., the length of the history.   {   var nbVisited = 0;   var i = h_hist.indexOf ('*');      i = h_hist.indexOf ('*', i+1);   while ( i != -1)      {      i = h_hist.indexOf ('*', i+1);      nbVisited++;      }   return (nbVisited);   }function nbDiffVisitedIn (files)// Returns how many pages in _files_ were already visited.   {   var nbpages = 0;   var arg = nbDiffVisitedIn.arguments;   var arg_len = nbDiffVisitedIn.arguments.length;   for (var i=0 ; i<arg_len ; i++)      {              var ident = makeIdent (arg[i]);      if (h_member('*' + ident + '*', h_hist))          nbpages++;      }   return (nbpages);   }// End-user functions for history munipulationfunction initHist (file)// Initialises the history with the current window or _file_ identifier.   {   if (initHist.arguments.length == 0)            h_hist = '*' + makeIdent( h_thisFile() ) + '*';           else      h_hist = '*' + makeIdent(file) + '*';     setHist (h_hist);   }function addHist (file)// Adds the current window or _file_ identifier to the history.   {   if (h_hist.charAt (h_hist.length -1) != "*") h_hist = h_hist + '*';   if (addHist.arguments.length == 0)      h_hist = h_hist + makeIdent( h_thisFile() ) + '*';   else      h_hist = h_hist + makeIdent(file) + '*';   setHist (h_hist);   }function deleteHist ()// Deletes the history.   {   var name = hist_cookie_name;   h_deleteCookie (name);   h_hist = "";   }function histEmpty ()// Returns true if the history is empty.   {   return (h_hist_empty);   }// End-user functions for writing and linkingfunction cond (yes_javascript_code, condd, no_javascript_code)// Conditional function.// _yes_javascript_code_ is  executed if cond holds.// _no_javascript_code_, if specified,  is executed if cond does not hold.   {   if (condd)      document.write("<SCRIPT type='text/javascript'>" +  yes_javascript_code + "</SCRIPT>");   else      if ( typeof(no_javascript_code) == "string" )         document.write("<SCRIPT type='text/javascript'>" + no_javascript_code + "</SCRIPT>");   }function hWrite (text)// Writes _text_ with possibly popup or/and status text if specified   {   if (popupText == null && statusText == null)      document.write(text);   else       {         var tmp = document.linkColor;         document.linkColor = hWrite_color;         document.write ("<A HREF='javascript:void(0)' onMouseOver='");       if (statusText != null)         document.write("window.status=" + '"' + statusText + '";');      if (popupText != null)         document.write ("h_show(" + '"pop' + h_popnb.toString() + '"' + ");");      document.write(" return true;' onMouseOut='");      if (statusText != null)         document.write('window.status="";');      if (popupText != null)         document.write("h_hide(" + '"pop' + h_popnb.toString() + '"' + ");");         document.write(" return true'>" + text + "</A>");      if (popupText != null)         document.write("<SPAN ID=" + '"pop' + h_popnb.toString() + '"' + " CLASS='popup'><TABLE " + popupAtt + " " + popup_att_default + "><TR><TD>" + popupText + "</TD></TR></TABLE></SPAN>");        document.linkColor = tmp;   popupText = null;   statusText = null;   popupAtt = "";         } }               function condWrite (yes_text, condd, no_text)// Conditional write.// _yes_text_ is the text to be written if cond holds.// _no_text_, if specified, is the text to be written if cond does not hold.   {   if (condd)      document.write (yes_text);           else      if ( typeof(no_text) == "string" )         document.write (no_text);   }function link (target, text)// Creates a link to file _target_ with text _text_.   {   if (target == null)   {      if (popupText == null && title_popup == true)         if (typeof(titleArray['dead_link']) != "undefined")             popupText = titleArray['dead_link'];      if (statusText == null && title_status == true)         if (typeof(titleArray['dead_link']) != "undefined")             statusText = titleArray['dead_link'];      if ( (popupText != null && dead_link_popup == true)           ||           (statusText != null && dead_link_status == true) )         {         var tmp = document.linkColor;         document.linkColor = dead_link_color;         document.write ("<A HREF='javascript:void(0)' onMouseOver='");       if (statusText != null && dead_link_status == true)         document.write("window.status=" + '"' + statusText + '";');      if (popupText != null && dead_link_popup == true)         document.write ("h_show(" + '"pop' + h_popnb.toString() + '"' + ")");      document.write(" return true' onMouseOut='");      if (statusText != null && dead_link_status == true)         document.write('window.status="";');      if (popupText != null && dead_link_popup == true)         document.write ("h_hide(" + '"pop' + h_popnb.toString() + '"' + ");");         document.write(" return true'>" + text + "</A>");      if (popupText != null && dead_link_popup == true)         document.write("<SPAN ID=" + '"pop' + h_popnb.toString() + '"' + " CLASS='popup'><TABLE " + popupAtt + " " + popup_att_default + "><TR><TD>" + popupText + "</TD></TR></TABLE></SPAN>");              document.linkColor = tmp;         h_popnb++;         }      else      switch ( dead_link_style )         {         case "underline" :            document.write ('<FONT COLOR=' + '"' + dead_link_color + '">' + '<U>' + text + '</U></FONT>'); break;         default :            document.write ('<FONT COLOR=' + '"' + dead_link_color + '">' + text + '</FONT>');         }   }   else      {      if (popupText == null && title_popup == true)         if (typeof(titleArray[target]) != "undefined")             popupText = titleArray[target];      if (statusText == null && title_status == true)         if (typeof(titleArray[target]) != "undefined")             statusText = titleArray[target];      document.write ('<A HREF=' + target);      if (statusText != null || popupText != null)         document.write(" onMouseOver='");      if (statusText != null)         document.write("window.status=" + '"' + statusText + '";');      if (popupText != null)        document.write("h_show(" + '"pop' + h_popnb.toString() + '"' + ");");      if (statusText != null || popupText != null)         document.write(" return true' onMouseOut='");      if (statusText != null)         document.write('window.status="";');      if (popupText != null)        document.write ("h_hide(" + '"pop' + h_popnb.toString() + '"' + ");");      if (statusText != null || popupText != null)         document.write(" return true'");      document.write (">" + text + '</A>');               if (popupText != null)         {         document.write("<SPAN ID=" + '"pop' + h_popnb.toString() + '"' + " CLASS='popup'><TABLE " + popupAtt + " " + popup_att_default + "><TR><TD>" + popupText + "</TD></TR></TABLE></SPAN>");           h_popnb++;         }      h_no_link = false;      }   popupText = null;   statusText = null;   popupAtt = "";   }    function condLink(target, text, condd, no_target, no_text)// Creates a conditional link to target with text _text_ // under condition _cond_. If cond does not hold and no_text, no_target // are specified, then creates a link to no_target with text no_text.   {   if (condd)      link (target, text);   else       {      if ( typeof(no_text) != "undefined" )         text = no_text;      if ( typeof(no_target) !="undefined" )         link (no_target, text);      }   }    function otherwiseLink (target, text, no_target, no_text)// Creates a link to target with text _text_ if no other // link was active in the page.// If some other link was active, uses no_target and no_text, if specified.    {   condLink(target, text, h_no_link, no_target, no_text);   }
