Source for "Gmail Google Calendar sidebar"

By Brad Stewart
Has 2 other scripts.


Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)

/*
   Google Calendar Feed View - GMAIL
   version 0.5 BETA
   04-13-2006
   Copyright (c) 2006, Chris McKeever
   Updates by Brad Stewart
   Released under the GPL license
   http://www.gnu.org/copyleft/gpl.html
   -
   -
   This script grabs a GCAL feed URL, parses it, and display it in 
   a side nav.   
   Installation:
      1) Click the install icon for this user script in FireFox
      2) First get your Calendar Feed URL from calendar.google.com (XML)
         a. click the down arrow beside the calendar name in the left panel
         b. choose calendar settings
         c. click the XML button next to "Private Address:" at the bottom 
         d. copy the URL in the pop-up
      3) Add this URL google bookmarks (http://google.com/bookmarks) with a label that does not contain spaces (GMgcal recommended)
      4) When GMail is locaded/refreshed a new NAV box will appear indicating you neeed to run setup.
      5) To run setup, click Firefox's tools menu, then choose user script commands->GMail Agenda Setup
      6) This will prompt you for the bookmark label (the one you selected above) and the events to display
      7) GMail _should_ refresh with your calendar loaded.
      8) To add feeds for further calendars, simply repeat steps 2 and 3 for each.  Make sure you use the same label as before.
      9) To change the colour of items from a calendar, rename that calendar (in google calendar) so that it ends with a colour hex code, such as #F2A640 for orange -- the # is necessary
   --------------------------------------------------------------------
   This is a Greasemonkey user script.
   -
   To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
   Then restart Firefox and revisit this script.
   Under Tools, there will be a new menu item to "Install User Script".
   Accept the default configuration and install.
   -
   To uninstall, go to Tools/Manage User Scripts,
   select "Add Calendar Feed - GMail", and click Uninstall.
   --------------------------------------------------------------------
*/

// ==UserScript==
// @name             Gmail Google Calendar sidebar
// @namespace        http://www.r2unit.com/greasemonkey
// @description      Adds a sidebar to GMail that displays your upcoming events/appointments from Google Calendar.
// @include          http://mail.google.com/mail/*
// @include          https://mail.google.com/mail/*
// @exclude          http://mail.google.com/mail/help/*
// @exclude          https://mail.google.com/mail/help/*
// ==/UserScript==


GM_registerMenuCommand('GMail Agenda Setup   ',gcal_setup)
var EventList = new Array();

function gcal_setup(){

   var gcalLabel = GM_getValue('gcalLabel');
   if (!gcalLabel || gcalLabel == 'undefined') gcalLabel = 'GMgcal';
   gcalLabel=prompt('What is the Label for the XML Feed Bookmark',gcalLabel);
   GM_setValue('gcalLabel',gcalLabel);

   var gcalDisplay = GM_getValue('gcalDisplay');
   if (!gcalDisplay) gcalDisplay = 5;
   gcalDisplay=prompt('Display how many events',gcalDisplay);
   GM_setValue('gcalDisplay',gcalDisplay);
   top.location.href = "https://mail.google.com/mail";

}

(function() {


var _gel = getObjMethodClosure(document, "getElementById");
// wait till screen is drawn
if(!_gel('nav')) return;

var newNode = getObjMethodClosure(document, "createElement");
var newText = getObjMethodClosure(document, "createTextNode");

GM_addStyle(
            // Block in sidebar
            ".gcalDIV {-moz-border-radius: 5px; background: #c3d9ff; margin: 20px 7px 0 0; padding: 3px;}\n"+
            ".gcalListDIV {background: white; display:none; padding: 0px 3px 0px 2;}\n"+
            ".gcalStatusDIV {background: #ffffcc; padding: 2px 0px 5px 2px; font-size: 8pt;}\n"+
            ".gcalItem {color: #CC3333; font-size: 8pt;}\n"+
            ".HgcalItem {color: #CC3333; font-size: 8pt;background-color:#FFFFCC}\n"+
            ".GgcalItem {color: #CC3333; font-size: 8pt;background-color:#EBFFCE}\n"+
            ".gcalEditDIV {text-align: right; padding: 2px 0px 5px 0; display:none; background: white;}\n"+
            ".gcalEditLink {color: #CC3333;}\n"
            );

var gcalLabel = GM_getValue('gcalLabel');
if (!gcalLabel || gcalLabel == 'undefined') gcalLabel = 'GMgcal';

var gcalDisplay = GM_getValue('gcalDisplay');
if (!gcalDisplay   || gcalDisplay == 'undefined') gcalDisplay = 5;

XMLURL = "http://www.google.com/bookmarks/lookup?q=label:" + gcalLabel + "&sort=title";

// define the NAV area
var gcalDIV = newNode("div");
gcalDIV.id = "nb_gcal_1";
gcalDIV.className = "gcalDIV";

// header
var gcalTitleDIV = newNode("div");
gcalTitleDIV.className = "s h";
gcalTitleDIV.addEventListener("click", toggleGcalDIV, true);
gcalDIV.appendChild(gcalTitleDIV);

var gcalTriangleImage = newNode("img");
gcalTriangleImage.src = "/mail/images/opentriangle.gif";
gcalTriangleImage.width = 11;
gcalTriangleImage.height = 11;
gcalTitleDIV.appendChild(gcalTriangleImage);

var gcalTitle = newNode("span");
gcalTitle.innerHTML = " Agenda";
gcalTitleDIV.appendChild(gcalTitle);

// container
var gcalContDIV = newNode("div");
gcalContDIV.style.display = 'block';
gcalDIV.appendChild(gcalContDIV)

// loading message
var gcalStatusDIV = newNode("div");
gcalStatusDIV.className = "gcalStatusDiv";
gcalStatusDIV.appendChild(newText('Loading ' + gcalLabel + "..."));
gcalContDIV.appendChild(gcalStatusDIV);

// link list
var gcalListDIV = newNode("div");
gcalListDIV.className = "gcalListDIV";
gcalContDIV.appendChild(gcalListDIV);

// DIV and A for editing
var gcalEditDIV = newNode("div");
gcalEditDIV.className = "gcalEditDIV";
gcalContDIV.appendChild(gcalEditDIV);

var gEditA = newNode('a');
gEditA.href = "http://gmail.com";
gEditA.className = "lk cs gcalEditLink";
gEditA.appendChild(newText("Reload"));
gEditA.addEventListener("click", function(e) {
   e.preventDefault();
   EventList = new Array();
   GM_setValue("last_updated", 0);
   getData();
} , true);
gcalEditDIV.appendChild(gEditA);

var gEditA = newNode('a');
gEditA.href = "http://calendar.google.com";
gEditA.target = "_blank";
gEditA.className = "lk cs gcalEditLink";
gEditA.appendChild(newText("Edit Gcal"));
gcalEditDIV.appendChild(gEditA);

_gel('nav').insertBefore(gcalDIV, _gel('nb_0'));

initialize();

function initialize(){
    
   // define global
   deflen = 15; // default length of text units
   EventList = new Array;   // Array of events
   XmlErrorOccurred = false;   // tinydom parser

   // user preferences 
   feed_bmk = gcalLabel;
   ShowDecline = false; 
   dayForward = 120;

   // Short Day array
   dayA = new Array;
   dayA[0] = 'Sun';
   dayA[1] = 'Mon';
   dayA[2] = 'Tue';
   dayA[3] = 'Wed';
   dayA[4] = 'Thu';
   dayA[5] = 'Fri';
   dayA[6] = 'Sat';

   // Month array
   monthA = new Array;
   monthA[1] = 'January';
   monthA[2] = 'February';
   monthA[3] = 'March';
   monthA[4] = 'April';
   monthA[5] = 'May';
   monthA[6] = 'June';
   monthA[7] = 'July';
   monthA[8] = 'August';
   monthA[9] = 'September';
   monthA[10] = 'October';
   monthA[11] = 'November';
   monthA[12] = 'December';

   // current date info
   nowParse = parseDate(new Date(),false);
   nowDate = new Date(monthA[nowParse['month']] + " " + nowParse['date'] + " " + nowParse['year']);
   nowTS = nowDate.getTime();
   // feed parameters

   start_maxTS = nowTS + (1000 * 60 * 60 * 24) * dayForward;
   start_max = parseDate(start_maxTS);
   if (start_max['month'].toString().length == 1) start_max['month'] = "0" + start_max['month'];
   if (start_max['date'].toString().length == 1) start_max['date'] = "0" + start_max['date'];
   start_max = start_max['year'] + "-" + start_max['month'] + "-" + start_max['date']

   start_minTS = nowTS - (45 * 24 * 60 * 60 * 1000) // look back days
   start_min = parseDate(start_minTS);
   if (start_min['month'].toString().length == 1) start_min['month'] = "0" + start_min['month'];
   if (start_min['date'].toString().length == 1) start_min['date'] = "0" + start_min['date'];
   start_min = start_min['year'] + "-" + start_min['month'] + "-" + start_min['date']

   // end global declarations 
   getData();
}

function getData(){
   var d = new Date();
   if (parseInt(GM_getValue("last_updated", 0)) + 3600000 > d.getTime()){
      var json = GM_getValue("events", "");
      try {
         data = eval(json);
         for (var i=0; i < data.length; i++){
            e = data[i];
            addEvent(new CalendarEvent(e.id,e.title,e.startTS,e.endTS,e.URL,e.location,e.repeatTS,e.repeatType,e.repeatInt,e.repeatByDay, e.colour));
         }
         EventList = EventList.sort(function(a,b){return cmp(a.startTS,b.startTS);});
         renderCalendar(EventList); 

         return;
      } catch(e){
      }
   }

   gcalStatusDIV.innerHTML = 'Retrieving Bookmarks...';

   GM_xmlhttpRequest({
      method: 'GET',
      url: XMLURL,
      onload: function(responseDetails) {
         var bmkURL = responseDetails.responseText.match(/\.\/url[^ \n\r"]+(?=.*id="bkmk_href)/g);
         if (!bmkURL){
            gcalStatusDIV.innerHTML = "Calendar URL not found.   Please run Setup under Tools -> User Script Commands.";
         }else{
            for (var i = 0; i < bmkURL.length; i++){
               XMLURL = bmkURL[i].replace('./url?url=', '');
               XMLURL = XMLURL.match(/(.+)(basic|full)/);
               XMLURL = XMLURL[0];
               if (XMLURL.match(/.*basic$/)) XMLURL = XMLURL.replace(/basic$/,'full');
               getFeed(XMLURL, bmkURL.length == 1);
            }
         }
      },
      onerror: function(responseDetails) {
         gcalStatusDIV.innerHTML = "Error Loading Agenda";
      }
   });
}
function makeJSON(events){
   // ######
   var results = new Array();
   for (var i = 0; i < events.length; i++){
      event = events[i];
      var result = "{";
      result += "id : '"+ event.id + "',"
      result += "title : '"+ event.title + "',"
      result += "URL : '"+ event.URL + "',"
      result += "location : '"+ event.location + "',"
      result += "colour : '"+ event.colour + "',"
      result += "startTS : "+ event.startTS + ","
      result += "endTS : "+ event.endTS + ","
      result += "duration : "+ event.duration + ","
      result += "repeatTS : '"+ event.repeatTS + "',"
      result += "repeatType : '"+ event.repeatType + "',"
      result += "repeatInt : '"+ event.repeatInt + "',"
      result += "repeatByDay : '"+ event.repeatByDay + "'"
      result += "}"
      results.push(result);
   }
   return "[" + results.join(",") + "]";
   
}

function getFeed(gcalURL, setTitle){
   if (gcalURL == 'undefined' || !gcalURL) {
      gcalStatusDIV.innerHTML = "Calendar URL not found.   Please run Setup under Tools -> User Script Commands.";	
      return;
   }

   var gcalURL = gcalURL + "?start-max=" + start_max + "&start-min=" +   start_min;
   
   GM_xmlhttpRequest({
      method: 'GET',
      url: gcalURL,
      headers: {
         'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/0.3',
         'Accept': 'application/atom+xml,application/xml,text/xml',
      },
      onload: function(responseDetails) { parseCalendarXML(responseDetails.responseText, setTitle); },
      onerror: function(responseDetails) { gcalStatusDIV.innerHTML = "Error Loading Agenda"; }
   });
}

function parseCalendarXML(feedXML, setTitle){
   var responseDOM = new XMLDoc(feedXML, function(error){if(XmlErrorOccurred == false) XmlErrorOccurred = true;});

   if ( responseDOM == null || responseDOM.docNode == null){
      gcalStatusDIV.innerHTML =   "<FONT style='color:red;font-size:.8em;'>The response from Google contained invalid XML.</FONT>";
      return;
   }
   
   var calTitle = shrink(responseDOM.docNode.getElements("title")[0].getText(),20,'');
   var calColour = null;
   var temp = calTitle.split("#");
   if (temp.length > 1){
      calColour = "#" + temp[1];
      calTitle = temp[0]
   }

   if (setTitle){
       gcalTitle.innerHTML = "&nbsp;" + calTitle;
   }

   gcalStatusDIV.innerHTML = "Loading " + calTitle   + "...";

   var feedAuthor = responseDOM.docNode.getElements("author")[0];
   if (feedAuthor.length != 0) {
      feedAuthor = feedAuthor.getElements("email")[0];
      if (feedAuthor) feedAuthor = feedAuthor.getText();
   }

   var eventNodes = responseDOM.docNode.getElements("entry");
   var whenNodes;
   var originalID;
   var statusNodes;   
   var whoNodes;
   var attd;
   var evCancelled;
   var aParent = new Array;
   var aEvent = new Array;
   
   var evId;
   var evAuthor;
   var evTitle;
   var evStartTS;
   var evEndTs;
   var evURL;
   var evLocation;
   var evRepeatTS;
   var evRepeatInt;
   var evRepeatType;
   var evRepeatByDay;

   var idRE = /[^\/]*$/;
   for (var eventNode = 0; eventNode < eventNodes.length; ++eventNode){
      aEvent = new Array;
      evId = idRE.exec(eventNodes[eventNode].getElements("id")[0].getText());
      evTitle = shrink(eventNodes[eventNode].getElements("title")[0].getText(),deflen,"...");
      evURL = eventNodes[eventNode].getElements("link")[0].getAttribute('href');

      summaryNode = eventNodes[eventNode].getElements('summary')[0];
      recurrenceNode = eventNodes[eventNode].getElements('gd:recurrence')[0];   
      whenNodes = eventNodes[eventNode].getElements("gd:when"); 
 
      originalID = eventNodes[eventNode].getElements("gd:originalEvent");
      if (originalID[0]){
         originalID = originalID[0].getAttribute('id');
         aParent[originalID] = true;
      }

      statusNodes = eventNodes[eventNode].getElements("gd:eventStatus");

      evCancelled = false;
      for (var statusI = 0; statusI < statusNodes.length; ++statusI){
         if(statusNodes[statusI].getAttribute('value').match(/.canceled/)) evCancelled = true;
      }
 
      evAuthor = eventNodes[eventNode].getElements("author")[0];
      if (evAuthor.length != 0){
         evAuthor = evAuthor.getElements("email")[0];
         if (evAuthor) evAuthor = evAuthor.getText(); 
      }

      whoNodes = eventNodes[eventNode].getElements("gd:who");   
      for (var whoI = 0; whoI < whoNodes.length; ++whoI){
         attd = whoNodes[whoI].getAttribute('valueString');
         if (whoNodes[whoI].getElements("gd:attendeeStatus")[0].getAttribute('value').match(/.declined/)
             && attd == feedAuthor && evAuthor != feedAuthor && !ShowDecline) evCancelled = true;
      }

      // left over code
      evRepeatTS = "";
      evRepeatInt = "";
      evRepeatType = "";
      evRepeatByDay = "";

      if (whenNodes.length > 0){   
         // normal event node
         aEvent = new Array;
         evLocation = shrink(eventNodes[eventNode].getElements('gd:where')[0].getAttribute('valueString'),deflen,"...");

         for (var whenNode = 0; whenNode < whenNodes.length; ++whenNode){

            aEvent[whenNode] = new Array;
            aEvent[whenNode]['evStartTS'] = TSfromISO(whenNodes[whenNode].getAttribute('startTime'),0,false);
            aEvent[whenNode]['evEndTS'] = TSfromISO(whenNodes[whenNode].getAttribute('endTime'),0,true);

         }
      }

      if(!evCancelled && !aParent[evId]){ 
         // loop the when node results and add
         for (var aWheni = 0; aWheni < aEvent.length; aWheni++){ 
            if (new Date(aEvent[aWheni]['evEndTS']).getTime() != aEvent[aWheni]['evEndTS']) aEvent[aWheni]['evEndTS'] = aEvent[aWheni]['evstartTS'];
               addEvent(new CalendarEvent(evId,evTitle,aEvent[aWheni]['evStartTS'],aEvent[aWheni]['evEndTS'],evURL,evLocation,evRepeatTS,evRepeatType,evRepeatInt,evRepeatByDay, calColour));
         }
      } 

   } // event loops   

   EventList = EventList.sort(function(a,b){return cmp(a.startTS,b.startTS);});
   renderCalendar(EventList); 
   GM_setValue("events", makeJSON(EventList));
   var date = new Date();
   GM_setValue("last_updated", date.getTime().toString());


}


function renderCalendar(eventA){
   var max_display = gcalDisplay;
   var Dmonth = true;
   var Ddate = true;
   var Dday_of_week = true;
   var Dyear = true;
   var Dtime = true;
   var Dlocation = true;
   var Dsingle = true;
   var Uhighlight = true;

   var evHTML = "";
   var event; var summary; var tT; var std; var etd;

   var now = monthA[nowParse['month']] + " " + nowParse['date'] + " " + nowParse['year']; 
   var highlight;

   var eCount = eventA.length;   
   if (eCount > parseInt(max_display)) eCount = parseInt(max_display); // set max display

   evHTML = "<TABLE cellspacing=0 cellpadding=0 border=0 width='99%'>";
   for (var eI = 0; eI < eCount; eI++){
      event = eventA[eI];
    
      std = parseDate(event.startTS);
      etd = parseDate(event.endTS);

      std['d'] = monthA[std['month']] + " " + std['date'] + " " + std['year'];
      etd['d'] = monthA[etd['month']] + " " + etd['date'] + " " + etd['year'];

      if (nowDate > new Date(std['d']) && Uhighlight){
         highlight = "GgcalItem"; 
      } else if (now == std['d'] && Uhighlight){
         highlight = "HgcalItem"; 
      } else highlight = "gcalItem";

      var style = "valign=top class='" + highlight + "'";

      // try to remove some of the dead space in the table
      std['month'] = monthA[std['month']].substring(0,3) + "&nbsp;";
      std['day'] = dayA[std['day']] + "&nbsp;";
      std['year'] = "&nbsp;" + std['year'];
      std['remainDate'] = "";

      etd['month'] = monthA[etd['month']].substring(0,3) + "&nbsp;";
      etd['day'] = dayA[etd['day']] + "&nbsp;";
      etd['year'] = "&nbsp;" + etd['year'];

      if (!Dday_of_week){
         std['day'] = "";
         etd['day'] = "";
      }

      if (!Dmonth){
         std['month'] = "";
         etd['month'] = "";
      }

      if (!Ddate){
         std['date'] = "";
         etd['date'] = "";
         std['month'] = std['month'].replace(/&nbsp;/,'');
         etd['month'] = etd['month'].replace(/&nbsp;/,'');
      }

      if (!Dyear) {
         std['year'] = "";
         etd['year'] = "";
      }

      std['t'] = "";
      etd['t'] = "";
      if (Dtime){
         var AMPM = "a";
         
         if(std['hour'] > 12){
            AMPM = "p";
            std['hour'] = std['hour'] - 12;
         } else if (std['hour'] == 0){
            AMPM = "a";
            std['hour'] = "12";
         } else if (std['hour'] == 12){
            AMPM = "p";
         } else if (std['hour'].toString().substring(0,1) == "0"){
            std['hour'] = std['hour'].toString().substring(1,2);
         }

         std['t'] = std['hour'] + ":" + std['minute'] + AMPM;

         if(etd['hour'] > 12){
            AMPM = "p";
            etd['hour'] = etd['hour'] - 12;
         } else if (etd['hour'] == 0){
            AMPM = "a";
            etd['hour'] = "12";
         } else if (etd['hour'] == 12){
            AMPM = "p";
         } else if (etd['hour'].toString().substring(0,1) == "0"){
             etd['hour'] = etd['hour'].toString().substring(1,2);
         }

         etd['t'] = etd['hour'] + ":" + etd['minute'] + AMPM;
         
      }

      if (std['d'] != etd['d']){
         if (std['t'] == "12:00a" && etd['t'] == "11:59p"){
            std['t'] = "";
            etd['t'] = "";
         }

         if(Dsingle){
            // force single line format
            if (std['date'] == ""){
               if (std['month'] != etd['month']) std['month'] = std['month'] + "~" + etd['month'];
            } else {
               if (std['month'] == etd['month']){
                  std['remainDate'] = "~" + etd['date'] + etd['year'];
               } else {
                  std['remainDate'] = "~" + etd['month'] + etd['date'] + etd['year'];
               }               
            }

            if (etd['t'] != ""){
               std['t'] = std['t'] + "~" + etd['t'];
            }
            colspan = 4;
         }else colspan = 5;

         summary = event.title;
         evHTML += "<TR><TD colspan=" + colspan + "><A class='gcalItem' style='color:" + event.color + "; font-weight: bold;' href='" + event.URL   + "' target='_blank'>" + summary + "</A></TD></TR>";
         if (Dlocation && event.location != '') evHTML += "<TR><TD " +   style + "style='color:" + event.colour + ";'" +" colspan=" + colspan + ">&nbsp;" + event.location + "</TD></TR>";

         evHTML += "<TR>" 
                   + "<TD " +   style + " style='color:" + event.colour + ";'>&nbsp;" + std['day'] + "</TD>" 
                   + "<TD " +   style + " style='color:" + event.colour + ";'>" + std['month'] + "</TD>" 
                   + "<TD " +   style + " style='color:" + event.colour + ";'>" + std['date'] + "</TD>";

         if (!Dsingle){
            evHTML += "<TD " +   style + " style='color:" + event.colour + ";'>" + std['year'] + "</TD>";
            evHTML += "<TD " +   style + " width='100%' style='color:" + event.colour + ";'>&nbsp;" + std['t'] + "</TD></TR>";
         } else {
            evHTML += "<TD " +   style + " width='100%' style='color:" + event.colour + ";'>" + std['remainDate'] + "</TD></TR>";
            if (std['t'] != '') evHTML += "<TR><TD " +   style + " colspan=" + colspan + " style='color:" + event.colour + ";'>&nbsp;" + std['t'] + "</TD></TR>";
         }

         if (!Dsingle){
            evHTML += "<TR>" 
                      + "<TD " +   style + " style='color:" + event.colour + ";'>&nbsp;" + etd['day'] + "</TD>" 
                      + "<TD " +   style + " style='color:" + event.colour + ";'>" + etd['month'] + "</TD>" 
                      + "<TD " +   style + " style='color:" + event.colour + ";'>" + etd['date'] + "</TD>" 
                      + "<TD " +   style + " style='color:" + event.colour + ";'>" + etd['year'] + "</TD>"
                      + "<TD " +   style + " width='100%' style='color:" + event.colour + ";'>&nbsp;" + etd['t'] + "</TD></TR>";
         }

      }else{
         if (std['t'] != etd['t'] && std['t'] != '12:00a' && etd['t'] != '11:59p') std['t'] = std['t'] + "~" + etd['t'];
         if (std['t'] == "12:00a") std['t'] = "";

         colspan = (!Dsingle) ? 5 : 6;
         summary = event.title;
         evHTML += "<TR><TD colspan=" + colspan + "><A class='gcalItem' style='color:" + event.colour +"; font-weight: bold;';href='" + event.URL   + "' target='_blank'>" + summary + "</A></TD></TR>";
         if (Dlocation && event.location != '') evHTML += "<TR><TD " +   style + "style='color:" + event.colour + ";'" +" colspan=" + colspan + ">&nbsp;" + event.location + "</TD></TR>";

         evHTML += "<TR>" 
                   + "<TD " +   style + " style='color:" + event.colour + ";'>&nbsp;" + std['day'] + "</TD>" 
                   + "<TD " +   style + " style='color:" + event.colour + ";'>" + std['month'] + "</TD>" 
                   + "<TD " +   style + " style='color:" + event.colour + ";'>" + std['date'] + "</TD>";

         if (!Dsingle){
            evHTML += "<TD " +   style + " style='color:" + event.colour + ";'>" + etd['year'] + "</TD>";
            evHTML += "<TD " +   style + "   width='100%' style='color:" + event.colour + ";'>&nbsp;" + std['t'] + "</TD></TR>";
         } else {
            evHTML += "<TD " +   style + " style='color:" + event.colour + ";'>" + std['year'] + "</TD></TR>";
            if (std['t'] != '') evHTML += "<TR><TD " +   style + " colspan=" + colspan + " style='color:" + event.colour + ";'>&nbsp;" + std['t'] + "</TD></TR>";
         }
          
      }
   
      // style = "valign=top class='" + highlight + "' style='font-size:2pt'";
      // evHTML += "<TR><TD " +   style + " colspan=" + colspan   + ">&nbsp;</TD></TR>";

   }

   evHTML += "</TABLE>";

   if (eCount == 0){
      gcalListDIV.innerHTML = "<B>No Events Found.</B>";
   } else {
      gcalListDIV.innerHTML = evHTML;
   } 
      var blockdisp = getCookie('GMgcal');
      gcalStatusDIV.style.display = 'none';
      gcalListDIV.style.display = 'block';
      gcalEditDIV.style.display = 'block';
      
      if (blockdisp == 0) toggleGcalDIV();
 

}

// --------------------- GMscript functions

function toggleGcalDIV() {
   if (gcalContDIV.style.display != "block"){ 
      setCookie('GMgcal', 1);
      gcalContDIV.style.display = "block";
      gcalTriangleImage.src = "/mail/images/opentriangle.gif";
   } else {
      setCookie('GMgcal', 0);
      gcalContDIV.style.display = "none";
      gcalTriangleImage.src = "/mail/images/triangle.gif";
   }
   return false;
}

function parseDate(TS,debug){
   var parsed = new Array;
   var date = new Date(TS);

   parsed['day'] = date.getDay();
   parsed['month'] = date.getMonth() + 1;
   parsed['date'] = date.getDate();
   parsed['year'] = date.getFullYear();
   parsed['hour'] = date.getHours();
   parsed['minute'] = date.getMinutes();
   parsed['second'] = date.getSeconds();
   if (parsed['hour'].toString().length == 1) parsed['hour'] = '0' + parsed['hour'];
   if (parsed['minute'].toString().length == 1) parsed['minute'] = '0' + parsed['minute'];
   if (parsed['second'].toString().length == 1) parsed['second'] = '0' + parsed['second'];

   //parsed['gmtOffset'] = date.getTimezoneOffset();
   parsed['gmtPosition'] = (parsed['gmtOffset'] > 0) ? "-" : "+";

   if (debug) alert(parsed['day'] + "\n" + parsed['month'] + "\n" + parsed['date'] + "\n" + parsed['year'] + "\n" + parsed['hour'] + "\n" + parsed['minute']);
   return parsed;
}

function TSfromISO(ISO,offset,isEnd){
   // converts date in the format 2006-04-15T20:00:00.000Z to milliseconds since EPOCH
   // works with 2006-04-15 20:00
   var tRE = /(\s|T)([0-9]{2}:[0-9]{2})/;
   var dRE = /([0-9]+)-([0-9]+)-([0-9]+)/;
   var oRE = /(\+|-){1}(.){5}$/;

   var TS;
   var date   = dRE.exec(ISO);
   var time   = tRE.exec(ISO);
   var gmtPosition = nowParse['gmtPosition'];
   var gmtOffset = oRE.exec(ISO);
/*
   var gmtPosition = "+";
   var gmtOffset = oRE.exec(ISO);
   if (gmtOffset && ISO.length > 10) var gmtPosition = gmtOffset[1];
*/

   var timeAdjust = 0;

   if (date){
      if (time){
         time = time[2];
      } else {
         gmtOffset = false;
         offset = 0;
         if (gmtPosition == "+"){
             if (isEnd) {
                timeAdjust = -1;
                time =   "23:59";
             } else time =   "00:00";
         } else {
             if (!isEnd) {
                timeAdjust = 1;
                time =   "00:00";
             } else time =   "23:59";
         }   
      }

      if (gmtOffset){
         gmtOffset = gmtOffset[0];
         offset = 1;
      } else gmtOffset = 0; 
   
      if(date[2].substring(0,1) == "0") date[2] = date[2].substring(1,2);
//      if(date[3].substring(0,1) == "0") date[3] = date[3].substring(1,2);

      TS = new Date(monthA[parseInt(date[2])] + " " + date[3] + " " + date[1] + " " + time);
 
      if (timeAdjust != 0){
         var TTS = TS;
         TS = new Date(TS.getTime() + 24 * 60 * 60 * 1000 * timeAdjust); // add a day based on gmtPosition
         var DSToffset = (TS.getTimezoneOffset() - TTS.getTimezoneOffset()) * 1000 * 60;
         TS = new Date(TS.getTime() - DSToffset);
      }

      TS = (offset == 0) ? TS.getTime() : TS.getTime() - (TS.getTimezoneOffset() * 60 * 1000) - (parseInt(gmtOffset) * 60 * 60 * 1000);

   } else TS = "";

   return TS;
}

// -----------------------------   Resource

function getObjMethodClosure(object, method) {
   // shorthand object reference
   return function(arg) {
      return object[method](arg); 
   }
}

function xpath(pattern){
   // simple xpath parser
   var a_emt = new Array();
   var sshot = document.evaluate(pattern, document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
   if( sshot.snapshotLength > 0){
      for (i=0; i< sshot.snapshotLength; i++){
         a_emt[i] = sshot.snapshotItem(i);
      } 
      return a_emt;
   }
    return null;
}

function setCookie(name, value) {
   var today = new Date();
   var expiry = new Date(today.getTime() + 24 * 60   * 60 * 1000);
                                                                                                                        
   document.cookie = name + "=" + escape(value) 
      + "; expires=" + expiry.toGMTString() 
      + "; path=/";
}

function getCookie(name) {
   var re = new RegExp(name + "=([^;]+)");;
   var value = re.exec(document.cookie);
   return (value != null) ? unescape(value[1]) : null;
}

function cmp(a,b) {
 return (a < b) ? -1 :( a > b) ? 1 : 0;
}

function shrink(text,length,append){
   // shrinks text to length and makes undefined = ''
   // appends append to the end
   if (text){
      // fix IE &apos; issue
      text = text.replace("&apos;","'");
      if (text.length > length) text = text.substring(0,length) + append; 
   } else text = "";

   return text;
}

// ------------------------------ Calendar Object

function CalendarEvent(id,title,startTS,endTS,URL,location,repeatTS,repeatType,repeatInt,repeatByDay, colour){
   this.id = id;
   this.title = title;
   this.URL = URL;
   this.location = location;
   this.colour = colour;
      
   this.startTS = startTS;
   this.endTS = endTS;
   this.duration = parseInt(endTS) - parseInt(startTS);
 
   this.repeatTS = repeatTS;   
   this.repeatType = repeatType;
   this.repeatInt = repeatInt;
   this.repeatByDay = repeatByDay;
}

function addEvent(event){
   // add event if it is in the future
   if (event.endTS >= nowTS) {
	EventList.push(event);
   }
}


// ------------------------------ End Calendar Object


// ----------------- TINYDOM
// =========================================================================
//
// tinyxmldom.js - an XML DOM parser in JavaScript compressed for downloading
//
//   This is the classic DOM that has shipped with XML for <SCRIPT>
//   since the beginning. For a more standards-compliant DOM, you may
//   wish to use the standards-compliant W3C DOM that is included
//   with XML for <SCRIPT> versions 3.0 and above
//
//
// version 3.1
//
// =========================================================================
//
// Copyright (C) 2000 - 2002, 2003 Michael Houghton (mike@idle.org), Raymond Irving and David Joham (djoham@yahoo.com)
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307   USA
//
// Visit the XML for <SCRIPT> home page at http://xmljs.sourceforge.net


var whitespace = "\n\r\t "; var quotes = "\"'"; function convertEscapes(str) { var gt; gt = -1; while (str.indexOf("&lt;", gt + 1) > -1) { var gt = str.indexOf("&lt;", gt + 1); var newStr = str.substr(0, gt); newStr += "<"; newStr = newStr + str.substr(gt + 4, str.length); str = newStr;}
gt = -1; while (str.indexOf("&gt;", gt + 1) > -1) { var gt = str.indexOf("&gt;", gt + 1); var newStr = str.substr(0, gt); newStr += ">"; newStr = newStr + str.substr(gt + 4, str.length); str = newStr;}
gt = -1; while (str.indexOf("&amp;", gt + 1) > -1) { var gt = str.indexOf("&amp;", gt + 1); var newStr = str.substr(0, gt); newStr += "&"; newStr = newStr + str.substr(gt + 5, str.length); str = newStr;}
return str;}
function convertToEscapes(str) { var gt = -1; while (str.indexOf("&", gt + 1) > -1) { gt = str.indexOf("&", gt + 1); var newStr = str.substr(0, gt); newStr += "&amp;"; newStr = newStr + str.substr(gt + 1, str.length); str = newStr;}
gt = -1; while (str.indexOf("<", gt + 1) > -1) { var gt = str.indexOf("<", gt + 1); var newStr = str.substr(0, gt); newStr += "&lt;"; newStr = newStr + str.substr(gt + 1, str.length); str = newStr;}
gt = -1; while (str.indexOf(">", gt + 1) > -1) { var gt = str.indexOf(">", gt + 1); var newStr = str.substr(0, gt); newStr += "&gt;"; newStr = newStr + str.substr(gt + 1, str.length); str = newStr;}
return str;}
function _displayElement(domElement, strRet) { if(domElement==null) { return;}
if(!(domElement.nodeType=='ELEMENT')) { return;}
var tagName = domElement.tagName; var tagInfo = ""; tagInfo = "<" + tagName; var attributeList = domElement.getAttributeNames(); for(var intLoop = 0; intLoop < attributeList.length; intLoop++) { var attribute = attributeList[intLoop]; tagInfo = tagInfo + " " + attribute + "="; tagInfo = tagInfo + "\"" + domElement.getAttribute(attribute) + "\"";}
tagInfo = tagInfo + ">"; strRet=strRet+tagInfo; if(domElement.children!=null) { var domElements = domElement.children; for(var intLoop = 0; intLoop < domElements.length; intLoop++) { var childNode = domElements[intLoop]; if(childNode.nodeType=='COMMENT') { strRet = strRet + "<!--" + childNode.content + "-->";}
else if(childNode.nodeType=='TEXT') { var cont = trim(childNode.content,true,true); strRet = strRet + childNode.content;}
else if (childNode.nodeType=='CDATA') { var cont = trim(childNode.content,true,true); strRet = strRet + "&lt;![CDATA[" + cont + "]]&gt;";}
else { strRet = _displayElement(childNode, strRet);}
}
}
strRet = strRet + "</" + tagName + ">"; return strRet;}
function firstWhiteChar(str,pos) { if (isEmpty(str)) { return -1;}
while(pos < str.length) { if (whitespace.indexOf(str.charAt(pos))!=-1) { return pos;}
else { pos++;}
}
return str.length;}
function isEmpty(str) { return (str==null) || (str.length==0);}
function trim(trimString, leftTrim, rightTrim) { if (isEmpty(trimString)) { return "";}
if (leftTrim == null) { leftTrim = true;}
if (rightTrim == null) { rightTrim = true;}
var left=0; var right=0; var i=0; var k=0; if (leftTrim == true) { while ((i<trimString.length) && (whitespace.indexOf(trimString.charAt(i++))!=-1)) { left++;}
}
if (rightTrim == true) { k=trimString.length-1; while((k>=left) && (whitespace.indexOf(trimString.charAt(k--))!=-1)) { right++;}
}
return trimString.substring(left, trimString.length - right);}
function XMLDoc(source, errFn) { this.topNode=null; this.errFn = errFn; this.createXMLNode = _XMLDoc_createXMLNode; this.error = _XMLDoc_error; this.getUnderlyingXMLText = _XMLDoc_getUnderlyingXMLText; this.handleNode = _XMLDoc_handleNode; this.hasErrors = false; this.insertNodeAfter = _XMLDoc_insertNodeAfter; this.insertNodeInto = _XMLDoc_insertNodeInto; this.loadXML = _XMLDoc_loadXML; this.parse = _XMLDoc_parse; this.parseAttribute = _XMLDoc_parseAttribute; this.parseDTD = _XMLDoc_parseDTD; this.parsePI = _XMLDoc_parsePI; this.parseTag = _XMLDoc_parseTag; this.removeNodeFromTree = _XMLDoc_removeNodeFromTree; this.replaceNodeContents = _XMLDoc_replaceNodeContents; this.selectNode = _XMLDoc_selectNode; this.selectNodeText = _XMLDoc_selectNodeText; this.source = source; if (this.parse()) { if (this.topNode!=null) { return this.error("expected close " + this.topNode.tagName);}
else { return true;}
}
}
function _XMLDoc_createXMLNode(strXML) { return new XMLDoc(strXML, this.errFn).docNode;}
function _XMLDoc_error(str) { this.hasErrors=true; if(this.errFn){ this.errFn("ERROR: " + str);}else if(this.onerror){ this.onerror("ERROR: " + str);}
return 0;}
function _XMLDoc_getTagNameParams(tag,obj){ var elm=-1,e,s=tag.indexOf('['); var attr=[]; if(s>=0){ e=tag.indexOf(']'); if(e>=0)elm=tag.substr(s+1,(e-s)-1); else obj.error('expected ] near '+tag); tag=tag.substr(0,s); if(isNaN(elm) && elm!='*'){ attr=elm.substr(1,elm.length-1); attr=attr.split('='); if(attr[1]) { s=attr[1].indexOf('"'); attr[1]=attr[1].substr(s+1,attr[1].length-1); e=attr[1].indexOf('"'); if(e>=0) attr[1]=attr[1].substr(0,e); else obj.error('expected " near '+tag)
};elm=-1;}else if(elm=='*') elm=-1;}
return [tag,elm,attr[0],attr[1]]
}
function _XMLDoc_getUnderlyingXMLText() { var strRet = ""; strRet = strRet + "<?xml version=\"1.0\"?>"; if (this.docNode==null) { return;}
strRet = _displayElement(this.docNode, strRet); return strRet;}
function _XMLDoc_handleNode(current) { if ((current.nodeType=='COMMENT') && (this.topNode!=null)) { return this.topNode.addElement(current);}
else if ((current.nodeType=='TEXT') || (current.nodeType=='CDATA')) { if(this.topNode==null) { if (trim(current.content,true,false)=="") { return true;}
else { return this.error("expected document node, found: " + current);}
}
else { return this.topNode.addElement(current);}
}
else if ((current.nodeType=='OPEN') || (current.nodeType=='SINGLE')) { var success = false; if(this.topNode==null) { this.docNode = current; current.parent = null; success = true;}
else { success = this.topNode.addElement(current);}
if (success && (current.nodeType!='SINGLE')) { this.topNode = current;}
current.nodeType = "ELEMENT"; return success;}
else if (current.nodeType=='CLOSE') { if (this.topNode==null) { return this.error("close tag without open: " + current.toString());}
else { if (current.tagName!=this.topNode.tagName) { return this.error("expected closing " + this.topNode.tagName + ", found closing " + current.tagName);}
else { this.topNode = this.topNode.getParent();}
}
}
return true;}
function _XMLDoc_insertNodeAfter (referenceNode, newNode) { var parentXMLText = this.getUnderlyingXMLText(); var selectedNodeXMLText = referenceNode.getUnderlyingXMLText(); var originalNodePos = parentXMLText.indexOf(selectedNodeXMLText) + selectedNodeXMLText.length; var newXML = parentXMLText.substr(0,originalNodePos); newXML += newNode.getUnderlyingXMLText(); newXML += parentXMLText.substr(originalNodePos); var newDoc = new XMLDoc(newXML, this.errFn); return newDoc;}
function _XMLDoc_insertNodeInto (referenceNode, insertNode) { var parentXMLText = this.getUnderlyingXMLText(); var selectedNodeXMLText = referenceNode.getUnderlyingXMLText(); var endFirstTag = selectedNodeXMLText.indexOf(">") + 1; var originalNodePos = parentXMLText.indexOf(selectedNodeXMLText) + endFirstTag; var newXML = parentXMLText.substr(0,originalNodePos); newXML += insertNode.getUnderlyingXMLText(); newXML += parentXMLText.substr(originalNodePos); var newDoc = new XMLDoc(newXML, this.errFn); return newDoc;}
function _XMLDoc_loadXML(source){ this.topNode=null; this.hasErrors = false; this.source=source; return this.parse();}
function _XMLDoc_parse() { var pos = 0; err = false; while(!err) { var closing_tag_prefix = ''; var chpos = this.source.indexOf('<',pos); var open_length = 1; var open; var close; if (chpos ==-1) { break;}
open = chpos; var str = this.source.substring(pos, open); if (str.length!=0) { err = !this.handleNode(new XMLNode('TEXT',this, str));}
if (chpos == this.source.indexOf("<?",pos)) { pos = this.parsePI(this.source, pos + 2); if (pos==0) { err=true;}
continue;}
if (chpos == this.source.indexOf("<!DOCTYPE",pos)) { pos = this.parseDTD(this.source, chpos+ 9); if (pos==0) { err=true;}
continue;}
if(chpos == this.source.indexOf('<!--',pos)) { open_length = 4; closing_tag_prefix = '--';}
if (chpos == this.source.indexOf('&lt;![CDATA[',pos)) { open_length = 9; closing_tag_prefix = ']]';}
chpos = this.source.indexOf(closing_tag_prefix + '>',chpos); if (chpos ==-1) { return this.error("expected closing tag sequence: " + closing_tag_prefix + '>');}
close = chpos + closing_tag_prefix.length; str = this.source.substring(open+1, close); var n = this.parseTag(str); if (n) { err = !this.handleNode(n);}
pos = close +1;}
return !err;}
function _XMLDoc_parseAttribute(src,pos,node) { while ((pos<src.length) && (whitespace.indexOf(src.charAt(pos))!=-1)) { pos++;}
if (pos >= src.length) { return pos;}
var p1 = pos; while ((pos < src.length) && (src.charAt(pos)!='=')) { pos++;}
var msg = "attributes must have values"; if(pos >= src.length) { return this.error(msg);}
var paramname = trim(src.substring(p1,pos++),false,true); while ((pos < src.length) && (whitespace.indexOf(src.charAt(pos))!=-1)) { pos++;}
if (pos >= src.length) { return this.error(msg);}
msg = "attribute values must be in quotes"; var quote = src.charAt(pos++); if (quotes.indexOf(quote)==-1) { return this.error(msg);}
p1 = pos; while ((pos < src.length) && (src.charAt(pos)!=quote)) { pos++;}
if (pos >= src.length) { return this.error(msg);}
if (!node.addAttribute(paramname,trim(src.substring(p1,pos++),false,true))) { return 0;}
return pos;}
function _XMLDoc_parseDTD(str,pos) { var firstClose = str.indexOf('>',pos); if (firstClose==-1) { return this.error("error in DTD: expected '>'");}
var closing_tag_prefix = ''; var firstOpenSquare = str.indexOf('[',pos); if ((firstOpenSquare!=-1) && (firstOpenSquare < firstClose)) { closing_tag_prefix = ']';}
while(true) { var closepos = str.indexOf(closing_tag_prefix + '>',pos); if (closepos ==-1) { return this.error("expected closing tag sequence: " + closing_tag_prefix + '>');}
pos = closepos + closing_tag_prefix.length +1; if (str.substring(closepos-1,closepos+2) != ']]&gt;') { break;}
}
return pos;}
function _XMLDoc_parsePI(str,pos) { var closepos = str.indexOf('?>',pos); return closepos + 2;}
function _XMLDoc_parseTag(src) { if (src.indexOf('!--')==0) { return new XMLNode('COMMENT', this, src.substring(3,src.length-2));}
if (src.indexOf('![CDATA[')==0) { return new XMLNode('CDATA', this, src.substring(8,src.length-2));}
var n = new XMLNode(); n.doc = this; if (src.charAt(0)=='/') { n.nodeType = 'CLOSE'; src = src.substring(1);}
else { n.nodeType = 'OPEN';}
if (src.charAt(src.length-1)=='/') { if (n.nodeType=='CLOSE') { return this.error("singleton close tag");}
else { n.nodeType = 'SINGLE';}
src = src.substring(0,src.length-1);}
if (n.nodeType!='CLOSE') { n.attributes = new Array();}
if (n.nodeType=='OPEN') { n.children = new Array();}
src = trim(src,true,true); if (src.length==0) { return this.error("empty tag");}
var endOfName = firstWhiteChar(src,0); if (endOfName==-1) { n.tagName = src; return n;}
n.tagName = src.substring(0,endOfName); var pos = endOfName; while(pos< src.length) { pos = this.parseAttribute(src, pos, n); if (this.pos==0) { return null;}
}
return n;}
function _XMLDoc_removeNodeFromTree(node) { var parentXMLText = this.getUnderlyingXMLText(); var selectedNodeXMLText = node.getUnderlyingXMLText(); var originalNodePos = parentXMLText.indexOf(selectedNodeXMLText); var newXML = parentXMLText.substr(0,originalNodePos); newXML += parentXMLText.substr(originalNodePos + selectedNodeXMLText.length); var newDoc = new XMLDoc(newXML, this.errFn); return newDoc;}
function _XMLDoc_replaceNodeContents(referenceNode, newContents) { var newNode = this.createXMLNode("<X>" + newContents + "</X>"); referenceNode.children = newNode.children; return this;}
function _XMLDoc_selectNode(tagpath){ tagpath = trim(tagpath, true, true); var srcnode,node,tag,params,elm,rg; var tags,attrName,attrValue,ok; srcnode=node=((this.source)?this.docNode:this); if (!tagpath) return node; if(tagpath.indexOf('/')==0)tagpath=tagpath.substr(1); tagpath=tagpath.replace(tag,''); tags=tagpath.split('/'); tag=tags[0]; if(tag){ if(tagpath.indexOf('/')==0)tagpath=tagpath.substr(1); tagpath=tagpath.replace(tag,''); params=_XMLDoc_getTagNameParams(tag,this); tag=params[0];elm=params[1]; attrName=params[2];attrValue=params[3]; node=(tag=='*')? node.getElements():node.getElements(tag); if (node.length) { if(elm<0){ srcnode=node;var i=0; while(i<srcnode.length){ if(attrName){ if (srcnode[i].getAttribute(attrName)!=attrValue) ok=false; else ok=true;}else ok=true; if(ok){ node=srcnode[i].selectNode(tagpath); if(node) return node;}
i++;}
}else if (elm<node.length){ node=node[elm].selectNode(tagpath); if(node) return node;}
}
}
}
function _XMLDoc_selectNodeText(tagpath){ var node=this.selectNode(tagpath); if (node != null) { return node.getText();}
else { return null;}
}
function XMLNode(nodeType,doc, str) { if (nodeType=='TEXT' || nodeType=='CDATA' || nodeType=='COMMENT' ) { this.content = str;}
else { this.content = null;}
this.attributes = null; this.children = null; this.doc = doc; this.nodeType = nodeType; this.parent = ""; this.tagName = ""; this.addAttribute = _XMLNode_addAttribute; this.addElement = _XMLNode_addElement; this.getAttribute = _XMLNode_getAttribute; this.getAttributeNames = _XMLNode_getAttributeNames; this.getElementById = _XMLNode_getElementById; this.getElements = _XMLNode_getElements; this.getText = _XMLNode_getText; this.getParent = _XMLNode_getParent; this.getUnderlyingXMLText = _XMLNode_getUnderlyingXMLText; this.removeAttribute = _XMLNode_removeAttribute; this.selectNode = _XMLDoc_selectNode; this.selectNodeText = _XMLDoc_selectNodeText; this.toString = _XMLNode_toString;}
function _XMLNode_addAttribute(attributeName,attributeValue) { this.attributes['_' + attributeName] = attributeValue; return true;}
function _XMLNode_addElement(node) { node.parent = this; this.children[this.children.length] = node; return true;}
function _XMLNode_getAttribute(name) { if (this.attributes == null) { return null;}
return this.attributes['_' + name];}
function _XMLNode_getAttributeNames() { if (this.attributes == null) { var ret = new Array(); return ret;}
var attlist = new Array(); for (var a in this.attributes) { attlist[attlist.length] = a.substring(1);}
return attlist;}
function _XMLNode_getElementById(id) { var node = this; var ret; if (node.getAttribute("id") == id) { return node;}
else{ var elements = node.getElements(); var intLoop = 0; while (intLoop < elements.length) { var element = elements[intLoop]; ret = element.getElementById(id); if (ret != null) { break;}
intLoop++;}
}
return ret;}
function _XMLNode_getElements(byName) { if (this.children==null) { var ret = new Array(); return ret;}
var elements = new Array(); for (var i=0; i<this.children.length; i++) { if ((this.children[i].nodeType=='ELEMENT') && ((byName==null) || (this.children[i].tagName == byName))) { elements[elements.length] = this.children[i];}
}
return elements;}
function _XMLNode_getText() { if (this.nodeType=='ELEMENT') { if (this.children==null) { return null;}
var str = ""; for (var i=0; i < this.children.length; i++) { var t = this.children[i].getText(); str += (t == null ? "" : t);}
return str;}
else if (this.nodeType=='TEXT') { return convertEscapes(this.content);}
else { return this.content;}
}
function _XMLNode_getParent() { return this.parent;}
function _XMLNode_getUnderlyingXMLText() { var strRet = ""; strRet = _displayElement(this, strRet); return strRet;}
function _XMLNode_removeAttribute(attributeName) { if(attributeName == null) { return this.doc.error("You must pass an attribute name into the removeAttribute function");}
var attributes = this.getAttributeNames(); var intCount = attributes.length; var tmpAttributeValues = new Array(); for ( intLoop = 0; intLoop < intCount; intLoop++) { tmpAttributeValues[intLoop] = this.getAttribute(attributes[intLoop]);}
this.attributes = new Array(); for (intLoop = 0; intLoop < intCount; intLoop++) { if ( attributes[intLoop] != attributeName) { this.addAttribute(attributes[intLoop], tmpAttributeValues[intLoop]);}
}
return true;}
function _XMLNode_toString() { return "" + this.nodeType + ":" + (this.nodeType=='TEXT' || this.nodeType=='CDATA' || this.nodeType=='COMMENT' ? this.content : this.tagName);}
}) (); // end function enclosure