// Copyright 2004 Tangora Software A/S. All rights reserved.
//
// Tangora CMS Dictionary script
//
// Last changed: 2005-02-17
//


// 
// Configuration: Change the following settings as desired
// 

// maxterms: maximum number of words in each term
// For example: Set maxterms=4 to support terms 
// such as "Bygning på lejet grund"
var maxterms=5;
var DictionaryClassName="dictionaryelem";
var linkClass="dictionarylink";
var linkPrefix="ORDBOG: ";

// popupPageId: id of the list page that is used for the popup window
var popupPageId=1503;
var popupWindowWidth=350;
var popupWindowHeight=300; // notice: window is automatically resized...
var popupWindowLeft=500;
var popupWindowTop=150;

// MainDictionaryPageId: id of the list page that is used for the dictionary page 
// on the website (i.e. NOT the popup page)
// Dictionary links on this page will automatically reuse the primary window and 
// will NOT open a popup window)
var MainDictionaryPageId=1511;

// Set Default_HighlightFirstOccurrence if you only want to highlight the first 
// occurrence of each word on each page (can be overridden when calling the 
// CreateDictionaryLinks function)
var Default_HighlightFirstOccurrence=true;

// At some websites, an extra <p></p> is added after each section
// Set TSRemoveExtraPTag=true to remove this extra tag 
TSRemoveExtraPTag=false;

// safeTags is an array of any HTML tags that should not be searched for terms
// safeCSS is an array of any CSS classes that should not be searched for terms
var safeTags=new Array("A", "STRONG", "B", "FONT");
var safeCSS=new Array("sectionheader");

// Notice: it is important that the punctuation variable 
// includes space in order to strip trailing spaces
var punctuation=".,:;?!()[]{}'\" \n\r";

// The following characters will be treated as separators inside words
// This is for example used to treat "intranet/extranet" as two separate words
var inline_punctuation="/";

// set InitDictionary=true to initialize the onload handler (is often done by using a 
// section layout or modifying the relevant sitelayouts)
// Notice: Will be ignored, if DisableDictionary=true
var InitDictionary;

// set DisableDictionary=true to disable dictionary links on a single page (is typically
// set by using a section layout to overrule InitDictionary=true in a site layout)
var DisableDictionary;

// DictionaryPageID is set by the code in the site layout (or section layout)
var DictionaryPageID;


// Function: GetLinkHTML
//
// Modify this function to change the way links are rendered, for example by prefixing 
// the word with an image
// 
function GetLinkHTML(linktext, recordid, ignore) {
  if (!ignore) { ignore=linktext; }
  if (!linkClass) { linkClass="inlinelink"; }
  if (!linkPrefix) { linkPrefix=""; }
  var popup, pageid;
  if (DictionaryPageID && DictionaryPageID==MainDictionaryPageId) {
    // reuse the primary browser window
    pageid=DictionaryPageID;
  } else {
  	popup=true;
    pageid=popupPageId;
  }
  var linkhref="/page"+pageid+".aspx?recordid"+pageid+"="+recordid;
  if (popup) {
    // set flags (resize window + ignore this keyword)
    linkhref+="&resize=true&ignore="+escape(ignore);
  }
  var html="<a title='"+linkPrefix+linktext+"' onmouseover=\"window.status='"+linkPrefix+linktext+"';return true\" onmouseout=\"window.status='';return true\" class='"+linkClass+"'";
  html+=" href='"+linkhref+"'";
  if (popup) {
  	html+=" target='"+DictionaryClassName+"popup' onclick=\"ShowDictionaryPopup('"+linkhref+"');return false\"";
  }
  html+=">"+linktext+"</a>";
  return html;
}

function ShowDictionaryPopup(linkhref) {
  var features="resizable=yes,titlebar=yes";
  if (navigator.userAgent.indexOf("MSIE")==-1) {
    // Only hide scrollbars in IE where they can be shown again by using document.body.scroll="auto"
    // Notice that the scrollbars are only shown by Mozilla/Netscape/Firefox and Safari when necessary,
    // so it should be an acceptable solution... 
    features+=",scrollbars=yes";
  }
  win=window.open(linkhref,DictionaryClassName+"popup","width="+popupWindowWidth+",height="+popupWindowHeight+",left="+popupWindowLeft+",top="+popupWindowTop+","+features);
  if (win) {
    if (win.document && win.document.body && win.document.body.innerHTML) {
      // blank window first (to hide any previous contents)
      win.document.body.innerHTML="";
    }
    if (win && win.focus) {
      win.focus();
    }
  }
}

//
// Function: CreateDictionaryLinks(HighlightFirstOccurrence)
//
// This is the main function that searches the page for recognized words
//
// Set HighlightFirstOccurrence to true if you only want to highlight the first 
// occurrence of each word on each page?
function CreateDictionaryLinks(HighlightFirstOccurrence) {
  // don't call script on admin pages or if it has already been called
  if (location.href.indexOf("/admin")!=-1 || DisableDictionary) {
    return;
  }
  DisableDictionary=true; // only invoke function once
  
  if (typeof(HighlightFirstOccurrence)=="undefined") {
    HighlightFirstOccurrence=Default_HighlightFirstOccurrence;
  }
  
  // read data from iframe 
  if (typeof terms=="undefined") {
    if (frames && frames.glossaryFrame && frames.glossaryFrame.terms) {
      terms=frames.glossaryFrame.terms;
    }
  }
  
  // convert tags to uppercase and store them as properties 
  safeTags=PrepareSafeTagArray(safeTags, true);
  // store tags as properties (ignore case)
  safeCSS=PrepareSafeTagArray(safeCSS);
  
  // ignore keyword? (used in popup window to avoid linking to the current keyword)
  var ignore="";
  var re=/ignore=([^&]+)/;
  var m=location.href.match(re);
  if (m && m[1]) {
    ignore=PrepareTerm(unescape(m[1].toLowerCase()));
  }

  // find objects
  var obj=GetElementsByClassName(DictionaryClassName);
  if (obj && obj.length && typeof(terms)=="object") {
    // this regular expression extracts 
    // 1) all HTML-tags "<[^>]*>[\s]*" (including any trailing white space)
    //    The string "[^>]" makes the expression non-greedy
    // 2) words (including any punctuation and "[\s]*" gets any trailing white space)
    //    The string "[^&<>\s]" is used instead of "\S" to prevent
    //    HTML-tags from being included in the words
    // 3) &nbsp; have to be treated individually
    // 4) > have to be trapped. They will normally be matched as part of case (1), but in 
    //    certain cases they won't (for example when an A-tag has an attribute which contains 
    //    a ">" such as "<A href='/page12.aspx' title='Tangora CMS >'>"
    // 5) ampersands have to be extracted individually since they are ignored in case (2)
    //    this is also the case for "inline punctuation" (which is treated as a separator)
    var reg=new RegExp("<[^>]*>[\\s]*|>|[^&"+inline_punctuation+"<>\\s]+[\\s]*|&nbsp;|>|[&"+inline_punctuation+"]", "g");
    var regTag=/<([^ >]*)/;
    var regClass=/\sclass=['"]*([^ >'"]+)/i;
    var s, m, tmp, linktext, mtag;
    var key=new Array();
    var i, t, found, hits;
    // prevHTML is set to true to avoid a leading space
    var isHTML, prevHTML=true;
    var safeHTML=false, tagName, tmptag;
    for (i=0; i<obj.length; i++) {
      hits=0;
      s=FixInnerHTML(obj[i].innerHTML);
      m=s.match(reg);
      tmp=new Array();
      for (var k=0;m && k<m.length;k++) {
        found=false;

        // is the first word a HTML-tag?
        isHTML=(m[k].indexOf("<")==0);
        if (isHTML) {
          // check for safe tags
          var mtag=m[k].match(regTag);
          if (mtag && mtag[1]) {
            tmptag=mtag[1].toUpperCase();
            if (safeHTML) {
              // reached end tag?
              if (tmptag=="/"+tagName) {
                safeHTML=false;
                tagName="";
              }
            } else {
              if (safeTags[tmptag]) {
                // ignore the contents of this HTML tag
                safeHTML=true;
                tagName=tmptag;
              } else {
                // check for CSS class names
                var classname=m[k].match(regClass);
                if (classname && classname[1] && safeCSS[classname[1]]) {
                	// found
                	safeHTML=true;
                	tagName=tmptag;
                }
              }
            }
          }
        }
        
        // prefix is used for any initial punctuation (for example parenthesis)
        var prefix, space, prevkey, tmpmaxterms;
        if (!isHTML && !safeHTML) {
          // combine words to array keys of varyings size (since some  
          // of the terms consist of multiple words)
          prefix=GetInitialPunctuation(m[k]);
          key[0]=PrepareKeyword(m[k]);
          if (prefix) {
            // strip initial punctuation
            key[0]=key[0].substr(prefix.length);
          }
          prevkey=key[0];
          tmpmaxterms=maxterms;
          for (t=1; t<tmpmaxterms && t+k<m.length; t++) {
          	if (m[k+t]=="&nbsp;") {
          	  tmpmaxterms++;
          	  // don't set this key
          	  key[t]=null;
            } else {
              // only add space if we are NOT adding an ampersand
              space=(m[k+t-1]=="&" || m[k+t]=="&")?"":" ";
              key[t]=ConvertHTMLEntities(prevkey+space+PrepareKeyword(m[k+t]));
              prevkey=key[t];
            }
          }
          // search array with terms in reverse order (longest term first)
          for (t=tmpmaxterms-1; t>=0 && !found; t--) {
            if (key[t] && terms[key[t]] && key[t]!=ignore) {
              // Found! 
              hits++;
  
              //
              // add word(s) to output string as a hyperlink 
              //
              linktext="";
              for (var tt=0; tt<t; tt++) {
                // add keywords including spaces
                linktext+=m[k+tt];
              }
              // strip punctuation from last keyword in this sentence
              linktext+=StripPunctuationAndSpaces(m[k+t]);
              // strip any initial punctuation from this sentence
              if (prefix) {
                linktext=linktext.substr(prefix.length); 
              }
              
              tmp[tmp.length]=prefix+GetLinkHTML(linktext, terms[key[t]], key[t])+GetPunctuationAndSpaces(m[k+t]);
  
              // skip words by incrementing k (relevant when the term 
              // consists of multiple words)
              k=k+t;
              found=true;
              
              // only highlight first occurrence of each word on each page?
              if (HighlightFirstOccurrence) {
              	// remove word from array
                terms[key[t]] = null;
              }
            } 
          } 
        }
        if (!found) {
          // add word to output string

          //tmp+=((prevHTML || isHTML)?"":" ")+m[k];
          tmp[tmp.length]=m[k];
        }
        prevHTML=isHTML;
        
      }
      if (hits) {
        obj[i].innerHTML=tmp.join("");
      }
    }
  }
}

// function PrepareTerm strips punctuation, extra spaces, etc. 
function PrepareTerm(term) {
  // remove any double spaces
  term=term.replace(/ +/g, " ");
  var words=term.split(" ");
  var str;
  for (var i=0; i<words.length; i++) {
    str=ConvertHTMLEntities(words[i]);
    str=PrepareKeyword(str)
    words[i]=str;
  }
  return words.join(" ");
}

// function PrepareKeyword strips punctuation and converts the
// string to lower case
function PrepareKeyword(str) {
  if (!str) return "";
  str=str.toLowerCase();
  return StripPunctuationAndSpaces(str);
}

function PrepareSafeTagArray(obj, convertCase) {
  if (typeof obj=="undefined") {
    obj=new Array();
  } else {
    var tmptag;
    for (var i=0; i<obj.length; i++) {
      tmptag=convertCase ? obj[i].toUpperCase() : obj[i];
      obj[tmptag]=true;
    }
  }
  return obj;
}

function StripPunctuationAndSpaces(str) {
  if (!str) return "";
  var len=0, strlen=str.length;
  while (len<strlen && punctuation.indexOf(str.substr(strlen-len-1, 1))>-1) {
    len++;
  }
  return str.substr(0,strlen-len);
}

// function GetPunctuationAndSpaces returns any trailing
// punctuation and spaces
function GetPunctuationAndSpaces(str) {
  if (!str) return "";
  var len=0, strlen=str.length;
  while (len<strlen && punctuation.indexOf(str.substr(strlen-len-1, 1))>-1) {
    len++;
  }
  return str.substr(strlen-len,len);
}

// function GetInitialPunctuation returns any leading punctutation
function GetInitialPunctuation(str) {
  if (!str) return "";
  var len=0, strlen=str.length;
  while (len<strlen && punctuation.indexOf(str.substr(len, 1))>-1) {
    len++;
  }
  return str.substr(0, len);
}

function ConvertHTMLEntities(str) {
  str=str.replace(/&trade;/g, unescape("%u2122"));
  str=str.replace(/&amp;/g, "&");
  return str;
}


// function FixInnerHTML removes an empty p tag at the end of the 
// objects innerHTML 
function FixInnerHTML(html) {
  if (TSRemoveExtraPTag) {
    var ptag="<P></P>";
    var l=ptag.length;
    if (html && html.length >= l) {
      var tmp=html.substring(html.length-l);
      if (tmp.toUpperCase() == ptag) {
        html=html.substring(0, html.length-l);
      }
    }
  }
  return html;
}


// GetElementsByClassName is similar to document.getElementsByName but checks 
// for CSS className and also works on IE Mac (by iterating through all divs)
function GetElementsByClassName(cssclass) {
  var obj;
  if (document.getElementsByTagName) {
    obj=new Array();
    var divarray=document.getElementsByTagName("DIV");
    if (divarray && divarray.length) {
      for (var i=0; i<divarray.length; i++) {
        if (divarray[i].className == cssclass) {
          obj[obj.length]=divarray[i];
        }
      }
    }
  }
  return obj;
}

function GetWindowHeight() {
  var myWidth = 0;
  var myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myWidth = window.innerWidth;
    myHeight = window.innerHeight;
  } else if( document.documentElement &&
      ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
    myHeight = document.documentElement.clientHeight;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    myWidth = document.body.clientWidth;
    myHeight = document.body.clientHeight;
  }
  return myHeight;
}

function AddTermFromLink(elemid) {
  var termelem=GetElem(elemid);
  if (textelem && elemid) {
    // get A-tag (first child)
    var linktag=GetFirstChild(termelem);
    if (linktag) {
      var href=linktag.href;
      var str=linktag.innerHTML;

      // extract recordid from href
      var recordid=GetRecordId(href, popupPageId);      
      
      AddTerm(recordid, str);
    }
  }
}

function AddTerm(recordid, term) {
  // prepare string (lower case, remove trailing spaces)
  // notice: trailing spaces and whitespace is removed from all 
  // words (if the terms consists of more than one word)
  var str;
  if (recordid && term) {
    var str=PrepareTerm(term);
    if (str && recordid) {
      if (typeof(jstext)=="string") {
        // add term to temporary string (used when manually
        // updating the word list)
        jstext+="terms['"+str+"']='"+recordid+"';\n";
      } else {
        // add term directly to array 
        if (!terms) { terms=new Array(); }
        terms[str]=recordid;
      }
    }
  }
}

// Extract recordid from URL
function GetRecordId(href, pageid) {
  if (!href) { return ""; }
  var reg=new RegExp("recordid"+pageid+"=(\\d+)");
  var m=href.match(reg);
  if (m && m[1]) {
    return m[1];
  } 
  return null;
}
function GetElem(elemid) {
  if (document.all) {
    return document.all[elemid];
  } else if (typeof document.getElementById=="function") {
    return document.getElementById(elemid);
  }
  return null;
}
function GetFirstChild(obj) {
  if (obj) {
    if (obj.firstChild) { 
      return obj.firstChild; 
    } else if (obj.children) {
      return obj.children[0];
    }
    return null;
  }
}

function GetBodyTableHeight() {
  var h=null;
/*
  if (document.body && typeof(document.body.offsetHeight)!="undefined") {
    h=document.body.offsetHeight;
    if (!h && document.body.firstChild) {
      // this works in Safari
      h=document.body.firstChild.offsetHeight;
    }
  }
*/
  var obj=GetElem("bodytable");
  if (obj && obj.offsetHeight) {
    h=obj.offsetHeight;
  }
  return h;
}

// resize window
var ResizeWindowPrevOnload;
function ResizeWindow() {
  var bodyHeight=GetBodyTableHeight();
  var windowHeight=GetWindowHeight()
  if (bodyHeight && windowHeight && bodyHeight > windowHeight) {
    window.resizeBy(0, bodyHeight-windowHeight+50);
  }
  if (ResizeWindowPrevOnload) {
    ResizeWindowPrevOnload();
  }
}
if (location.href.indexOf("&resize=true")!=-1) {
  ResizeWindowPrevOnload=window.onload;
  window.onload=ResizeWindow;
}

// Init onload handler
var TSDictionary_PrevOnloadFunc; 
if (InitDictionary && !DisableDictionary && !TSDictionary_PrevOnloadFunc) {
  TSDictionary_PrevOnloadFunc=window.onload;
  window.onload=function () {
    if (typeof(CreateDictionaryLinks)=="function") {
      CreateDictionaryLinks();
      if (TSDictionary_PrevOnloadFunc) { TSDictionary_PrevOnloadFunc (); }
    }
  }
}

