/* SpryMenuBar.js - Revision: Spry Preview Release 1.4 */

// Copyright (c) 2006. Adobe Systems Incorporated.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

/*******************************************************************************

 SpryMenuBar.js
 This file handles the JavaScript for Spry Menu Bar.  You should have no need
 to edit this file.  Some highlights of the MenuBar object is that timers are
 used to keep submenus from showing up until the user has hovered over the parent
 menu item for some time, as well as a timer for when they leave a submenu to keep
 showing that submenu until the timer fires.

 *******************************************************************************/

var Spry;
if(!Spry)
{
	Spry = {};
}
if(!Spry.Widget)
{
	Spry.Widget = {};
}

// Constructor for Menu Bar
// element should be an ID of an unordered list (<ul> tag)
// preloadImage1 and preloadImage2 are images for the rollover state of a menu
Spry.Widget.MenuBar = function(element, opts)
{
	this.init(element, opts);
};

Spry.Widget.MenuBar.prototype.init = function(element, opts)
{
	this.element = this.getElement(element);

	// represents the current (sub)menu we are operating on
	this.currMenu = null;

	var isie = (typeof document.all != 'undefined' && typeof window.opera == 'undefined' && navigator.vendor != 'KDE');
	if(typeof document.getElementById == 'undefined' || (navigator.vendor == 'Apple Computer, Inc.' && typeof window.XMLHttpRequest == 'undefined') || (isie && typeof document.uniqueID == 'undefined'))
	{
		// bail on older unsupported browsers
		return;
	}

	// load hover images now
	if(opts)
	{
		for(var k in opts)
		{
			var rollover = new Image;
			rollover.src = opts[k];
		}
	}

	if(this.element)
	{
		this.currMenu = this.element;
		var items = this.element.getElementsByTagName('li');
		for(var i=0; i<items.length; i++)
		{
			this.initialize(items[i], element, isie);
			if(isie)
			{
				this.addClassName(items[i], "MenuBarItemIE");
				items[i].style.position = "static";
			}
		}
		if(isie)
		{
			if(this.hasClassName(this.element, "MenuBarVertical"))
			{
				this.element.style.position = "relative";
			}
			var linkitems = this.element.getElementsByTagName('a');
			for(var i=0; i<linkitems.length; i++)
			{
				linkitems[i].style.position = "relative";
			}
		}
	}
};

Spry.Widget.MenuBar.prototype.getElement = function(ele)
{
	if (ele && typeof ele == "string")
		return document.getElementById(ele);
	return ele;
};

Spry.Widget.MenuBar.prototype.hasClassName = function(ele, className)
{
	if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)
	{
		return false;
	}
	return true;
};

Spry.Widget.MenuBar.prototype.addClassName = function(ele, className)
{
	if (!ele || !className || this.hasClassName(ele, className))
		return;
	ele.className += (ele.className ? " " : "") + className;
};

Spry.Widget.MenuBar.prototype.removeClassName = function(ele, className)
{
	if (!ele || !className || !this.hasClassName(ele, className))
		return;
	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
};

// addEventListener for Menu Bar
// attach an event to a tag without creating obtrusive HTML code
Spry.Widget.MenuBar.prototype.addEventListener = function(element, eventType, handler, capture)
{
	try
	{
		if (element.addEventListener)
		{
			element.addEventListener(eventType, handler, capture);
		}
		else if (element.attachEvent)
		{
			element.attachEvent('on' + eventType, handler);
		}
	}
	catch (e) {}
};

// createIframeLayer for Menu Bar
// creates an IFRAME underneath a menu so that it will show above form controls and ActiveX
Spry.Widget.MenuBar.prototype.createIframeLayer = function(menu)
{
	var layer = document.createElement('iframe');
	layer.tabIndex = '-1';
	layer.src = 'javascript:false;';
	menu.parentNode.appendChild(layer);
	
	layer.style.left = menu.offsetLeft + 'px';
	layer.style.top = menu.offsetTop + 'px';
	layer.style.width = menu.offsetWidth + 'px';
	layer.style.height = menu.offsetHeight + 'px';
};

// removeIframeLayer for Menu Bar
// removes an IFRAME underneath a menu to reveal any form controls and ActiveX
Spry.Widget.MenuBar.prototype.removeIframeLayer =  function(menu)
{
	var layers = menu.parentNode.getElementsByTagName('iframe');
	while(layers.length > 0)
	{
		layers[0].parentNode.removeChild(layers[0]);
	}
};

// clearMenus for Menu Bar
// root is the top level unordered list (<ul> tag)
Spry.Widget.MenuBar.prototype.clearMenus = function(root)
{
	var menus = root.getElementsByTagName('ul');
	for(var i=0; i<menus.length; i++)
	{
		this.hideSubmenu(menus[i]);
	}
	this.removeClassName(this.element, "MenuBarActive");
};

// bubbledTextEvent for Menu Bar
// identify bubbled up text events in Safari so we can ignore them
Spry.Widget.MenuBar.prototype.bubbledTextEvent = function()
{
	return (navigator.vendor == 'Apple Computer, Inc.' && (event.target == event.relatedTarget.parentNode || (event.eventPhase == 3 && event.target.parentNode == event.relatedTarget)));
};

// showSubmenu for Menu Bar
// set the proper CSS class on this menu to show it
Spry.Widget.MenuBar.prototype.showSubmenu = function(menu)
{
	if(this.currMenu)
	{
		this.clearMenus(this.currMenu);
		this.currMenu = null;
	}
	
	if(menu)
	{
		this.addClassName(menu, "MenuBarSubmenuVisible");
		if(typeof document.all != 'undefined' && typeof window.opera == 'undefined' && navigator.vendor != 'KDE')
		{
			if(!this.hasClassName(this.element, "MenuBarHorizontal") || menu.parentNode.parentNode != this.element)
			{
				menu.style.top = menu.parentNode.offsetTop + 'px';
			}
		}
		if(typeof document.uniqueID != "undefined")
		{
			this.createIframeLayer(menu);
		}
	}
	this.addClassName(this.element, "MenuBarActive");
};

// hideSubmenu for Menu Bar
// remove the proper CSS class on this menu to hide it
Spry.Widget.MenuBar.prototype.hideSubmenu = function(menu)
{
	if(menu)
	{
		this.removeClassName(menu, "MenuBarSubmenuVisible");
		if(typeof document.all != 'undefined' && typeof window.opera == 'undefined' && navigator.vendor != 'KDE')
		{
			menu.style.top = '';
			menu.style.left = '';
		}
		this.removeIframeLayer(menu);
	}
};

// initialize for Menu Bar
// create event listeners for the Menu Bar widget so we can properly
// show and hide submenus
Spry.Widget.MenuBar.prototype.initialize = function(listitem, element, isie)
{
	var opentime, closetime;
	var link = listitem.getElementsByTagName('a')[0];
	var submenus = listitem.getElementsByTagName('ul');
	var menu = (submenus.length > 0 ? submenus[0] : null);

	var hasSubMenu = false;
	if(menu)
	{
		this.addClassName(link, "MenuBarItemSubmenu");
		hasSubMenu = true;
	}

	if(!isie)
	{
		// define a simple function that comes standard in IE to determine
		// if a node is within another node
		listitem.contains = function(testNode)
		{
			// this refers to the list item
			if(testNode == null)
			{
				return false;
			}
			if(testNode == this)
			{
				return true;
			}
			else
			{
				return this.contains(testNode.parentNode);
			}
		};
	}
	
	// need to save this for scope further down
	var self = this;

	this.addEventListener(listitem, 'mouseover', function(e)
	{
		if(self.bubbledTextEvent())
		{
			// ignore bubbled text events
			return;
		}
		clearTimeout(closetime);
		if(self.currMenu == listitem)
		{
			self.currMenu = null;
		}
		// show menu highlighting
		self.addClassName(link, hasSubMenu ? "MenuBarItemSubmenuHover" : "MenuBarItemHover");
		if(menu && !self.hasClassName(menu, "MenuBarSubmenuVisible"))
		{
			opentime = window.setTimeout(function(){self.showSubmenu(menu);}, 250);
		}
	}, false);

	this.addEventListener(listitem, 'mouseout', function(e)
	{
		if(self.bubbledTextEvent())
		{
			// ignore bubbled text events
			return;
		}

		var related = (typeof e.relatedTarget != 'undefined' ? e.relatedTarget : e.toElement);
		if(!listitem.contains(related))
		{
			clearTimeout(opentime);
			self.currMenu = listitem;

			// remove menu highlighting
			self.removeClassName(link, hasSubMenu ? "MenuBarItemSubmenuHover" : "MenuBarItemHover");
			if(menu)
			{
				closetime = window.setTimeout(function(){self.hideSubmenu(menu);}, 1200);
			}
		}
	}, false);
};
















/*
Pungo Spell Copyright (c) 2003 Billy Cook, Barry Johnson

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/


// Public functions --------------------------------

// spellCheck - spell check a field
function spellCheck( formName, fieldName, spelltext ) {

   var h_spellform = document.forms['spell_form'];
   h_spellform.spell_formname.value = formName;
   h_spellform.spell_fieldname.value = fieldName;
   h_spellform.spellstring.value = document.forms[formName][fieldName].value;
   openSpellWin(640, 480);
   h_spellform.submit();
   return true;
}

// Private functions -------------------------------

// globals
var wordindex = -1;
var offsetindex = 0;
var ignoredWords = Array();

// mispelled word object
//
function misp(word, start, end, suggestions) {
   this.word = word;               // the word
   this.start = start;             // start index
   this.end = end;                 // end index
   this.suggestions = suggestions; // array of suggestions
}

// replace the word in the misps array at the "wordindex" index.  The
// misps array is generated by a PHP script after the string to be spell
// checked is evaluated with pspell
//
function replaceWord() {
   var frm = document.fm1;
   var strstart = '';
   var strend;

   // if this isn't the beginning of the string then get all of the string
   // that is before the word we are replacing
   if ( misps[ wordindex ].start != 0 )
       strstart = mispstr.slice( 0, misps[ wordindex ].start + offsetindex);

   // get the end of the string after the word we are replacing
   strend = mispstr.slice( misps[ wordindex ].end + 1 + offsetindex);
  
   // rebuild the string with the new word
   mispstr = strstart +  frm.changeto.value  + strend;

   // update offsetindex to compensate for replacing a word with a word
   // of a different length.
   offsetindex += frm.changeto.value.length - misps[ wordindex ].word.length;

   // update the word so future replaceAll calls don't change it
   misps[ wordindex ].word = frm.changeto.value;

   nextWord(false);
}

// replaces all instances of currently selected word with contents chosen by user. 
// note: currently only replaces words after hilighted word.  I think we can re-index
// all words at replacement or ignore time to have it wrap to the beginning if we want
// to.
//
function replaceAll() {
   var frm = document.fm1;
   var strstart = '';
   var strend;
   var idx;
   var origword;
   var localoffsetindex = offsetindex;

   origword = misps[ wordindex ].word;

   // reindex everything past the current word
   for (idx = wordindex; idx < misps.length; idx++) {
      misps[ idx ].start += localoffsetindex;
      misps[ idx ].end += localoffsetindex;
   }

   // testing
   localoffsetindex = 0;

   for (idx = 0; idx < misps.length; idx++) {

      if (misps[ idx ].word == origword) {
         if ( misps[ idx ].start != 0 )
            strstart = mispstr.slice( 0, misps[ idx ].start + localoffsetindex);
   
   
         // get the end of the string after the word we are replacing
         strend = mispstr.slice( misps[ idx ].end + 1 + localoffsetindex);
        
         // rebuild the string with the new word
         mispstr = strstart +  frm.changeto.value  + strend;
      
         // update offsetindex to compensate for replacing a word with a word
         // of a different length.
         localoffsetindex += frm.changeto.value.length - misps[ idx ].word.length;

      }
      // we have to re-index everything after replacements
      misps[ idx ].start += localoffsetindex;
      misps[ idx ].end += localoffsetindex;
   }

   // add the word to the ignore array
   ignoredWords[ origword ] = 1;

   // reset offsetindex since we reindexed
   offsetindex = 0;

   nextWord(false);
}

// hilight the word that was selected using the nextWord function
//
function hilightWord() {
   var strstart = '';
   var strend;

   // if this isn't the beginning of the string then get all of the string
   // that is before the word we are replacing

   if ( misps[ wordindex ].start != 0 )
       strstart = mispstr.slice( 0, misps[ wordindex ].start + offsetindex);

   // get the end of the string after the word we are replacing

   strend = mispstr.slice( misps[ wordindex ].end + 1 + offsetindex);

   // rebuild the string with a span wrapped around the misspelled word 
   // so we can hilight it in the div the user is viewing the string in


   //var divptr = document.getElementById("strview");
   var divptr = iFrameBody;

   divptr.innerHTML = '';
   divptr.innerHTML = strstart;

   divptr.innerHTML +=  "<span class='hilight' id='h1'>" + misps[ wordindex ].word + "</span>" + htmlToText(strend);
   
   //if (document.getElementById("h1").scrollIntoView)
      //document.getElementById("h1").scrollIntoView();

   divptr.innerHTML = divptr.innerHTML.replace(/_\|_/g, "<br>");
}


// called by onLoad handler to start the process of evaluating misspelled
// words
//
function startsp() {
   nextWord(false);
}

function getCorrectedText() {
   return mispstr;
}

// display the next misspelled word to the user and populate the suggested
// spellings box
//
function nextWord(ignoreall) {
   var frm = document.fm1;
   var sug = document.fm1.suggestions;
   var sugidx = 0;
   var newopt;
   var isselected = 0;

   // push ignored word onto ingoredWords array
   if (ignoreall)
      ignoredWords[ misps[ wordindex ].word ] = 1;

   // update the index of all words we have processed
   // This must be done to accomodate the replaceAll function.
   if (wordindex >= 0) {
      misps[ wordindex ].start += offsetindex;
      misps[ wordindex ].end += offsetindex;
   }

   // increment the counter for the array of misspelled words
   wordindex++;

 

   // draw it and quit if there are no more misspelled words to evaluate
   if (misps.length <= wordindex) {
      iFrameBody.innerHTML = mispstr;
      iFrameBody.innerHTML = iFrameBody.innerHTML.replace(/_\|_/g, "<br>");
      
      clearBox( sug );
      alert('Spell checking complete.');
      frm.change.disabled = true;
      frm.changeall.disabled = true;
      frm.ignore.disabled = true;
      frm.ignoreall.disabled = true;

      // put line feeds back
      mispstr = mispstr.replace(/_\|_/g, "\n");

      // get a handle to the field we need to re-populate
      window.opener.document.forms[spell_formname][spell_fieldname].value = mispstr;
      window.close();
      return true;
   }


   // check to see if word is supposed to be ignored
   if (ignoredWords[ misps[ wordindex ].word ] == 1) {
       nextWord(false);
       return;
   }

   // clear out the suggestions box
   clearBox( sug );

   // re-populate the suggestions box if there are any suggested spellings for the word
   if (misps[ wordindex ].suggestions.length) {
      for (sugidx = 0; sugidx < misps[ wordindex ].suggestions.length; sugidx++) {
         if (sugidx == 0)
            isselected = 1;
         else
            isselected = 0;
         newopt = new Option(misps[ wordindex ].suggestions[sugidx], misps[ wordindex ].suggestions[sugidx], 0, isselected); 
         sug.options[ sugidx ] = newopt;

         if (isselected) {
            frm.changeto.value = misps[ wordindex ].suggestions[sugidx];
            frm.changeto.select();
         }
      }
   }
   hilightWord();
}

function htmlToText(thetext) {
   // disable for now
   return thetext;

   var re = /\</g;
   var re2 = /\>/g;
   var re3 = /\n/g;
   var re4 = /\ /g;
   
   thetext = thetext.replace(re, "&lt;");                          
   thetext = thetext.replace(re2, "&gt;");
   thetext = thetext.replace(re3, "<br>");
   thetext = thetext.replace(re4, "&nbsp;");

   return thetext;
}

// remove all items from the suggested spelling box
// 
function clearBox( box ) {
  var length = box.length;

  // delete old options -- rememeber that select
  //                       boxes automatically re-index
  for (i = 0; i < length; i++) {
     box.options[0] = null;
  }
}

function openSpellWin(width, height) {
  window.open("", "spellWindow", 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=no,width='+width+',height='+height+'\'');
}


