Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/interfaceConfig.xml
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/interfaceConfig.xml	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/interfaceConfig.xml	(revision 24065)
@@ -0,0 +1,186 @@
+<interfaceConfig>
+  <actionList>
+    <action name='p' class='PageAction'>
+      <subaction name='home' xslt='home.xsl'/>
+      <subaction name='about' xslt='about.xsl'/>
+      <subaction name='help' xslt='help.xsl'/>
+      <subaction name='pref' xslt='pref.xsl'/>
+      <subaction name='gli4gs3' xslt='gli4gs3.xsl'/>
+      <subaction name='nav' xslt='nav.xsl'/><!-- used for the collection header frame -->
+      <subaction name="html" xslt="html.xsl"/> <!-- use to put an external page into a frame with a collection header-->
+    </action>
+    <action name='q' class='QueryAction' xslt='query.xsl'/>
+    <action name='b' class='GS2BrowseAction' xslt='classifier.xsl'/>
+    <action name='a' class='AppletAction' xslt='applet.xsl'/>
+    <action name='d' class='DocumentAction' xslt='document.xsl'/>
+    <action name='xd' class='XMLDocumentAction'>
+      <subaction name='toc' xslt='document-toc.xsl'/>
+      <subaction name='text' xslt='document-content.xsl'/>
+    </action>
+    <action name='pr' class='ProcessAction' xslt='process.xsl'/>
+    <action name='s' class='SystemAction' xslt='system.xsl'/>
+    <action name='g' class='GeneralAction'>
+      <subaction name="authen" xslt='authen.xsl'/>
+      <subaction name="berry" xslt='berry.xsl'/>
+    </action>
+  </actionList>
+  <languageList>
+    <language name="en">
+      <displayItem name='name'>English</displayItem>
+    </language>
+    <language name="fr">
+      <displayItem name='name'>FranÃ§ais</displayItem>
+    </language>
+    <language name='es'>
+      <displayItem name='name'>EspaÃ±ol</displayItem>
+    </language>
+    <language name="jp">
+      <displayItem name='name'>ã«ã»ãã</displayItem>
+    </language>
+    <language name="vi">
+      <displayItem name='name'>Vietnamese</displayItem>
+    </language>
+    <language name='ar'>
+      <displayItem name='name'>Arabic</displayItem>
+    </language>
+  	<language name='bg'>
+      <displayItem name='name'>Bulgarian</displayItem>
+    </language>
+  	<language name='bn'>
+      <displayItem name='name'>àŠ¬àŠŸàŠàŠ²àŠŸ (Bengali)</displayItem>
+    </language>
+  	<language name='ca'>
+      <displayItem name='name'>CatalÃ  (Catalan)</displayItem>
+    </language>
+  	<language name='cs'>
+      <displayItem name='name'>Äesky (Czech)</displayItem>
+    </language>
+  	<language name='de'>
+      <displayItem name='name'>Deutsch (German)</displayItem>
+    </language>
+  	<language name='el'>
+      <displayItem name='name'>ÎÎ»Î»Î·ÎœÎ¹ÎºÎ¬ (Greek)</displayItem>
+    </language>
+    <language name='fa'>
+      <displayItem name='name'>Farsi</displayItem>
+    </language>
+    <language name='fi'>
+      <displayItem name='name'>Finnish</displayItem>
+    </language>
+    <language name='gd'>
+      <displayItem name='name'>Gaelic (Scottish)</displayItem>
+    </language>
+    <language name='gl'>
+      <displayItem name='name'>Galician</displayItem>
+    </language>
+    <language name='he'>
+      <displayItem name='name'>Hebrew</displayItem>
+    </language>
+    <language name='hi'>
+      <displayItem name='name'>Hindi</displayItem>
+    </language>
+    <language name='hu'>
+      <displayItem name='name'>Hungarian</displayItem>
+    </language>
+    <language name='hy'>
+      <displayItem name='name'>Armenian</displayItem>
+    </language>
+    <language name='id'>
+      <displayItem name='name'>Bahasa Indonesia (Indonesian)</displayItem>
+    </language>
+    <language name='it'>
+      <displayItem name='name'>Italiano</displayItem>
+    </language>    
+    <language name='ka'>
+      <displayItem name='name'>Georgian</displayItem>
+    </language>
+    <language name='kk'>
+      <displayItem name='name'>ÒÐ°Ð·Ð°Ò (Kazakh)</displayItem>
+    </language>
+    <language name='kn'>
+      <displayItem name='name'>Kannada</displayItem>
+    </language>
+    <language name='ky'>
+      <displayItem name='name'>ÐÑÑÐ³ÑÐ·ÑÐ° (Kirghiz)</displayItem>
+    </language>    
+    <language name='lv'>
+      <displayItem name='name'>Latvian</displayItem>
+    </language>
+	<language name='mi'>
+      <displayItem name='name'>MÄori</displayItem>
+    </language>
+	<language name='ml'>
+      <displayItem name='name'>Malayalam</displayItem>
+    </language>
+	<language name='mn'>
+      <displayItem name='name'>ÐÐŸÐœÐ³ÐŸÐ» (Mongolian)</displayItem>
+    </language>
+	<language name='mr'>
+      <displayItem name='name'>Marathi</displayItem>
+    </language>
+	<language name='nl'>
+      <displayItem name='name'>Nederlands (Dutch)</displayItem>
+    </language>
+	<language name='pl'>
+      <displayItem name='name'>polski (Polish)</displayItem>
+    </language>
+	<language name='pt-br'>
+      <displayItem name='name'>portuguÃªs-BR (Brasil)</displayItem>
+    </language>
+	<language name='pt-pt'>
+      <displayItem name='name'>portuguÃªs-PT (Portugal)</displayItem>
+    </language>
+	<language name='ps'>
+      <displayItem name='name'>Pushto</displayItem>
+    </language>
+	<language name='prs'>
+      <displayItem name='name'>Dari</displayItem>
+    </language>
+	<language name='ro'>
+      <displayItem name='name'>Romanian</displayItem>
+    </language>
+	<language name='ru'>
+      <displayItem name='name'>ÑÑÑÑÐºÐžÐ¹ (Russian)</displayItem>
+    </language>
+	<language name='si'>
+      <displayItem name='name'>Sinhalese</displayItem>
+    </language>
+	<language name='sk'>
+      <displayItem name='name'>SlovenÄina (Slovak)</displayItem>
+    </language>
+	<language name='sr'>
+      <displayItem name='name'>Serbian</displayItem>
+    </language>
+	<language name='ta'>
+      <displayItem name='name'>Tamil</displayItem>
+    </language>	
+	<language name='te'>
+      <displayItem name='name'>Telugu</displayItem>
+    </language>
+	<language name='th'>
+      <displayItem name='name'>Thai</displayItem>
+    </language>
+	<language name='tr'>
+      <displayItem name='name'>Turkish</displayItem>
+    </language>
+	<language name='uk'>
+      <displayItem name='name'>Ukrainian</displayItem>
+    </language>
+	<language name='ur'>
+      <displayItem name='name'>Urdu</displayItem>
+    </language>
+	<language name='vi'>
+      <displayItem name='name'>Tiáº¿ng Viá»t</displayItem>
+    </language>
+	<language name='zh'>
+      <displayItem name='name'>ç®äœäž­æ (Simplified Chinese)</displayItem>
+    </language>
+	<language name='zh-tr'>
+      <displayItem name='name'>ç¹é«äž­æ (Traditional Chinese)</displayItem>
+    </language>
+  </languageList>
+  <optionList>
+    <option name="highlightQueryTerms" value="true"/>
+    <option name="berryBaskets" value="true"/>
+  </optionList>
+</interfaceConfig>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/YAHOO.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/YAHOO.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/YAHOO.js	(revision 24065)
@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class The Yahoo global namespace
+ */
+var YAHOO = function() {
+
+    return {
+
+        /**
+         * Yahoo presentation platform utils namespace
+         */
+        util: {},
+
+        /**
+         * Yahoo presentation platform widgets namespace
+         */
+        widget: {},
+
+        /**
+         * Yahoo presentation platform examples namespace
+         */
+        example: {},
+
+        /**
+         * Returns the namespace specified and creates it if it doesn't exist
+         *
+         * YAHOO.namespace("property.package");
+         * YAHOO.namespace("YAHOO.property.package");
+         *
+         * Either of the above would create YAHOO.property, then
+         * YAHOO.property.package
+         *
+         * @param  {String} sNameSpace String representation of the desired
+         *                             namespace
+         * @return {Object}            A reference to the namespace object
+         */
+        namespace: function( sNameSpace ) {
+
+            if (!sNameSpace || !sNameSpace.length) {
+                return null;
+            }
+
+            var levels = sNameSpace.split(".");
+
+            var currentNS = YAHOO;
+
+            // YAHOO is implied, so it is ignored if it is included
+            for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {
+                currentNS[levels[i]] = currentNS[levels[i]] || {};
+                currentNS = currentNS[levels[i]];
+            }
+
+            return currentNS;
+
+        }
+    };
+
+} ();
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/connection.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/connection.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/connection.js	(revision 24065)
@@ -0,0 +1,465 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * The Connection Manager provides a simplified interface to the XMLHttpRequest
+ * object.  It handles cross-browser instantiantion of XMLHttpRequest, negotiates the
+ * interactive states and server response returning the results to a pre-defined
+ * callback function you create.
+ * @ class
+ */
+YAHOO.util.Connect = {};
+
+YAHOO.util.Connect =
+{
+  /**
+   * Array of  MSFT ActiveX ids for XMLHttpRequest.
+   * @private
+   * @type array
+   */
+	_msxml_progid:[
+		'MSXML2.XMLHTTP.5.0',
+		'MSXML2.XMLHTTP.4.0',
+		'MSXML2.XMLHTTP.3.0',
+		'MSXML2.XMLHTTP',
+		'Microsoft.XMLHTTP'
+		],
+
+  /**
+   * Array of HTTP header(s)
+   * @private
+   * @type array
+   */
+	_http_header:[],
+
+ /**
+  * Property modified by setForm() to determine if the transaction
+  * should be processed as a HTML form POST.
+  * @private
+  * @type boolean
+  */
+	_isFormPost:false,
+
+ /**
+  * Property modified by setForm() to the HTML form POST body.
+  * @private
+  * @type string
+  */
+	_sFormData:null,
+
+  /**
+   * The polling frequency, in milliseconds, for HandleReadyState.
+   * when attempting to determine a transaction's XHR  readyState.
+   * The default is 300 milliseconds.
+   * @private
+   * @type int
+   */
+	_polling_interval:300,
+
+  /**
+   * A transaction counter that increments the transaction id for each transaction.
+   * @private
+   * @type int
+   */
+	_transaction_id:0,
+
+  /**
+   * Member to add an ActiveX id to the existing xml_progid array.
+   * In the event(unlikely) a new ActiveX id is introduced, it can be added
+   * without internal code modifications.
+   * @public
+   * @param string id The ActiveX id to be added to initialize the XHR object.
+   * @return void
+   */
+	setProgId:function(id)
+	{
+		this.msxml_progid.unshift(id);
+	},
+
+  /**
+   * Instantiates a XMLHttpRequest object and returns an object with two properties:
+   * the XMLHttpRequest instance and the transaction id.
+   * @private
+   * @param {int} transactionId Property containing the transaction id for this transaction.
+   * @return connection object
+   * @type object
+   */
+	createXhrObject:function(transactionId)
+	{
+		var obj,http;
+		try
+		{
+			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
+			http = new XMLHttpRequest();
+			//  Object literal with http and id properties
+			obj = { conn:http, tId:transactionId };
+		}
+		catch(e)
+		{
+			for(var i=0; i<this._msxml_progid.length; ++i){
+				try
+				{
+					// Instantiates XMLHttpRequest for IE and assign to http.
+					http = new ActiveXObject(this._msxml_progid[i]);
+					//  Object literal with http and id properties
+					obj = { conn:http, tId:transactionId };
+				}
+				catch(e){}
+			}
+		}
+		finally
+		{
+			return obj;
+		}
+	},
+
+  /**
+   * This method is called by asyncRequest and syncRequest to create a
+   * valid connection object for the transaction.  It also passes a
+   * transaction id and increments the transaction id counter.
+   * @private
+   * @return object
+   */
+	getConnectionObject:function()
+	{
+		var o;
+		var tId = this._transaction_id;
+
+		try
+		{
+			o = this.createXhrObject(tId);
+			if(o){
+				this._transaction_id++;
+			}
+		}
+		catch(e){}
+		finally
+		{
+			return o;
+		}
+	},
+
+  /**
+   * Method for initiating an asynchronous request via the XHR object.
+   * @public
+   * @param {string} method HTTP transaction method
+   * @param {string} uri Fully qualified path of resource
+   * @param callback User-defined callback function or object
+   * @param callbackArg User-defined callback arguments
+   * @param {string} postData POST body
+   * @return {object} Returns the connection object
+   */
+	asyncRequest:function(method, uri, callback, postData)
+	{
+		var errorObj;
+		var o = this.getConnectionObject();
+
+		if(!o){
+			return null;
+		}
+		else{
+			var oConn = this;
+
+			o.conn.open(method, uri, true);
+		    this.handleReadyState(o, callback);
+
+			if(this._isFormPost){
+				postData = this._sFormData;
+				this._isFormPost = false;
+			}
+			else if(postData){
+				this.initHeader('Content-Type','application/x-www-form-urlencoded');
+			}
+
+			//Verify whether the transaction has any user-defined HTTP headers
+			//and set them.
+			if(this._http_header.length>0){
+				this.setHeader(o);
+			}
+			postData?o.conn.send(postData):o.conn.send(null);
+
+			return o;
+		}
+	},
+
+  /**
+   * This method serves as a timer that polls the XHR object's readyState
+   * property during a transaction, instead of binding a callback to the
+   * onreadystatechange event.  Upon readyState 4, handleTransactionResponse
+   * will process the response, and the timer will be cleared.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param callback User-defined callback object
+   * @param callbackArg User-defined arguments passed to the callback
+   * @return void
+   */
+	handleReadyState:function(o, callback)
+	{
+		var oConn = this;
+		var poll = window.setInterval(
+			function(){
+				if(o.conn.readyState==4){
+					oConn.handleTransactionResponse(o, callback);
+					window.clearInterval(poll);
+				}
+			}
+		,this._polling_interval);
+	},
+
+  /**
+   * This method attempts to interpret the server response and
+   * determine whether the transaction was successful, or if an error or
+   * exception was encountered.
+   *
+   * @private
+   * @param {object} o The connection object
+   * @param {function} callback - User-defined callback object
+   * @param {} callbackArg - User-defined arguments to be passed to the callback
+   * @return void
+   */
+	handleTransactionResponse:function(o, callback)
+	{
+		var httpStatus;
+		var responseObject;
+
+		try{
+			httpStatus = o.conn.status;
+		}
+		catch(e){
+			// 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+			// when the o object's status and statusText properties are
+			// unavailable, and a query attempt throws an exception.
+			httpStatus = 13030;
+		}
+
+		if(httpStatus == 200){
+			responseObject = this.createResponseObject(o, callback.argument);
+			if(callback.success){
+				if(!callback.scope){
+					callback.success(responseObject);
+				}
+				else{
+					callback.success.apply(callback.scope, [responseObject]);
+				}
+			}
+		}
+		else{
+			switch(httpStatus){
+				// The following case labels are wininet.dll error codes that may be encountered.
+				// Server timeout
+				case 12002:
+				// 12029 to 12031 correspond to dropped connections.
+				case 12029:
+				case 12030:
+				case 12031:
+				// Connection closed by server.
+				case 12152:
+				// See above comments for variable status.
+				case 13030:
+					responseObject = this.createExceptionObject(o, callback.argument);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+						}
+						else{
+							callback.failure.apply(callback.scope,[responseObject]);
+						}
+					}
+					break;
+				default:
+					responseObject = this.createResponseObject(o, callback.argument);
+					if(callback.failure){
+						if(!callback.scope){
+							callback.failure(responseObject);
+						}
+						else{
+							callback.failure.apply(callback.scope,[responseObject]);
+						}
+					}
+			}
+		}
+
+		this.releaseObject(o);
+	},
+
+  /**
+   * This method evaluates the server response, creates and returns the results via
+   * its properties.  Success and failure cases(and exceptions) will differ in their defined properties
+   * but property "type" will confirm the transaction's status.
+   * @private
+   * @param {object} o The connection object
+   * @param {} callbackArg User-defined arguments to be passed to the callback
+   * @param {boolean} isSuccess Indicates whether the transaction was successful or not.
+   * @return object
+   */
+	createResponseObject:function(o, callbackArg)
+	{
+		var obj = {};
+
+		obj.tId = o.tId;
+		obj.status = o.conn.status;
+		obj.statusText = o.conn.statusText;
+		obj.allResponseHeaders = o.conn.getAllResponseHeaders();
+		obj.responseText = o.conn.responseText;
+		obj.responseXML = o.conn.responseXML;
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+	},
+
+  /**
+   * If a transaction cannot be completed due to dropped or closed connections,
+   * there may be not be enough information to build a full response object.
+   * The object's property "type" value will be "failure", and two additional
+   * unique, properties are added - errorCode and errorText.
+   * @private
+   * @param {int} tId Transaction Id
+   * @param callbackArg The user-defined arguments
+   * @param {string} errorCode Error code associated with the exception.
+   * @param {string} errorText Error message describing the exception.
+   * @return object
+   */
+	createExceptionObject:function(tId, callbackArg)
+	{
+		var COMM_CODE = 0;
+		var COMM_ERROR = 'communication failure';
+
+		var obj = {};
+
+		obj.tId = tId;
+		obj.status = COMM_CODE;
+		obj.statusText = COMM_ERROR;
+		if(callbackArg){
+			obj.argument = callbackArg;
+		}
+
+		return obj;
+	},
+
+  /**
+   * Accessor that stores the HTTP headers for each transaction.
+   * @public
+   * @param {string} label The HTTP header label
+   * @param {string} value The HTTP header value
+   * @return void
+   */
+	initHeader:function(label,value)
+	{
+		var oHeader = [label,value];
+		this._http_header.push(oHeader);
+	},
+
+  /**
+   * Accessor that sets the HTTP headers for each transaction.
+   * @private
+   * @param {object} o The connection object for the transaction.
+   * @return void
+   */
+	setHeader:function(o)
+	{
+		var oHeader = this._http_header;
+		for(var i=0;i<oHeader.length;i++){
+			o.conn.setRequestHeader(oHeader[i][0],oHeader[i][1]);
+		}
+		oHeader.splice(0,oHeader.length);
+	},
+
+  /**
+   * This method assembles the form label and value pairs and
+   * constructs an encoded POST body.  Both syncRequest()
+   * and asyncRequest() will automatically initialize the
+   * transaction with a HTTP header Content-Type of
+   * application/x-www-form-urlencoded.
+   * @public
+   * @param {string} formName value of form name attribute
+   * @return void
+   */
+	setForm:function(formName)
+	{
+		this._sFormData = '';
+		var oForm = document.forms[formName];
+		var oElement, elName, elValue;
+		// iterate over the form elements collection to construct the
+		// label-value pairs.
+		for (var i=0; i<oForm.elements.length; i++){
+			oElement = oForm.elements[i];
+			elName = oForm.elements[i].name;
+			elValue = oForm.elements[i].value;
+			switch (oElement.type)
+			{
+				case 'select-multiple':
+					for(var j=0; j<oElement.options.length; j++){
+						if(oElement.options[j].selected){
+							this._sFormData += encodeURIComponent(elName) + '=' + encodeURIComponent(oElement.options[j].value) + '&';
+						}
+					}
+					break;
+				case 'radio':
+				case 'checkbox':
+					if(oElement.checked){
+						this._sFormData += encodeURIComponent(elName) + '=' + encodeURIComponent(elValue) + '&';
+					}
+					break;
+				case 'file':
+				// stub case as XMLHttpRequest will only send the file path as a string.
+					break;
+				case undefined:
+				// stub case for fieldset element which returns undefined.
+					break;
+				default:
+					this._sFormData += encodeURIComponent(elName) + '=' + encodeURIComponent(elValue) + '&';
+					break;
+			}
+		}
+		this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+		this._isFormPost = true;
+		this.initHeader('Content-Type','application/x-www-form-urlencoded');
+	},
+
+  /**
+   * Public method to terminate a transaction, if it has not reached readyState 4.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest.
+   * @return void
+   */
+	abort:function(o)
+	{
+		if(this.isCallInProgress(o)){
+			o.conn.abort();
+			this.releaseObject(o);
+		}
+	},
+
+  /**
+   * Accessor to check if the transaction associated with the connection object
+   * is still being processed.
+   * @public
+   * @param {object} o The connection object returned by asyncRequest
+   * @return boolean
+   */
+	isCallInProgress:function(o)
+	{
+		if(o){
+			return o.conn.readyState != 4 && o.conn.readyState != 0;
+		}
+	},
+
+  /**
+   * Dereference the XHR instance and the connection object after the transaction is completed.
+   * @private
+   * @param {object} o The connection object
+   * @return void
+   */
+	releaseObject:function(o)
+	{
+			//dereference the XHR instance.
+			o.conn = null;
+			//dereference the connection object.
+			o = null;
+	}
+}
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dom.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dom.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dom.js	(revision 24065)
@@ -0,0 +1,433 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Provides helper methods for DOM elements.
+ */
+YAHOO.util.Dom = new function() {
+
+   /**
+    * Returns an HTMLElement reference
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @return {HTMLElement} A DOM reference to an HTML element.
+    */
+   this.get = function(el) {
+      if (typeof el == 'string') { // accept object or id
+         el = document.getElementById(el);
+      }
+
+      return el;
+   };
+
+   /**
+    * Normalizes currentStyle and ComputedStyle.
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {String} property The style property whose value is returned.
+    * @return {String} The current value of the style property.
+    */
+   this.getStyle = function(el, property) {
+      var value = null;
+      var dv = document.defaultView;
+
+      el = this.get(el);
+
+      if (property == 'opacity' && el.filters) {// IE opacity
+         value = 1;
+         try {
+            value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
+         } catch(e) {
+            try {
+               value = el.filters.item('alpha').opacity / 100;
+            } catch(e) {}
+         }
+      }
+      else if (el.style[property]) {
+         value = el.style[property];
+      }
+      else if (el.currentStyle && el.currentStyle[property]) {
+         value = el.currentStyle[property];
+      }
+      else if ( dv && dv.getComputedStyle )
+      {  // convert camelCase to hyphen-case
+
+         var converted = '';
+         for(i = 0, len = property.length;i < len; ++i) {
+            if (property.charAt(i) == property.charAt(i).toUpperCase()) {
+               converted = converted + '-' + property.charAt(i).toLowerCase();
+            } else {
+               converted = converted + property.charAt(i);
+            }
+         }
+
+         if (dv.getComputedStyle(el, '').getPropertyValue(converted)) {
+            value = dv.getComputedStyle(el, '').getPropertyValue(converted);
+         }
+      }
+
+      return value;
+   };
+
+   /**
+    * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {String} property The style property to be set.
+    * @param {String} val The value to apply to the given property.
+    */
+   this.setStyle = function(el, property, val) {
+      el = this.get(el);
+      switch(property) {
+         case 'opacity' :
+            if (el.filters) {
+               el.style.filter = 'alpha(opacity=' + val * 100 + ')';
+
+               if (!el.currentStyle.hasLayout) {
+                  el.style.zoom = 1;
+               }
+            } else {
+               el.style.opacity = val;
+               el.style['-moz-opacity'] = val;
+               el.style['-khtml-opacity'] = val;
+            }
+            break;
+         default :
+            el.style[property] = val;
+      }
+   };
+
+   /**
+    * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getXY = function(el) {
+      el = this.get(el);
+
+      // has to be part of document to have pageXY
+      if (el.parentNode === null || this.getStyle(el, 'display') == 'none') {
+         return false;
+      }
+
+      /**
+       * Position of the html element (x, y)
+       * @private
+       * @type Array
+       */
+      var parent = null;
+      var pos = [];
+      var box;
+
+      if (el.getBoundingClientRect) { // IE
+         box = el.getBoundingClientRect();
+         var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+         var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+
+         return [box.left + scrollLeft, box.top + scrollTop];
+      }
+      else if (document.getBoxObjectFor) { // gecko
+         box = document.getBoxObjectFor(el);
+         pos = [box.x, box.y];
+      }
+      else { // safari/opera
+         pos = [el.offsetLeft, el.offsetTop];
+         parent = el.offsetParent;
+         if (parent != el) {
+            while (parent) {
+               pos[0] += parent.offsetLeft;
+               pos[1] += parent.offsetTop;
+               parent = parent.offsetParent;
+            }
+         }
+
+         // opera & (safari absolute) incorrectly account for body offsetTop
+         var ua = navigator.userAgent.toLowerCase();
+         if (
+            ua.indexOf('opera') != -1
+            || ( ua.indexOf('safari') != -1 && this.getStyle(el, 'position') == 'absolute' )
+         ) {
+            pos[1] -= document.body.offsetTop;
+         }
+      }
+
+      if (el.parentNode) { parent = el.parentNode; }
+      else { parent = null; }
+
+      while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') {
+         pos[0] -= parent.scrollLeft;
+         pos[1] -= parent.scrollTop;
+
+         if (parent.parentNode) { parent = parent.parentNode; }
+         else { parent = null; }
+      }
+
+      return pos;
+   };
+
+   /**
+    * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getX = function(el) {
+      return this.getXY(el)[0];
+   };
+
+   /**
+    * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getY = function(el) {
+      return this.getXY(el)[1];
+   };
+
+   /**
+    * Set the position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {array} pos Contains X & Y values for new position (coordinates are page-based)
+    */
+   this.setXY = function(el, pos, noRetry) {
+      el = this.get(el);
+      var pageXY = YAHOO.util.Dom.getXY(el);
+      if (pageXY === false) { return false; } // has to be part of doc to have pageXY
+
+      if (this.getStyle(el, 'position') == 'static') { // default to relative
+         this.setStyle(el, 'position', 'relative');
+      }
+
+      var delta = [
+         parseInt( YAHOO.util.Dom.getStyle(el, 'left'), 10 ),
+         parseInt( YAHOO.util.Dom.getStyle(el, 'top'), 10 )
+      ];
+
+      if ( isNaN(delta[0]) ) { delta[0] = 0; } // defalts to 'auto'
+      if ( isNaN(delta[1]) ) { delta[1] = 0; }
+
+      if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
+      if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
+
+      var newXY = this.getXY(el);
+
+      // if retry is true, try one more time if we miss
+      if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
+         this.setXY(el, pos, true);
+      }
+
+      return true;
+   };
+
+   /**
+    * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {Int} x to use as the X coordinate.
+    */
+   this.setX = function(el, x) {
+      return this.setXY(el, [x, null]);
+   };
+
+   /**
+    * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {Int} Value to use as the Y coordinate.
+    */
+   this.setY = function(el, y) {
+      return this.setXY(el, [null, y]);
+   };
+
+   /**
+    * Returns the region position of the given element.
+    * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @return {Region} A Region instance containing "top, left, bottom, right" member data.
+    */
+   this.getRegion = function(el) {
+      el = this.get(el);
+      return new YAHOO.util.Region.getRegion(el);
+   };
+
+   /**
+    * Returns the width of the client (viewport).
+    * @return {Int} The width of the viewable area of the page.
+    */
+   this.getClientWidth = function() {
+      return (
+         document.documentElement.offsetWidth
+         || document.body.offsetWidth
+      );
+   };
+
+   /**
+    * Returns the height of the client (viewport).
+    * @return {Int} The height of the viewable area of the page.
+    */
+   this.getClientHeight = function() {
+      return (
+         self.innerHeight
+         || document.documentElement.clientHeight
+         || document.body.clientHeight
+      );
+   };
+};
+
+/**
+ * @class A region is a representation of an object on a grid.  It is defined
+ * by the top, right, bottom, left extents, so is rectangular by default.  If
+ * other shapes are required, this class could be extended to support it.
+ *
+ * @param {int} t the top extent
+ * @param {int} r the right extent
+ * @param {int} b the bottom extent
+ * @param {int} l the left extent
+ * @constructor
+ */
+YAHOO.util.Region = function(t, r, b, l) {
+
+    /**
+     * The region's top extent
+     * @type int
+     */
+    this.top = t;
+
+    /**
+     * The region's right extent
+     * @type int
+     */
+    this.right = r;
+
+    /**
+     * The region's bottom extent
+     * @type int
+     */
+    this.bottom = b;
+
+    /**
+     * The region's left extent
+     * @type int
+     */
+    this.left = l;
+};
+
+/**
+ * Returns true if this region contains the region passed in
+ *
+ * @param  {Region}  region The region to evaluate
+ * @return {boolean}        True if the region is contained with this region,
+ *                          else false
+ */
+YAHOO.util.Region.prototype.contains = function(region) {
+    return ( region.left   >= this.left   &&
+             region.right  <= this.right  &&
+             region.top    >= this.top    &&
+             region.bottom <= this.bottom    );
+};
+
+/**
+ * Returns the area of the region
+ *
+ * @return {int} the region's area
+ */
+YAHOO.util.Region.prototype.getArea = function() {
+    return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+/**
+ * Returns the region where the passed in region overlaps with this one
+ *
+ * @param  {Region} region The region that intersects
+ * @return {Region}        The overlap region, or null if there is no overlap
+ */
+YAHOO.util.Region.prototype.intersect = function(region) {
+    var t = Math.max( this.top,    region.top    );
+    var r = Math.min( this.right,  region.right  );
+    var b = Math.min( this.bottom, region.bottom );
+    var l = Math.max( this.left,   region.left   );
+
+    if (b >= t && r >= l) {
+        return new YAHOO.util.Region(t, r, b, l);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Returns the region representing the smallest region that can contain both
+ * the passed in region and this region.
+ *
+ * @param  {Region} region The region that to create the union with
+ * @return {Region}        The union region
+ */
+YAHOO.util.Region.prototype.union = function(region) {
+    var t = Math.min( this.top,    region.top    );
+    var r = Math.max( this.right,  region.right  );
+    var b = Math.max( this.bottom, region.bottom );
+    var l = Math.min( this.left,   region.left   );
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/**
+ * toString
+ * @return string the region properties
+ */
+YAHOO.util.Region.prototype.toString = function() {
+    return ( "Region {" +
+             "  t: "    + this.top    +
+             ", r: "    + this.right  +
+             ", b: "    + this.bottom +
+             ", l: "    + this.left   +
+             "}" );
+}
+
+/**
+ * Returns a region that is occupied by the DOM element
+ *
+ * @param  {HTMLElement} el The element
+ * @return {Region}         The region that the element occupies
+ * @static
+ */
+YAHOO.util.Region.getRegion = function(el) {
+    var p = YAHOO.util.Dom.getXY(el);
+
+    var t = p[1];
+    var r = p[0] + el.offsetWidth;
+    var b = p[1] + el.offsetHeight;
+    var l = p[0];
+
+    return new YAHOO.util.Region(t, r, b, l);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * @class
+ *
+ * A point is a region that is special in that it represents a single point on
+ * the grid.
+ *
+ * @param {int} x The X position of the point
+ * @param {int} y The Y position of the point
+ * @constructor
+ * @extends Region
+ */
+YAHOO.util.Point = function(x, y) {
+    /**
+     * The X position of the point
+     * @type int
+     */
+    this.x      = x;
+
+    /**
+     * The Y position of the point
+     * @type int
+     */
+    this.y      = y;
+
+    this.top    = y;
+    this.right  = x;
+    this.bottom = y;
+    this.left   = x;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dragdrop-debug.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dragdrop-debug.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dragdrop-debug.js	(revision 24065)
@@ -0,0 +1,2517 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Defines the interface and base operation of items that that can be
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that
+ * was clicked matches a handle element.  By default this is the linked
+ * element, but there are times that you will want only a portion of the
+ * linked element to initiate the drag operation, and the setHandleElId()
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents an the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any
+ * other * DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new YAHOO.util.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would
+ * actually happen if you were to run the code above.  Normally you would
+ * override this class or one of the default implementations, but you can
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *   alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DragDrop = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+    }
+};
+
+YAHOO.util.DragDrop.prototype = {
+
+    /**
+     * The id of the element associated with this object.  This is what we
+     * refer to as the "linked element" because the size and position of
+     * this element is used to determine when the drag and drop objects have
+     * interacted.
+     *
+     * @type String
+     */
+    id: null,
+
+    /**
+     * The id of the element that will be dragged.  By default this is same
+     * as the linked element , but could be changed to another element. Ex:
+     * YAHOO.util.DDProxy
+     *
+     * @type String
+     * @private
+     */
+    dragElId: null,
+
+    /**
+     * the id of the element that initiates the drag operation.  By default
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the
+     * header element within the linked html element is clicked.
+     *
+     * @type String
+     * @private
+     */
+    handleElId: null,
+
+    /**
+     * An array of HTML tags that will be ignored if clicked.
+     */
+    invalidHandleTypes: null,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are
+     * related.  Instances only get events when interacting with other
+     * DragDrop object in the same group.  This lets us define multiple
+     * groups using a single DragDrop subclass if we want.
+     *
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     *
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     *
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     */
+    padding: null,
+
+    /**
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     *
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     *
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint
+     *
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint
+     *
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Used to maintain the
+     * slider thumb value, and this needs to be fixed.
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * vertical graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     *
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an
+     * object.
+     *
+     * @param {Event} e
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragEnter event
+     * @private
+     */
+    // b4DragEnter: function(e) { },
+
+    /**
+     * Abstract method called when this element fist begins hovering over
+     * another DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another
+     * DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop
+     * obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     *
+     * @param {Event} e
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
+
+     * @param {Event} e
+     * @private
+     */
+    b4MouseDown: function(e) {  },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @param {Event} e
+     */
+    onMouseDown: function(e) { /* override this */ },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @param {Event} e
+     */
+    onMouseUp: function(e) { /* override this */ },
+
+    /**
+     * Returns a reference to the linked element
+     *
+     * @return {Object} the html element
+     */
+    getEl: function() {
+        if (!this._domRef) {
+            this._domRef = this.DDM.getElement(this.id);
+        }
+
+        return this._domRef;
+    },
+
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another
+     * element. An example of this can be found in YAHOO.util.DDProxy
+     *
+     * @return {Object} the html element
+     */
+    getDragEl: function() {
+        return this.DDM.getElement(this.dragElId);
+    },
+
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * YAHOO.util.DragDrop subclass
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    init: function(id, sGroup) {
+        this.initTarget(id, sGroup);
+        YAHOO.util.Event.addListener(id, "mousedown",
+                                          this.handleMouseDown, this, true);
+    },
+
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    initTarget: function(id, sGroup) {
+
+        // create a local reference to the drag and drop manager
+        this.DDM = YAHOO.util.DDM;
+
+        // create a logger instance
+        this.logger = new ygLogger("DragDrop");
+
+        // set the default padding
+        this.padding = [0, 0, 0, 0];
+
+        // initialize the groups array
+        this.groups = {};
+
+        // set the id
+        this.id = id;
+
+        // the element is a drag handle by default
+        this.setDragElId(id);
+
+        // by default, clicked anchors will not start drag operations
+        this.invalidHandleTypes = {a : "a"};
+
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter
+        this.handleElId = id;
+
+        // cache the position of the element if we can
+        if (document && document.body) {
+            this.setInitPosition();
+        }
+
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
+
+    },
+
+    /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
+
+    /**
+     * Stores the initial placement of the dd element
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
+
+        if (!this.DDM.verifyEl(el)) {
+            this.logger.debug(this.id + " element is broken");
+            return;
+        }
+
+        var dx = diffX || 0;
+        var dy = diffY || 0;
+
+        var p = YAHOO.util.Dom.getXY( el );
+
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
+
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
+
+        this.setStartPosition(p);
+    },
+
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+
+        var p = pos || YAHOO.util.Dom.getXY( this.getEl() );
+
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
+
+    /**
+     * Add this instance to a group of related drag/drop objects.  All
+     * instances belong to at least one group, and can belong to as many
+     * groups as needed.
+     *
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
+
+    /**
+     * Allows you to specify that an element other than the linked element
+     * will be moved with the cursor during a drag
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
+
+    /**
+     * Allows you to specify a child of the linked element that should be
+     * used to initiate the drag operation.  An example of this would be if
+     * you have a content div with text and links.  Clicking anywhere in the
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element
+     * that starts the drag operation.
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setHandleElId: function(id) {
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
+
+    /**
+     * Allows you to set an element outside of the linked element as a drag
+     * handle
+     */
+    setOuterHandleElId: function(id) {
+        this.logger.debug("Adding outer handle event: " + id);
+        YAHOO.util.Event.addListener(id, "mousedown",
+                this.handleMouseDown, this, true);
+        this.setHandleElId(id);
+    },
+
+    /**
+     * Remove all drag and drop hooks for this element
+     */
+    unreg: function() {
+        this.logger.debug("DragDrop obj cleanup " + this.id);
+        YAHOO.util.Event.removeListener(this.id, "mousedown",
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
+
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     *
+     * @return {boolean} true if this obj or all drag/drop is locked, else
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
+
+    /**
+     * Fired when this object is clicked
+     *
+     * @param {Event} e
+     * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD) {
+
+        this.logger.debug("isLocked: " + this.isLocked());
+
+        var EU = YAHOO.util.Event;
+
+
+        var button = e.which || e.button;
+        this.logger.debug("button: " + button);
+
+        if (this.primaryButtonOnly && button > 1) {
+            this.logger.debug("Mousedown was not produced by the primary button");
+            return;
+        }
+
+        if (this.isLocked()) {
+            this.logger.debug("Drag and drop is disabled, aborting");
+            return;
+        }
+
+        this.logger.debug("mousedown " + this.id);
+
+        this.DDM.refreshCache(this.groups);
+
+        // Only process the event if we really clicked within the linked
+        // element.  The reason we make this check is that in the case that
+        // another element was moved between the clicked element and the
+        // cursor in the time between the mousedown and mouseup events. When
+        // this happens, the element gets the next mousedown event
+        // regardless of where on the screen it happened.
+        var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e));
+        if ( this.DDM.isOverTarget(pt, this) )  {
+
+            this.logger.debug("click is legit");
+
+            //  check to see if the handle was clicked
+            var srcEl = EU.getTarget(e);
+
+            if (this.isValidHandleChild(srcEl) &&
+                    (this.id == this.handleElId ||
+                     this.DDM.handleWasClicked(srcEl, this.id)) ) {
+
+                // set the initial element position
+                this.setStartPosition();
+
+                this.logger.debug("firing onMouseDown events");
+
+
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
+                this.DDM.handleMouseDown(e, this);
+
+                this.DDM.stopEvent(e);
+            }
+        }
+    },
+
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     *
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
+
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     *
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = null;
+    },
+
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     *
+     * @param {ygNode} node
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
+        var type = node.nodeName;
+
+        if (type == "#text") {
+            // this.logger.debug("text node, getting parent node type");
+            type = node.parentNode.nodeName;
+        }
+
+        return (!this.invalidHandleTypes[type]);
+    },
+
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     *
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.xTicks.sort(this.DDM.numericSort) ;
+        this.logger.debug("xTicks: " + this.xTicks.join());
+    },
+
+    /**
+     * Create the array of vertical tick marks if an interval was specified in
+     * setYConstraint().
+     *
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.yTicks.sort(this.DDM.numericSort) ;
+        this.logger.debug("yTicks: " + this.yTicks.join());
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Use
+     * this method to limit the horizontal travel of the element.  Pass in
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     *
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
+
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+
+        this.constrainX = true;
+        this.logger.debug("initPageX:" + this.initPageX + " minX:" + this.minX +
+                " maxX:" + this.maxX);
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Set
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     *
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
+
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+
+        this.constrainY = true;
+
+        this.logger.debug("initPageY:" + this.initPageY + " minY:" + this.minY +
+                " maxY:" + this.maxY);
+    },
+
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
+
+        // this.logger.debug("init pagexy: " + this.initPageX + ", " +
+        //      this.initPageY);
+        // this.logger.debug("last pagexy: " + this.lastPageX + ", " +
+        //      this.lastPageY);
+
+        // figure out how much this thing has moved
+        var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+        var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
+
+        // this.logger.debug("diff: " + dx + ", " + dy);
+
+        // reset the initial location
+        this.setInitPosition(dx, dy);
+
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint,
+                                 this.rightConstraint,
+                                 this.xTickSize        );
+        }
+
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint,
+                                 this.bottomConstraint,
+                                 this.yTickSize         );
+        }
+    },
+
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify
+     * that it move a number of pixels at a time.  This method resolves the
+     * location when we have it set up like this.
+     *
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
+
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel,
+            // so we return the value passed to us.
+            return val;
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i = 0; i < tickArray.length; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
+            }
+
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
+
+    /**
+     * toString method
+     * @return {string} string representation of the dd obj
+     */
+    toString: function(val, tickArray) {
+        return ("YAHOO.util.DragDrop {" + this.id + "}");
+    }
+
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+// Only load the library once.  Rewriting the manager class would orphan
+// existing drag and drop instances.
+if (!YAHOO.util.DragDropMgr) {
+
+    /**
+     * @class Handles the element interaction for all DragDrop items in the
+     * window.  Generally, you will not call this class directly, but it does
+     * have helper methods that could be useful in your DragDrop
+     * implementations.  This class should not be instantiated; all methods
+     * are are static.
+     *
+     * @constructor
+     */
+    YAHOO.util.DragDropMgr = new function() {
+
+        /**
+         * utility package shorthand
+         * @private
+         */
+        var UTIL = YAHOO.util;
+
+        /**
+         * Two dimensional Array of registered DragDrop objects.  The first
+         * dimension is the DragDrop item group, the second the DragDrop
+         * object.
+         *
+         * @private
+         */
+        this.ids = {};
+
+        /**
+         * Array of element ids defined as drag handles.  Used to determine
+         * if the element that generated the mousedown event is actually the
+         * handle and not the html element itself.
+         *
+         * @private
+         */
+        this.handleIds = {};
+
+        /**
+         * the DragDrop object that is currently being dragged
+         *
+         * @type DragDrop
+         * @private
+         **/
+        this.dragCurrent = null;
+
+        /**
+         * the DragDrop object(s) that are being hovered over
+         *
+         * @type Array
+         * @private
+         */
+        this.dragOvers = {};
+
+        /**
+         * @private
+         */
+        this.logger = null;
+
+        /**
+         * the X distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaX = 0;
+
+        /**
+         * the Y distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaY = 0;
+
+        /**
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to
+         * false if you need the default behavior (not recommended)
+         *
+         * @type boolean
+         */
+        this.preventDefault = true;
+
+        /**
+         * Flag to determine if we should stop the propagation of the events
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         *
+         * @type boolean
+         */
+        this.stopPropagation = true;
+
+        /**
+         * @private
+         */
+        this.initalized = false;
+
+        /**
+         * All drag and drop can be disabled.
+         *
+         * @private
+         */
+        this.locked = false;
+
+        /**
+         * Called the first time an element is registered.
+         *
+         * @private
+         */
+        this.init = function() {
+            this.logger = new ygLogger("DragDropMgr");
+        };
+
+        /**
+         * In point mode, drag and drop interaction is defined by the
+         * location of the cursor during the drag/drop
+         * @type int
+         */
+        this.POINT     = 0;
+
+        /**
+         * In intersect mode, drag and drop interactio nis defined by the
+         * overlap of two or more drag and drop objects.
+         * @type int
+         */
+        this.INTERSECT = 1;
+
+        /**
+         * The current drag and drop mode.  Default it point mode
+         * @type int
+         */
+        this.mode = this.POINT;
+
+        /**
+         * Runs method on all drag and drop objects
+         * @private
+         */
+        this._execOnAll = function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
+        };
+
+        /**
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @private
+         */
+        this._onLoad = function() {
+
+            this._execOnAll("setInitPosition", []);
+
+            this.logger = new ygLogger("DragDropMgr");
+            this.logger.debug("DDM onload");
+
+            var EU = UTIL.Event;
+
+            EU.addListener(document, "mouseup",   this.handleMouseUp, this, true);
+            EU.addListener(document, "mousemove", this.handleMouseMove, this, true);
+            EU.addListener(window,   "unload",    this._onUnload, this, true);
+            EU.addListener(window,   "resize",    this._onResize, this, true);
+            // EU.addListener(window,   "mouseout",    this._test);
+
+            this.initalized = true;
+
+        };
+
+        /**
+         * Reset constraints on all drag and drop objs
+         * @private
+         */
+        this._onResize = function(e) {
+            this.logger.debug("window resize");
+            this._execOnAll("resetConstraints", []);
+        };
+
+        /**
+         * Lock all drag and drop functionality
+         */
+        this.lock = function() { this.locked = true; };
+
+        /**
+         * Unlock all drag and drop functionality
+         */
+        this.unlock = function() { this.locked = false; };
+
+        /**
+         * Is drag and drop locked?
+         *
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         */
+        this.isLocked = function() { return this.locked; };
+
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         *
+         * @private
+         */
+        this.locationCache = {};
+
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @type boolean
+         */
+        this.useCache = true;
+
+        /**
+         * The number of pixels that the mouse needs to move after the
+         * mousedown before the drag is initiated.  Default=3;
+         * @type int
+         */
+        this.clickPixelThresh = 3;
+
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @type int
+         */
+        this.clickTimeThresh = 1000;
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the
+         * mousdown time threshold has been met
+         * @type boolean
+         * @private
+         */
+        this.dragThreshMet = false;
+
+        /**
+         * Timeout used for the click time threshold
+         * @type Object
+         * @private
+         */
+        this.clickTimeout = null;
+
+        /**
+         * The X position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startX = 0;
+
+        /**
+         * The Y position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startY = 0;
+
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.
+         * This is executed in ygDragDrop.init()
+         *
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         */
+        this.regDragDrop = function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
+
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        };
+
+        /**
+         * Unregisters a drag and drop item.  This is executed in
+         * ygDragDrop.unreg, use that method instead of calling this directly.
+         * @private
+         */
+        this._remove = function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
+            }
+            delete this.handleIds[oDD.id];
+        };
+
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing ygDragDrop.setHandleElId()
+         *
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag
+         * handle
+         */
+        this.regHandle = function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
+            }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop item.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item,
+         * false otherwise
+         */
+        this.isDragDrop = function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        };
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         *
+         * @param {ygDragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {ygDragDrop[]} the related instances
+         */
+        this.getRelated = function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
+            }
+
+            return oDDs;
+        };
+
+        /**
+         * Returns true if the specified dd target is a legal target for
+         * the specifice drag obj
+         *
+         * @param {ygDragDrop} the drag obj
+         * @param {ygDragDrop) the target
+         * @return {boolean} true if the target is a legal target for the
+         * dd obj
+         */
+        this.isLegalTarget = function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD);
+            for (var i =0;i<targets.length;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof ygDragDrop, and the exact subclass of ygDragDrop.  typeof
+         * returns "object", oDD.constructor.toString() always returns
+         * "ygDragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in ygDragDrop.
+         *
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = ygDragDrop
+         */
+        this.isTypeOfDD = function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop handle for the given Drag Drop object.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false
+         * otherwise
+         */
+        this.isHandle = function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] &&
+                            this.handleIds[sDDId][sHandleId] );
+        };
+
+        /**
+         * Returns the DragDrop instance for a given id
+         *
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         */
+        this.getDDById = function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         *
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         */
+        this.handleMouseDown = function(e, oDD) {
+            this.logger.debug("mousedown - adding event handlers");
+            this.dragCurrent = oDD;
+
+            var el = oDD.getEl();
+
+            // track start position
+            this.startX = UTIL.Event.getPageX(e);
+            this.startY = UTIL.Event.getPageY(e);
+
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
+
+            this.dragThreshMet = false;
+
+            this.clickTimeout = setTimeout(
+               "var DDM=YAHOO.util.DDM;DDM.startDrag(DDM.startX, DDM.startY)",
+               this.clickTimeThresh );
+        };
+
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold
+         * time threshold has been met.
+         *
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         */
+        this.startDrag = function(x, y) {
+            this.logger.debug("firing drag start events");
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        };
+
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked
+         * from the context of the document.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseUp = function(e) {
+
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            clearTimeout(this.clickTimeout);
+
+            if (this.dragThreshMet) {
+                this.logger.debug("mouseup detected - completing drag");
+                this.fireEvents(e, true);
+            } else {
+                this.logger.debug("drag threshold not met");
+            }
+
+            this.stopDrag(e);
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Utility to stop event propagation and event default, if these
+         * features are turned on.
+         *
+         * @param {Event} e the event as returned by this.getEvent()
+         */
+        this.stopEvent = function(e) {
+            if (this.stopPropagation) {
+                UTIL.Event.stopPropagation(e);
+            }
+
+            if (this.preventDefault) {
+                UTIL.Event.preventDefault(e);
+            }
+        };
+
+        /**
+         * Internal function to clean up event handlers after the drag
+         * operation is complete
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.stopDrag = function(e) {
+            // this.logger.debug("mouseup - removing event handlers");
+
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.logger.debug("firing endDrag events");
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(e);
+                }
+
+                this.logger.debug("firing onMouseUp event");
+                this.dragCurrent.onMouseUp(e);
+            }
+
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        };
+
+
+        /**
+         * Internal function to handle the mousemove event.  Will be invoked
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the
+         * user drags objects beyond the window boundary.  Currently we can
+         * detect this in internet explorer by verifying that the mouse is
+         * down during the mousemove event.  Firefox doesn't give us the
+         * button state on the mousemove event.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseMove = function(e) {
+            if (! this.dragCurrent) {
+                // this.logger.debug("no current drag obj");
+                return;
+            }
+
+            // var button = e.which || e.button;
+
+            this.logger.debug("which: " + e.which + ", button: "+ e.button);
+
+
+            // check for IE mouseup outside of page boundary
+            if (UTIL.Event.isIE && !e.button) {
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+                // this.logger.debug("button failure");
+            }
+
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - UTIL.Event.getPageX(e));
+                var diffY = Math.abs(this.startY - UTIL.Event.getPageY(e));
+                // this.logger.debug("diffX: " + diffX + "diffY: " + diffY);
+                if (diffX > this.clickPixelThresh ||
+                            diffY > this.clickPixelThresh) {
+                    this.logger.debug("pixel threshold met");
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
+
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                this.fireEvents(e, false);
+            }
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are
+         * hovering over or dropping on
+         *
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         */
+        this.fireEvents = function(e, isDrop) {
+            var dc = this.dragCurrent;
+
+            // If the user did the mouse up outside of the window, we could
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
+
+            var x = UTIL.Event.getPageX(e);
+            var y = UTIL.Event.getPageY(e);
+            var pt = new YAHOO.util.Point(x,y);
+
+            // cache the previous dragOver array
+            var oldOvers = [];
+
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
+
+            // Check to see if the object we were hovering over is no longer
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
+
+                var ddo = this.dragOvers[i];
+
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
+
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
+
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
+
+            for (var sGroup in dc.groups) {
+                // this.logger.debug("Processing group " + sGroup);
+
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
+
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
+
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (this.mode) {
+                if (outEvts.length > 0) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
+
+                if (enterEvts.length > 0) {
+                    dc.onDragEnter(e, enterEvts);
+                }
+
+                if (overEvts.length > 0) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
+
+                if (dropEvts.length > 0) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
+
+            } else {
+                // fire dragout events
+                for (i=0; i < outEvts.length; ++i) {
+                    this.logger.debug(dc.id+" onDragOut: " + outEvts[i].id);
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
+
+                // fire enter events
+                for (i=0; i < enterEvts.length; ++i) {
+                    this.logger.debug(dc.id + " dragEnter " + enterEvts[i].id);
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
+
+                // fire over events
+                for (i=0; i < overEvts.length; ++i) {
+                    this.logger.debug(dc.id + " dragOver " + overEvts[i].id);
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
+
+                // fire drop events
+                for (i=0; i < dropEvts.length; ++i) {
+                    this.logger.debug(dc.id + " dragDrop " + dropEvts[i].id);
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
+
+            }
+
+        };
+
+        /**
+         * Helper function for getting the best match from the list of drag
+         * and drop objects returned by the drag and drop events when we are
+         * in INTERSECT mode.  It returns either the first object that the
+         * cursor is over, or the object that has the greatest overlap with
+         * the dragged element.
+         *
+         * @param  {ygDragDrop[]} dds The array of drag and drop objects
+         * targeted
+         * @return {ygDragDrop}       The best single match
+         */
+        this.getBestMatch = function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
+
+            if (dds.length == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<dds.length; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner ||
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
+                }
+            }
+
+            return winner;
+        };
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the
+         * drag and drop objects in the specified groups
+         *
+         * @param {Array} aGroups an associative array of groups to refresh
+         */
+        this.refreshCache = function(aGroups) {
+            this.logger.debug("refreshing element location cache");
+            for (sGroup in aGroups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            this.logger.debug("something is wrong with the element");
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            oDD.unreg();
+                        }
+                    }
+                }
+            }
+        };
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         */
+        this.verifyEl = function(el) {
+            try {
+                if (el) {
+                    var parent = el.offsetParent;
+                    if (parent) {
+                        return true;
+                    }
+                }
+            } catch(e) {
+                this.logger.debug("detected problem with an element");
+            }
+
+            return false;
+        };
+
+        /**
+         * Returns the an array containing the drag and drop element's position
+         * and size, including the ygDragDrop.padding configured for it
+         *
+         * @param {ygDragDrop} oDD the drag and drop object to get the
+         * location for
+         * @return array containing the top left and bottom right points of the
+         * element
+         */
+        this.getLocation = function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                this.logger.debug(oDD + " is not a DD obj");
+                return null;
+            }
+
+            var el = oDD.getEl();
+
+            if (!this.verifyEl(el)) {
+                this.logger.debug(oDD + " element is not usable");
+                return null;
+            }
+
+            // this.logger.debug(oDD.id + " padding: " + oDD.padding);
+
+            // var aPos = ygPos.getPos(el);
+            var aPos = YAHOO.util.Dom.getXY(el);
+
+            x1 = aPos[0];
+            x2 = x1 + el.offsetWidth;
+
+            y1 = aPos[1];
+            y2 = y1 + el.offsetHeight;
+
+            var t = y1 - oDD.padding[0];
+            var r = x2 + oDD.padding[1];
+            var b = y2 + oDD.padding[2];
+            var l = x1 - oDD.padding[3];
+
+            return new YAHOO.util.Region( t, r, b, l );
+
+        };
+
+        /**
+         * Checks the cursor location to see if it over the target
+         *
+         * @param {YAHOO.util.Point} pt The point to evaluate
+         * @param {ygDragDrop} oDDTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         */
+        this.isOverTarget = function(pt, oDDTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oDDTarget.id];
+            if (!loc || !this.useCache) {
+                this.logger.debug("cache not populated");
+                loc = this.getLocation(oDDTarget);
+                this.locationCache[oDDTarget.id] = loc;
+
+                this.logger.debug("cache: " + loc);
+            }
+
+            // this.logger.debug("isOverTarget: " + x + "," + y + ", " + loc);
+
+            // var cursorIsOver =  (x >= loc[3] && x <= loc[1] && y >= loc[0] && y <= loc[2]);
+            //oDDTarget.cursorIsOver = loc.contains( new YAHOO.util.Point(x, y) );
+            oDDTarget.cursorIsOver = loc.contains( pt );
+            oDDTarget.overlap = null;
+
+            // if (this.INTERSECT == this.mode) {
+            if (intersect) {
+
+                var curRegion =
+                    YAHOO.util.Region.getRegion(this.dragCurrent.getDragEl());
+                var overlap = curRegion.intersect(loc);
+
+                if (overlap) {
+                    oDDTarget.overlap = overlap;
+                    return true;
+                } else {
+                    return false;
+                }
+
+            } else {
+                return oDDTarget.cursorIsOver;
+            }
+        };
+
+        /**
+         * @private
+         */
+        this._onUnload = function(e, me) {
+            this.unregAll();
+        };
+
+        /**
+         * Cleans up the drag and drop events and objects.
+         *
+         * @private
+         */
+        this.unregAll = function() {
+            this.logger.debug("unregister all");
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        };
+
+        /**
+         * A cache of DOM elements
+         *
+         * @private
+         */
+        this.elementCache = {};
+
+        /**
+         * Get the wrapper for the DOM element specified
+         *
+         * @param {String} id the id of the elment to get
+         * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
+         * @private
+         */
+        this.getElWrapper = function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                // this.logger.debug("adding element cache: " + id);
+                oWrapper = this.elementCache[id] =
+                    new this.ElementWrapper(document.getElementById(id));
+            }
+            return oWrapper;
+        };
+
+        /**
+         * Returns the actual DOM element
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         */
+        this.getElement = function(id) {
+            // return this.getElWrapper(id).el;
+            return document.getElementById(id);
+        };
+
+        /**
+         * Returns the style property for the DOM element (i.e.,
+         * document.getElById(id).style)
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         */
+        this.getCss = function(id) {
+            // return this.getElWrapper(id).css;
+            var css = null;
+            var el = document.getElementById(id);
+            if (el) {
+                css = el.style;
+            }
+
+            return css;
+        };
+
+        /**
+         * Inner class for cached elements
+         */
+        this.ElementWrapper = function(el) {
+                /**
+                 * @private
+                 */
+                this.el = el || null;
+                /**
+                 * @private
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * @private
+                 */
+                this.css = this.el && el.style;
+            };
+
+        /**
+         * Returns the X position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         */
+        this.getPosX = function(el) {
+            return YAHOO.util.Dom.getX(el);
+        };
+
+        /**
+         * Returns the Y position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         */
+        this.getPosY = function(el) {
+            return YAHOO.util.Dom.getY(el);
+        };
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we
+         * emulate the IE behavior
+         *
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         */
+        this.swapNode = function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                // the node reference order for the swap is a little tricky.
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+                n1.parentNode.replaceChild(n2,n1);
+                p.insertBefore(n1,s);
+            }
+        };
+
+        /**
+         * @private
+         */
+        this.getScroll = function () {
+            var t, l;
+            if (document.documentElement && document.documentElement.scrollTop) {
+                t = document.documentElement.scrollTop;
+                l = document.documentElement.scrollLeft;
+            } else if (document.body) {
+                t = document.body.scrollTop;
+                l = document.body.scrollLeft;
+            }
+            return { top: t, left: l };
+        };
+
+        /**
+         * Returns the specified element style property
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string}     The value of the style property
+         */
+        this.getStyle = function(el, styleProp) {
+            if (el.style.styleProp) {
+                return el.style.styleProp;
+            } else if (el.currentStyle) {
+                return el.currentStyle[styleProp];
+            } else if (document.defaultView) {
+                return document.defaultView.getComputedStyle(el, null).
+                    getPropertyValue(styleProp);
+            }
+        };
+
+        /**
+         * Gets the scrollTop
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollTop = function () { return this.getScroll().top; };
+
+        /**
+         * Gets the scrollLeft
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollLeft = function () { return this.getScroll().left; };
+
+        this.moveToEl = function (moveEl, targetEl) {
+            var aCoord = YAHOO.util.Dom.getXY(targetEl);
+            this.logger.debug("moveToEl: " + aCoord);
+            YAHOO.util.Dom.setXY(moveEl, aCoord);
+        };
+
+        /**
+         * Gets the client height
+         *
+         * @return {int} client height in px
+         */
+        this.getClientHeight = function() {
+            return (window.innerHeight) ? window.innerHeight :
+                (document.documentElement && document.documentElement.clientHeight) ?
+                document.documentElement.clientHeight : document.body.offsetHeight;
+        };
+
+        /**
+         * Gets the client width
+         *
+         * @return {int} client width in px
+         */
+        this.getClientWidth = function() {
+            return (window.innerWidth) ? window.innerWidth :
+                (document.documentElement && document.documentElement.clientWidth) ?
+                document.documentElement.clientWidth : document.body.offsetWidth;
+        };
+
+        /**
+         * numeric array sort function
+         */
+        this.numericSort = function(a, b) { return (a - b); };
+
+        /**
+         * @private
+         */
+        this._timeoutCount = 0;
+
+        /**
+         * @private
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         */
+        this._addListeners = function() {
+            if ( UTIL.Event &&
+                 document          &&
+                 document.body        ) {
+
+                this._onLoad();
+            } else {
+                if (this._timeoutCount > 500) {
+                    this.logger.debug("DragDrop requires the Event Utility");
+                } else {
+                    setTimeout("YAHOO.util.DDM._addListeners()", 10);
+                    this._timeoutCount += 1;
+                }
+            }
+
+        };
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for
+         * the handle element in order to determine wheter or not it was
+         * clicked.
+         *
+         * @param node the html element to inspect
+         */
+        this.handleWasClicked = function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                this.logger.debug("clicked node is a handle");
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+                // this.logger.debug("p: " + p);
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        this.logger.debug(p.id + " is not a handle");
+                        p = p.parentNode;
+                    }
+                }
+            }
+
+            return false;
+        };
+
+    };
+
+    // shorter alias, save a few bytes
+    YAHOO.util.DDM = YAHOO.util.DragDropMgr;
+    YAHOO.util.DDM._addListeners();
+
+}
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation where the linked element follows the
+ * mouse cursor.
+ *
+ * @extends DragDrop
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ */
+YAHOO.util.DD = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+        this.logger.setModuleName("DD");
+    }
+};
+
+YAHOO.util.DD.prototype = new YAHOO.util.DragDrop();
+
+/**
+ * Should we auto-scroll? Defaults to true
+ *
+ * @type boolean
+ */
+YAHOO.util.DD.prototype.scroll = true;
+
+/**
+ * Sets the pointer offset to the distance between the linked element's top
+ * left corner and the location the element was clicked
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ */
+YAHOO.util.DD.prototype.autoOffset = function(iPageX, iPageY) {
+    var el = this.getEl();
+    var aCoord = YAHOO.util.Dom.getXY(el);
+    var x = iPageX - aCoord[0];
+    var y = iPageY - aCoord[1];
+    this.setDelta(x, y);
+    this.logger.debug("autoOffset el pos: " + aCoord + ", delta: " + x + "," + y);
+};
+
+/**
+ * Sets the pointer offset.  You can call this directly to force the offset to
+ * be in a particular location (e.g., pass in 0,0 to set it to the center of the
+ * object, as done in ygDDSliderBG)
+ *
+ * @param {int} iDeltaX the distance from the left
+ * @param {int} iDeltaY the distance from the top
+ */
+YAHOO.util.DD.prototype.setDelta = function(iDeltaX, iDeltaY) {
+    this.deltaX = iDeltaX;
+    this.deltaY = iDeltaY;
+    this.logger.debug("deltaX:" + this.deltaX + ", deltaY:" + this.deltaY);
+};
+
+/**
+ * Sets the drag element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+
+YAHOO.util.DD.prototype.setDragElPos = function(iPageX, iPageY) {
+    this.alignElWithMouse(this.getDragEl(), iPageX, iPageY);
+};
+
+/**
+ * Sets the element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {HTMLElement} el the element to move
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+YAHOO.util.DD.prototype.alignElWithMouse = function(el, iPageX, iPageY) {
+    var oCoord = this.getTargetCoord(iPageX, iPageY);
+    var aCoord = [oCoord.x, oCoord.y];
+    // this.logger.debug("****alignElWithMouse : " + el.id + ", " + aCoord + ", " + el.style.display);
+    YAHOO.util.Dom.setXY(el, aCoord);
+
+    this.cachePosition(oCoord.x, oCoord.y);
+
+    this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+};
+
+/**
+ * Saves the most recent position so that we can reset the constraints and
+ * tick marks on-demand.  We need to know this so that we can calculate the
+ * number of pixels the element is offset from its original position.
+ */
+YAHOO.util.DD.prototype.cachePosition = function(iPageX, iPageY) {
+    if (iPageX) {
+        this.lastPageX = iPageX;
+        this.lastPageY = iPageY;
+    } else {
+        var aCoord = YAHOO.util.Dom.getXY(this.getEl());
+        this.lastPageX = aCoord[0];
+        this.lastPageY = aCoord[1];
+    }
+};
+
+/**
+ * Auto-scroll the window if the dragged object has been moved beyond the
+ * visible window boundary.
+ *
+ * @param {int} x the drag element's x position
+ * @param {int} y the drag element's y position
+ * @param {int} h the height of the drag element
+ * @param {int} w the width of the drag element
+ * @private
+ */
+YAHOO.util.DD.prototype.autoScroll = function(x, y, h, w) {
+
+    if (this.scroll) {
+        // The client height
+        var clientH = this.DDM.getClientHeight();
+
+        // The client width
+        var clientW = this.DDM.getClientWidth();
+
+        // The amt scrolled down
+        var st = this.DDM.getScrollTop();
+
+        // The amt scrolled right
+        var sl = this.DDM.getScrollLeft();
+
+        // Location of the bottom of the element
+        var bot = h + y;
+
+        // Location of the right of the element
+        var right = w + x;
+
+        // The distance from the cursor to the bottom of the visible area,
+        // adjusted so that we don't scroll if the cursor is beyond the
+        // element drag constraints
+        var toBot = (clientH + st - y - this.deltaY);
+
+        // The distance from the cursor to the right of the visible area
+        var toRight = (clientW + sl - x - this.deltaX);
+
+        // this.logger.debug( " x: " + x + " y: " + y + " h: " + h +
+        // " clientH: " + clientH + " clientW: " + clientW +
+        // " st: " + st + " sl: " + sl + " bot: " + bot +
+        // " right: " + right + " toBot: " + toBot + " toRight: " + toRight);
+
+        // How close to the edge the cursor must be before we scroll
+        // var thresh = (document.all) ? 100 : 40;
+        var thresh = 40;
+
+        // How many pixels to scroll per autoscroll op.  This helps to reduce
+        // clunky scrolling. IE is more sensitive about this ... it needs this
+        // value to be higher.
+        var scrAmt = (document.all) ? 80 : 30;
+
+        // Scroll down if we are near the bottom of the visible page and the
+        // obj extends below the crease
+        if ( bot > clientH && toBot < thresh ) {
+            window.scrollTo(sl, st + scrAmt);
+        }
+
+        // Scroll up if the window is scrolled down and the top of the object
+        // goes above the top border
+        if ( y < st && st > 0 && y - st < thresh ) {
+            window.scrollTo(sl, st - scrAmt);
+        }
+
+        // Scroll right if the obj is beyond the right border and the cursor is
+        // near the border.
+        if ( right > clientW && toRight < thresh ) {
+            window.scrollTo(sl + scrAmt, st);
+        }
+
+        // Scroll left if the window has been scrolled to the right and the obj
+        // extends past the left border
+        if ( x < sl && sl > 0 && x - sl < thresh ) {
+            window.scrollTo(sl - scrAmt, st);
+        }
+    }
+};
+
+/**
+ * Finds the location the element should be placed if we want to move
+ * it to where the mouse location less the click offset would place us.
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ * @return an object that contains the coordinates (Object.x and Object.y)
+ * @private
+ */
+YAHOO.util.DD.prototype.getTargetCoord = function(iPageX, iPageY) {
+
+    // this.logger.debug("getTargetCoord: " + iPageX + ", " + iPageY);
+
+    var x = iPageX - this.deltaX;
+    var y = iPageY - this.deltaY;
+
+    if (this.constrainX) {
+        if (x < this.minX) { x = this.minX; }
+        if (x > this.maxX) { x = this.maxX; }
+    }
+
+    if (this.constrainY) {
+        if (y < this.minY) { y = this.minY; }
+        if (y > this.maxY) { y = this.maxY; }
+    }
+
+    x = this.getTick(x, this.xTicks);
+    y = this.getTick(y, this.yTicks);
+
+    // this.logger.debug("getTargetCoord " +
+            // " iPageX: " + iPageX +
+            // " iPageY: " + iPageY +
+            // " x: " + x + ", y: " + y);
+
+    return {x:x, y:y};
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4MouseDown = function(e) {
+    // this.resetConstraints();
+    this.autoOffset(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4Drag = function(e) {
+    this.setDragElPos(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Debugging ygDragDrop events that can be overridden
+///////////////////////////////////////////////////////////////////////////////
+/*
+YAHOO.util.DD.prototype.startDrag = function(x, y) {
+    this.logger.debug(this.id.toString()  + " startDrag");
+};
+
+YAHOO.util.DD.prototype.onDrag = function(e) {
+    this.logger.debug(this.id.toString() + " onDrag");
+};
+
+YAHOO.util.DD.prototype.onDragEnter = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragEnter: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragOver = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragOver: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragOut = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragOut: " + id);
+};
+
+YAHOO.util.DD.prototype.onDragDrop = function(e, id) {
+    this.logger.debug(this.id.toString() + " onDragDrop: " + id);
+};
+
+YAHOO.util.DD.prototype.endDrag = function(e) {
+    this.logger.debug(this.id.toString() + " endDrag");
+};
+*/
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * @extends YAHOO.util.DD
+ * @constructor
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DDProxy = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+        this.initFrame();
+        this.logger.setModuleName("DDProxy");
+    }
+};
+
+YAHOO.util.DDProxy.prototype = new YAHOO.util.DD();
+
+/**
+ * A reference to the one div element we create for all instances of this class
+ *
+ * @type Object
+ */
+YAHOO.util.DDProxy.frameDiv = null;
+
+/**
+ * the drag frame div id
+ *
+ * @type String
+ */
+YAHOO.util.DDProxy.dragElId = "ygddfdiv";
+
+/**
+ * The border width of the frame.  This is used when we resize the frame to
+ * the size of the linked element.  We substract the border width to make
+ * the div the correct size.
+ *
+ * @TODO find a better way to handle this
+ *
+ * @type int
+ */
+YAHOO.util.DDProxy.prototype.borderWidth = 2;
+
+/**
+ * By default we resize the drag frame to be the same size as the element
+ * we want to drag (this is to get the frame effect).  We can turn it off
+ * if we want a different behavior (ex: ygDDMy2)
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.resizeFrame = true;
+
+/**
+ * By default the frame is positioned exactly where the drag element is, so
+ * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
+ * you do not have constraints on the obj is to have the drag frame centered
+ * around the cursor.  Set centerFrame to true for this effect.  Ex:
+ * ygDDMy2
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.centerFrame = false;
+
+/**
+ * Create the drag frame if needed
+ */
+YAHOO.util.DDProxy.createFrame = function() {
+    var THIS = YAHOO.util.DDProxy;
+
+    if (!document || !document.body) {
+        setTimeout(THIS.createFrame, 50);
+        return;
+    }
+
+    if (!THIS.frameDiv) {
+        THIS.frameDiv = document.createElement("div");
+        THIS.frameDiv.id = THIS.dragElId;
+        var s = THIS.frameDiv.style;
+        s.position = "absolute";
+        s.visibility = "hidden";
+        s.cursor = "move";
+        s.border = "2px solid #aaa";
+        s.zIndex = 999;
+
+        document.body.appendChild(THIS.frameDiv);
+    }
+};
+
+/**
+ * Initialization for the drag frame element.  Must be called in the
+ * constructor of all subclasses
+ */
+YAHOO.util.DDProxy.prototype.initFrame = function() {
+    YAHOO.util.DDProxy.createFrame();
+    this.setDragElId(YAHOO.util.DDProxy.dragElId);
+    this.useAbsMath = true;
+};
+
+/**
+ * Resizes the drag frame to the dimensions of the clicked object, positions
+ * it over the object, and finally displays it
+ *
+ * @param {int} iPageX X click position
+ * @param {int} iPageY Y click position
+ * @private
+ */
+YAHOO.util.DDProxy.prototype.showFrame = function(iPageX, iPageY) {
+    var el = this.getEl();
+
+    var s = this.getDragEl().style;
+
+    if (this.resizeFrame) {
+        s.width = (parseInt(el.offsetWidth) - (2*this.borderWidth)) + "px";
+        s.height = (parseInt(el.offsetHeight) - (2*this.borderWidth)) + "px";
+    }
+
+    if (this.centerFrame) {
+        this.setDelta(Math.round(parseInt(s.width)/2),
+                Math.round(parseInt(s.width)/2));
+    }
+
+    this.setDragElPos(iPageX, iPageY);
+
+    s.visibility = "";
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4MouseDown = function(e) {
+    var x = YAHOO.util.Event.getPageX(e);
+    var y = YAHOO.util.Event.getPageY(e);
+    this.autoOffset(x, y);
+    this.setDragElPos(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4StartDrag = function(x, y) {
+    // show the drag frame
+    this.logger.debug("start drag show frame, x: " + x + ", y: " + y);
+    this.showFrame(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4EndDrag = function(e) {
+    this.logger.debug(this.id + " b4EndDrag");
+
+    // hide the drag frame
+    var s = this.getDragEl().style;
+    s.visibility = "hidden";
+};
+
+// overrides YAHOO.util.DragDrop
+// By default we try to move the element to the last location of the frame.
+// This is so that the default behavior mirrors that of YAHOO.util.DD.
+YAHOO.util.DDProxy.prototype.endDrag = function(e) {
+    this.logger.debug(this.id + " endDrag");
+    var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    del.style.visibility = "";
+
+    // Hide the linked element before the move to get around a Safari
+    // rendering bug.
+    lel.style.visibility = "hidden";
+    YAHOO.util.DDM.moveToEl(lel, del);
+    del.style.visibility = "hidden";
+    lel.style.visibility = "";
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that does not move, but can be a drop
+ * target.  You would get the same result by simply omitting implementation
+ * for the event callbacks, but this way we reduce the processing cost of the
+ * event listener and the callbacks.
+ *
+ * @extends YAHOO.util.DragDrop
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+
+YAHOO.util.DDTarget = function(id, sGroup) {
+    if (id) {
+        this.initTarget(id, sGroup);
+        this.logger.setModuleName("DDTarget");
+    }
+};
+
+YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dragdrop.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dragdrop.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/dragdrop.js	(revision 24065)
@@ -0,0 +1,2426 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Defines the interface and base operation of items that that can be
+ * dragged or can be drop targets.  It was designed to be extended, overriding
+ * the event handlers for startDrag, onDrag, onDragOver, onDragOut.
+ * Up to three html elements can be associated with a DragDrop instance:
+ * <ul>
+ * <li>linked element: the element that is passed into the constructor.
+ * This is the element which defines the boundaries for interaction with
+ * other DragDrop objects.</li>
+ * <li>handle element(s): The drag operation only occurs if the element that
+ * was clicked matches a handle element.  By default this is the linked
+ * element, but there are times that you will want only a portion of the
+ * linked element to initiate the drag operation, and the setHandleElId()
+ * method provides a way to define this.</li>
+ * <li>drag element: this represents an the element that would be moved along
+ * with the cursor during a drag operation.  By default, this is the linked
+ * element itself as in {@link YAHOO.util.DD}.  setDragElId() lets you define
+ * a separate element that would be moved, as in {@link YAHOO.util.DDProxy}
+ * </li>
+ * </ul>
+ * This class should not be instantiated until the onload event to ensure that
+ * the associated elements are available.
+ * The following would define a DragDrop obj that would interact with any
+ * other * DragDrop obj in the "group1" group:
+ * <pre>
+ *  dd = new YAHOO.util.DragDrop("div1", "group1");
+ * </pre>
+ * Since none of the event handlers have been implemented, nothing would
+ * actually happen if you were to run the code above.  Normally you would
+ * override this class or one of the default implementations, but you can
+ * also override the methods you want on an instance of the class...
+ * <pre>
+ *  dd.onDragDrop = function(e, id) {
+ *   alert("dd was dropped on " + id);
+ *  }
+ * </pre>
+ * @constructor
+ * @param {String} id of the element that is linked to this instance
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DragDrop = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+    }
+};
+
+YAHOO.util.DragDrop.prototype = {
+
+    /**
+     * The id of the element associated with this object.  This is what we
+     * refer to as the "linked element" because the size and position of
+     * this element is used to determine when the drag and drop objects have
+     * interacted.
+     *
+     * @type String
+     */
+    id: null,
+
+    /**
+     * The id of the element that will be dragged.  By default this is same
+     * as the linked element , but could be changed to another element. Ex:
+     * YAHOO.util.DDProxy
+     *
+     * @type String
+     * @private
+     */
+    dragElId: null,
+
+    /**
+     * the id of the element that initiates the drag operation.  By default
+     * this is the linked element, but could be changed to be a child of this
+     * element.  This lets us do things like only starting the drag when the
+     * header element within the linked html element is clicked.
+     *
+     * @type String
+     * @private
+     */
+    handleElId: null,
+
+    /**
+     * An array of HTML tags that will be ignored if clicked.
+     */
+    invalidHandleTypes: null,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageX: 0,
+
+    /**
+     * The linked element's absolute X position at the time the drag was
+     * started
+     *
+     * @type int
+     * @private
+     */
+    startPageY: 0,
+
+    /**
+     * The group defines a logical collection of DragDrop objects that are
+     * related.  Instances only get events when interacting with other
+     * DragDrop object in the same group.  This lets us define multiple
+     * groups using a single DragDrop subclass if we want.
+     *
+     */
+    groups: null,
+
+    /**
+     * Individual drag/drop instances can be locked.  This will prevent
+     * onmousedown start drag.
+     *
+     * @type boolean
+     * @private
+     */
+    locked: false,
+
+    /**
+     * Lock this instance
+     */
+    lock: function() { this.locked = true; },
+
+    /**
+     * Unlock this instace
+     */
+    unlock: function() { this.locked = false; },
+
+    /**
+     * By default, all insances can be a drop target.  This can be disabled by
+     * setting isTarget to false.
+     *
+     * @type boolean
+     */
+    isTarget: true,
+
+    /**
+     * The padding configured for this drag and drop object for calculating
+     * the drop zone intersection with this object.
+     */
+    padding: null,
+
+    /**
+     * @private
+     */
+    _domRef: null,
+
+    /**
+     * Internal typeof flag
+     * @private
+     */
+    __ygDragDrop: true,
+
+    /**
+     * Set to true when horizontal contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainX: false,
+
+    /**
+     * Set to true when vertical contraints are applied
+     *
+     * @type boolean
+     * @private
+     */
+    constrainY: false,
+
+    /**
+     * The left constraint
+     *
+     * @type int
+     * @private
+     */
+    minX: 0,
+
+    /**
+     * The right constraint
+     *
+     * @type int
+     * @private
+     */
+    maxX: 0,
+
+    /**
+     * The up constraint
+     *
+     * @type int
+     * @private
+     */
+    minY: 0,
+
+    /**
+     * The down constraint
+     *
+     * @type int
+     * @private
+     */
+    maxY: 0,
+
+    /**
+     * Maintain offsets when we resetconstraints.  Used to maintain the
+     * slider thumb value, and this needs to be fixed.
+     * @type boolean
+     */
+    maintainOffset: false,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * horizontal graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    xTicks: null,
+
+    /**
+     * Array of pixel locations the element will snap to if we specified a
+     * vertical graduation/interval.  This array is generated automatically
+     * when you define a tick interval.
+     * @type int[]
+     */
+    yTicks: null,
+
+    /**
+     * By default the drag and drop instance will only respond to the primary
+     * button click (left button for a right-handed mouse).  Set to true to
+     * allow drag and drop to start with any mouse click that is propogated
+     * by the browser
+     * @type boolean
+     */
+    primaryButtonOnly: true,
+
+    /**
+     * Code that executes immediately before the startDrag event
+     * @private
+     */
+    b4StartDrag: function(x, y) { },
+
+    /**
+     * Abstract method called after a drag/drop object is clicked
+     * and the drag or mousedown time thresholds have beeen met.
+     *
+     * @param {int} X click location
+     * @param {int} Y click location
+     */
+    startDrag: function(x, y) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDrag event
+     * @private
+     */
+    b4Drag: function(e) { },
+
+    /**
+     * Abstract method called during the onMouseMove event while dragging an
+     * object.
+     *
+     * @param {Event} e
+     */
+    onDrag: function(e) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragEnter event
+     * @private
+     */
+    // b4DragEnter: function(e) { },
+
+    /**
+     * Abstract method called when this element fist begins hovering over
+     * another DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of one or more
+     * dragdrop items being hovered over.
+     */
+    onDragEnter: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOver event
+     * @private
+     */
+    b4DragOver: function(e) { },
+
+    /**
+     * Abstract method called when this element is hovering over another
+     * DragDrop obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this is hovering over.  In INTERSECT mode, an array of dd items
+     * being hovered over.
+     */
+    onDragOver: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragOut event
+     * @private
+     */
+    b4DragOut: function(e) { },
+
+    /**
+     * Abstract method called when we are no longer hovering over an element
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was hovering over.  In INTERSECT mode, an array of dd items
+     * that the mouse is no longer over.
+     */
+    onDragOut: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the onDragDrop event
+     * @private
+     */
+    b4DragDrop: function(e) { },
+
+    /**
+     * Abstract method called when this item is dropped on another DragDrop
+     * obj
+     *
+     * @param {Event} e
+     * @param {String || YAHOO.util.DragDrop[]} id In POINT mode, the element
+     * id this was dropped on.  In INTERSECT mode, an array of dd items this
+     * was dropped on.
+     */
+    onDragDrop: function(e, id) { /* override this */ },
+
+    /**
+     * Code that executes immediately before the endDrag event
+     * @private
+     */
+    b4EndDrag: function(e) { },
+
+    /**
+     * Fired when we are done dragging the object
+     *
+     * @param {Event} e
+     */
+    endDrag: function(e) { /* override this */ },
+
+    /**
+     * Code executed immediately before the onMouseDown event
+
+     * @param {Event} e
+     * @private
+     */
+    b4MouseDown: function(e) {  },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mousedown
+     * @param {Event} e
+     */
+    onMouseDown: function(e) { /* override this */ },
+
+    /**
+     * Event handler that fires when a drag/drop obj gets a mouseup
+     * @param {Event} e
+     */
+    onMouseUp: function(e) { /* override this */ },
+
+    /**
+     * Returns a reference to the linked element
+     *
+     * @return {Object} the html element
+     */
+    getEl: function() {
+        if (!this._domRef) {
+            this._domRef = this.DDM.getElement(this.id);
+        }
+
+        return this._domRef;
+    },
+
+    /**
+     * Returns a reference to the actual element to drag.  By default this is
+     * the same as the html element, but it can be assigned to another
+     * element. An example of this can be found in YAHOO.util.DDProxy
+     *
+     * @return {Object} the html element
+     */
+    getDragEl: function() {
+        return this.DDM.getElement(this.dragElId);
+    },
+
+    /**
+     * Sets up the DragDrop object.  Must be called in the constructor of any
+     * YAHOO.util.DragDrop subclass
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    init: function(id, sGroup) {
+        this.initTarget(id, sGroup);
+        YAHOO.util.Event.addListener(id, "mousedown",
+                                          this.handleMouseDown, this, true);
+    },
+
+    /**
+     * Initializes Targeting functionality only... the object does not
+     * get a mousedown handler.
+     *
+     * @param id the id of the linked element
+     * @param {String} sGroup the group of related items
+     * element is supposed to be a target only, set to false.
+     */
+    initTarget: function(id, sGroup) {
+
+        // create a local reference to the drag and drop manager
+        this.DDM = YAHOO.util.DDM;
+
+
+        // set the default padding
+        this.padding = [0, 0, 0, 0];
+
+        // initialize the groups array
+        this.groups = {};
+
+        // set the id
+        this.id = id;
+
+        // the element is a drag handle by default
+        this.setDragElId(id);
+
+        // by default, clicked anchors will not start drag operations
+        this.invalidHandleTypes = {a : "a"};
+
+        // We don't want to register this as the handle with the manager
+        // so we just set the id rather than calling the setter
+        this.handleElId = id;
+
+        // cache the position of the element if we can
+        if (document && document.body) {
+            this.setInitPosition();
+        }
+
+        // add to an interaction group
+        this.addToGroup((sGroup) ? sGroup : "default");
+
+    },
+
+    /**
+     * Configures the padding for the target zone in px.  Effectively expands
+     * (or reduces) the virtual object size for targeting calculations.
+     * Supports css-style shorthand; if only one parameter is passed, all sides
+     * will have that padding, and if only two are passed, the top and bottom
+     * will have the first param, the left and right the second.
+     * @param {int} iTop    Top pad
+     * @param {int} iRight  Right pad
+     * @param {int} iBot    Bot pad
+     * @param {int} iLeft   Left pad
+     */
+    setPadding: function(iTop, iRight, iBot, iLeft) {
+        // this.padding = [iLeft, iRight, iTop, iBot];
+        if (!iRight && 0 !== iRight) {
+            this.padding = [iTop, iTop, iTop, iTop];
+        } else if (!iBot && 0 !== iBot) {
+            this.padding = [iTop, iRight, iTop, iRight];
+        } else {
+            this.padding = [iTop, iRight, iBot, iLeft];
+        }
+    },
+
+    /**
+     * Stores the initial placement of the dd element
+     */
+    setInitPosition: function(diffX, diffY) {
+        var el = this.getEl();
+
+        if (!this.DDM.verifyEl(el)) {
+            return;
+        }
+
+        var dx = diffX || 0;
+        var dy = diffY || 0;
+
+        var p = YAHOO.util.Dom.getXY( el );
+
+        this.initPageX = p[0] - dx;
+        this.initPageY = p[1] - dy;
+
+        this.lastPageX = p[0];
+        this.lastPageY = p[1];
+
+        this.setStartPosition(p);
+    },
+
+    /**
+     * Sets the start position of the element.  This is set when the obj
+     * is initialized, the reset when a drag is started.
+     * @param pos current position (from previous lookup)
+     * @private
+     */
+    setStartPosition: function(pos) {
+
+        var p = pos || YAHOO.util.Dom.getXY( this.getEl() );
+
+        this.startPageX = p[0];
+        this.startPageY = p[1];
+    },
+
+    /**
+     * Add this instance to a group of related drag/drop objects.  All
+     * instances belong to at least one group, and can belong to as many
+     * groups as needed.
+     *
+     * @param sGroup {string} the name of the group
+     */
+    addToGroup: function(sGroup) {
+        this.groups[sGroup] = true;
+        this.DDM.regDragDrop(this, sGroup);
+    },
+
+    /**
+     * Allows you to specify that an element other than the linked element
+     * will be moved with the cursor during a drag
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setDragElId: function(id) {
+        this.dragElId = id;
+    },
+
+    /**
+     * Allows you to specify a child of the linked element that should be
+     * used to initiate the drag operation.  An example of this would be if
+     * you have a content div with text and links.  Clicking anywhere in the
+     * content area would normally start the drag operation.  Use this method
+     * to specify that an element inside of the content div is the element
+     * that starts the drag operation.
+     *
+     * @param id the id of the element that will be used to initiate the drag
+     */
+    setHandleElId: function(id) {
+        this.handleElId = id;
+        this.DDM.regHandle(this.id, id);
+    },
+
+    /**
+     * Allows you to set an element outside of the linked element as a drag
+     * handle
+     */
+    setOuterHandleElId: function(id) {
+        YAHOO.util.Event.addListener(id, "mousedown",
+                this.handleMouseDown, this, true);
+        this.setHandleElId(id);
+    },
+
+    /**
+     * Remove all drag and drop hooks for this element
+     */
+    unreg: function() {
+        YAHOO.util.Event.removeListener(this.id, "mousedown",
+                this.handleMouseDown);
+        this._domRef = null;
+        this.DDM._remove(this);
+    },
+
+    /**
+     * Returns true if this instance is locked, or the drag drop mgr is locked
+     * (meaning that all drag/drop is disabled on the page.)
+     *
+     * @return {boolean} true if this obj or all drag/drop is locked, else
+     * false
+     */
+    isLocked: function() {
+        return (this.DDM.isLocked() || this.locked);
+    },
+
+    /**
+     * Fired when this object is clicked
+     *
+     * @param {Event} e
+     * @param {YAHOO.util.DragDrop} oDD the clicked dd object (this dd obj)
+     * @private
+     */
+    handleMouseDown: function(e, oDD) {
+
+
+        var EU = YAHOO.util.Event;
+
+
+        var button = e.which || e.button;
+
+        if (this.primaryButtonOnly && button > 1) {
+            return;
+        }
+
+        if (this.isLocked()) {
+            return;
+        }
+
+
+        this.DDM.refreshCache(this.groups);
+
+        // Only process the event if we really clicked within the linked
+        // element.  The reason we make this check is that in the case that
+        // another element was moved between the clicked element and the
+        // cursor in the time between the mousedown and mouseup events. When
+        // this happens, the element gets the next mousedown event
+        // regardless of where on the screen it happened.
+        var pt = new YAHOO.util.Point(EU.getPageX(e), EU.getPageY(e));
+        if ( this.DDM.isOverTarget(pt, this) )  {
+
+
+            //  check to see if the handle was clicked
+            var srcEl = EU.getTarget(e);
+
+            if (this.isValidHandleChild(srcEl) &&
+                    (this.id == this.handleElId ||
+                     this.DDM.handleWasClicked(srcEl, this.id)) ) {
+
+                // set the initial element position
+                this.setStartPosition();
+
+
+                this.b4MouseDown(e);
+                this.onMouseDown(e);
+                this.DDM.handleMouseDown(e, this);
+
+                this.DDM.stopEvent(e);
+            }
+        }
+    },
+
+    /**
+     * Allows you to specify a tag name that should not start a drag operation
+     * when clicked.  This is designed to facilitate embedding links within a
+     * drag handle that do something other than start the drag.
+     *
+     * @param {string} tagName the type of element to exclude
+     */
+    addInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = type;
+    },
+
+    /**
+     * Unsets an excluded tag name set by addInvalidHandleType
+     *
+     * @param {string} tagName the type of element to unexclude
+     */
+    removeInvalidHandleType: function(tagName) {
+        var type = tagName.toUpperCase();
+        this.invalidHandleTypes[type] = null;
+    },
+
+    /**
+     * Checks the tag exclusion list to see if this click should be ignored
+     *
+     * @param {ygNode} node
+     * @return {boolean} true if this is a valid tag type, false if not
+     */
+    isValidHandleChild: function(node) {
+        var type = node.nodeName;
+
+        if (type == "#text") {
+            type = node.parentNode.nodeName;
+        }
+
+        return (!this.invalidHandleTypes[type]);
+    },
+
+    /**
+     * Create the array of horizontal tick marks if an interval was specified
+     * in setXConstraint().
+     *
+     * @private
+     */
+    setXTicks: function(iStartX, iTickSize) {
+        this.xTicks = [];
+        this.xTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.xTicks[this.xTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.xTicks.sort(this.DDM.numericSort) ;
+    },
+
+    /**
+     * Create the array of vertical tick marks if an interval was specified in
+     * setYConstraint().
+     *
+     * @private
+     */
+    setYTicks: function(iStartY, iTickSize) {
+        this.yTicks = [];
+        this.yTickSize = iTickSize;
+
+        var tickMap = {};
+
+        for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
+            if (!tickMap[i]) {
+                this.yTicks[this.yTicks.length] = i;
+                tickMap[i] = true;
+            }
+        }
+
+        this.yTicks.sort(this.DDM.numericSort) ;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Use
+     * this method to limit the horizontal travel of the element.  Pass in
+     * 0,0 for the parameters if you want to lock the drag to the y axis.
+     *
+     * @param {int} iLeft the number of pixels the element can move to the left
+     * @param {int} iRight the number of pixels the element can move to the
+     * right
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element
+     * should move iTickSize pixels at a time.
+     */
+    setXConstraint: function(iLeft, iRight, iTickSize) {
+        this.leftConstraint = iLeft;
+        this.rightConstraint = iRight;
+
+        this.minX = this.initPageX - iLeft;
+        this.maxX = this.initPageX + iRight;
+        if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
+
+        this.constrainX = true;
+    },
+
+    /**
+     * By default, the element can be dragged any place on the screen.  Set
+     * this to limit the vertical travel of the element.  Pass in 0,0 for the
+     * parameters if you want to lock the drag to the x axis.
+     *
+     * @param {int} iUp the number of pixels the element can move up
+     * @param {int} iDown the number of pixels the element can move down
+     * @param {int} iTickSize optional parameter for specifying that the
+     * element should move iTickSize pixels at a time.
+     */
+    setYConstraint: function(iUp, iDown, iTickSize) {
+        this.topConstraint = iUp;
+        this.bottomConstraint = iDown;
+
+        this.minY = this.initPageY - iUp;
+        this.maxY = this.initPageY + iDown;
+        if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
+
+        this.constrainY = true;
+
+    },
+
+    /**
+     * resetConstraints must be called if you manually reposition a dd element.
+     * @param {boolean} maintainOffset
+     */
+    resetConstraints: function() {
+
+
+        // figure out how much this thing has moved
+        var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
+        var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
+
+
+        // reset the initial location
+        this.setInitPosition(dx, dy);
+
+        if (this.constrainX) {
+            this.setXConstraint( this.leftConstraint,
+                                 this.rightConstraint,
+                                 this.xTickSize        );
+        }
+
+        if (this.constrainY) {
+            this.setYConstraint( this.topConstraint,
+                                 this.bottomConstraint,
+                                 this.yTickSize         );
+        }
+    },
+
+    /**
+     * Normally the drag element is moved pixel by pixel, but we can specify
+     * that it move a number of pixels at a time.  This method resolves the
+     * location when we have it set up like this.
+     *
+     * @param {int} val where we want to place the object
+     * @param {int[]} tickArray sorted array of valid points
+     * @return {int} the closest tick
+     * @private
+     */
+    getTick: function(val, tickArray) {
+
+        if (!tickArray) {
+            // If tick interval is not defined, it is effectively 1 pixel,
+            // so we return the value passed to us.
+            return val;
+        } else if (tickArray[0] >= val) {
+            // The value is lower than the first tick, so we return the first
+            // tick.
+            return tickArray[0];
+        } else {
+            for (var i = 0; i < tickArray.length; ++i) {
+                var next = i + 1;
+                if (tickArray[next] && tickArray[next] >= val) {
+                    var diff1 = val - tickArray[i];
+                    var diff2 = tickArray[next] - val;
+                    return (diff2 > diff1) ? tickArray[i] : tickArray[next];
+                }
+            }
+
+            // The value is larger than the last tick, so we return the last
+            // tick.
+            return tickArray[tickArray.length - 1];
+        }
+    },
+
+    /**
+     * toString method
+     * @return {string} string representation of the dd obj
+     */
+    toString: function(val, tickArray) {
+        return ("YAHOO.util.DragDrop {" + this.id + "}");
+    }
+
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+// Only load the library once.  Rewriting the manager class would orphan
+// existing drag and drop instances.
+if (!YAHOO.util.DragDropMgr) {
+
+    /**
+     * @class Handles the element interaction for all DragDrop items in the
+     * window.  Generally, you will not call this class directly, but it does
+     * have helper methods that could be useful in your DragDrop
+     * implementations.  This class should not be instantiated; all methods
+     * are are static.
+     *
+     * @constructor
+     */
+    YAHOO.util.DragDropMgr = new function() {
+
+        /**
+         * utility package shorthand
+         * @private
+         */
+        var UTIL = YAHOO.util;
+
+        /**
+         * Two dimensional Array of registered DragDrop objects.  The first
+         * dimension is the DragDrop item group, the second the DragDrop
+         * object.
+         *
+         * @private
+         */
+        this.ids = {};
+
+        /**
+         * Array of element ids defined as drag handles.  Used to determine
+         * if the element that generated the mousedown event is actually the
+         * handle and not the html element itself.
+         *
+         * @private
+         */
+        this.handleIds = {};
+
+        /**
+         * the DragDrop object that is currently being dragged
+         *
+         * @type DragDrop
+         * @private
+         **/
+        this.dragCurrent = null;
+
+        /**
+         * the DragDrop object(s) that are being hovered over
+         *
+         * @type Array
+         * @private
+         */
+        this.dragOvers = {};
+
+        /**
+         * @private
+         */
+
+        /**
+         * the X distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaX = 0;
+
+        /**
+         * the Y distance between the cursor and the object being dragged
+         *
+         * @type int
+         * @private
+         */
+        this.deltaY = 0;
+
+        /**
+         * Flag to determine if we should prevent the default behavior of the
+         * events we define. By default this is true, but this can be set to
+         * false if you need the default behavior (not recommended)
+         *
+         * @type boolean
+         */
+        this.preventDefault = true;
+
+        /**
+         * Flag to determine if we should stop the propagation of the events
+         * we generate. This is true by default but you may want to set it to
+         * false if the html element contains other features that require the
+         * mouse click.
+         *
+         * @type boolean
+         */
+        this.stopPropagation = true;
+
+        /**
+         * @private
+         */
+        this.initalized = false;
+
+        /**
+         * All drag and drop can be disabled.
+         *
+         * @private
+         */
+        this.locked = false;
+
+        /**
+         * Called the first time an element is registered.
+         *
+         * @private
+         */
+        this.init = function() {
+        };
+
+        /**
+         * In point mode, drag and drop interaction is defined by the
+         * location of the cursor during the drag/drop
+         * @type int
+         */
+        this.POINT     = 0;
+
+        /**
+         * In intersect mode, drag and drop interactio nis defined by the
+         * overlap of two or more drag and drop objects.
+         * @type int
+         */
+        this.INTERSECT = 1;
+
+        /**
+         * The current drag and drop mode.  Default it point mode
+         * @type int
+         */
+        this.mode = this.POINT;
+
+        /**
+         * Runs method on all drag and drop objects
+         * @private
+         */
+        this._execOnAll = function(sMethod, args) {
+            for (var i in this.ids) {
+                for (var j in this.ids[i]) {
+                    var oDD = this.ids[i][j];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+                    oDD[sMethod].apply(oDD, args);
+                }
+            }
+        };
+
+        /**
+         * Drag and drop initialization.  Sets up the global event handlers
+         * @private
+         */
+        this._onLoad = function() {
+
+            this._execOnAll("setInitPosition", []);
+
+
+            var EU = UTIL.Event;
+
+            EU.addListener(document, "mouseup",   this.handleMouseUp, this, true);
+            EU.addListener(document, "mousemove", this.handleMouseMove, this, true);
+            EU.addListener(window,   "unload",    this._onUnload, this, true);
+            EU.addListener(window,   "resize",    this._onResize, this, true);
+            // EU.addListener(window,   "mouseout",    this._test);
+
+            this.initalized = true;
+
+        };
+
+        /**
+         * Reset constraints on all drag and drop objs
+         * @private
+         */
+        this._onResize = function(e) {
+            this._execOnAll("resetConstraints", []);
+        };
+
+        /**
+         * Lock all drag and drop functionality
+         */
+        this.lock = function() { this.locked = true; };
+
+        /**
+         * Unlock all drag and drop functionality
+         */
+        this.unlock = function() { this.locked = false; };
+
+        /**
+         * Is drag and drop locked?
+         *
+         * @return {boolean} True if drag and drop is locked, false otherwise.
+         */
+        this.isLocked = function() { return this.locked; };
+
+        /**
+         * Location cache that is set for all drag drop objects when a drag is
+         * initiated, cleared when the drag is finished.
+         *
+         * @private
+         */
+        this.locationCache = {};
+
+        /**
+         * Set useCache to false if you want to force object the lookup of each
+         * drag and drop linked element constantly during a drag.
+         * @type boolean
+         */
+        this.useCache = true;
+
+        /**
+         * The number of pixels that the mouse needs to move after the
+         * mousedown before the drag is initiated.  Default=3;
+         * @type int
+         */
+        this.clickPixelThresh = 3;
+
+        /**
+         * The number of milliseconds after the mousedown event to initiate the
+         * drag if we don't get a mouseup event. Default=1000
+         * @type int
+         */
+        this.clickTimeThresh = 1000;
+
+        /**
+         * Flag that indicates that either the drag pixel threshold or the
+         * mousdown time threshold has been met
+         * @type boolean
+         * @private
+         */
+        this.dragThreshMet = false;
+
+        /**
+         * Timeout used for the click time threshold
+         * @type Object
+         * @private
+         */
+        this.clickTimeout = null;
+
+        /**
+         * The X position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startX = 0;
+
+        /**
+         * The Y position of the mousedown event stored for later use when a
+         * drag threshold is met.
+         * @type int
+         * @private
+         */
+        this.startY = 0;
+
+        /**
+         * Each DragDrop instance must be registered with the DragDropMgr.
+         * This is executed in ygDragDrop.init()
+         *
+         * @param {DragDrop} oDD the DragDrop object to register
+         * @param {String} sGroup the name of the group this element belongs to
+         */
+        this.regDragDrop = function(oDD, sGroup) {
+            if (!this.initialized) { this.init(); }
+
+            if (!this.ids[sGroup]) {
+                this.ids[sGroup] = {};
+            }
+            this.ids[sGroup][oDD.id] = oDD;
+        };
+
+        /**
+         * Unregisters a drag and drop item.  This is executed in
+         * ygDragDrop.unreg, use that method instead of calling this directly.
+         * @private
+         */
+        this._remove = function(oDD) {
+            for (var g in oDD.groups) {
+                if (g && this.ids[g][oDD.id]) {
+                    delete this.ids[g][oDD.id];
+                }
+            }
+            delete this.handleIds[oDD.id];
+        };
+
+        /**
+         * Each DragDrop handle element must be registered.  This is done
+         * automatically when executing ygDragDrop.setHandleElId()
+         *
+         * @param {String} sDDId the DragDrop id this element is a handle for
+         * @param {String} sHandleId the id of the element that is the drag
+         * handle
+         */
+        this.regHandle = function(sDDId, sHandleId) {
+            if (!this.handleIds[sDDId]) {
+                this.handleIds[sDDId] = {};
+            }
+            this.handleIds[sDDId][sHandleId] = sHandleId;
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop item.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop item,
+         * false otherwise
+         */
+        this.isDragDrop = function(id) {
+            return ( this.getDDById(id) ) ? true : false;
+        };
+
+        /**
+         * Returns the drag and drop instances that are in all groups the
+         * passed in instance belongs to.
+         *
+         * @param {ygDragDrop} p_oDD the obj to get related data for
+         * @param {boolean} bTargetsOnly if true, only return targetable objs
+         * @return {ygDragDrop[]} the related instances
+         */
+        this.getRelated = function(p_oDD, bTargetsOnly) {
+            var oDDs = [];
+            for (var i in p_oDD.groups) {
+                for (j in this.ids[i]) {
+                    var dd = this.ids[i][j];
+                    if (! this.isTypeOfDD(dd)) {
+                        continue;
+                    }
+                    if (!bTargetsOnly || dd.isTarget) {
+                        oDDs[oDDs.length] = dd;
+                    }
+                }
+            }
+
+            return oDDs;
+        };
+
+        /**
+         * Returns true if the specified dd target is a legal target for
+         * the specifice drag obj
+         *
+         * @param {ygDragDrop} the drag obj
+         * @param {ygDragDrop) the target
+         * @return {boolean} true if the target is a legal target for the
+         * dd obj
+         */
+        this.isLegalTarget = function (oDD, oTargetDD) {
+            var targets = this.getRelated(oDD);
+            for (var i =0;i<targets.length;++i) {
+                if (targets[i].id == oTargetDD.id) {
+                    return true;
+                }
+            }
+
+            return false;
+        };
+
+        /**
+         * My goal is to be able to transparently determine if an object is
+         * typeof ygDragDrop, and the exact subclass of ygDragDrop.  typeof
+         * returns "object", oDD.constructor.toString() always returns
+         * "ygDragDrop" and not the name of the subclass.  So for now it just
+         * evaluates a well-known variable in ygDragDrop.
+         *
+         * @param {Object} the object to evaluate
+         * @return {boolean} true if typeof oDD = ygDragDrop
+         */
+        this.isTypeOfDD = function (oDD) {
+            return (oDD && oDD.__ygDragDrop);
+        };
+
+        /**
+         * Utility function to determine if a given element has been
+         * registered as a drag drop handle for the given Drag Drop object.
+         *
+         * @param {String} id the element id to check
+         * @return {boolean} true if this element is a DragDrop handle, false
+         * otherwise
+         */
+        this.isHandle = function(sDDId, sHandleId) {
+            return ( this.handleIds[sDDId] &&
+                            this.handleIds[sDDId][sHandleId] );
+        };
+
+        /**
+         * Returns the DragDrop instance for a given id
+         *
+         * @param {String} id the id of the DragDrop object
+         * @return {DragDrop} the drag drop object, null if it is not found
+         */
+        this.getDDById = function(id) {
+            for (var i in this.ids) {
+                if (this.ids[i][id]) {
+                    return this.ids[i][id];
+                }
+            }
+            return null;
+        };
+
+        /**
+         * Fired after a registered DragDrop object gets the mousedown event.
+         * Sets up the events required to track the object being dragged
+         *
+         * @param {Event} e the event
+         * @param oDD the DragDrop object being dragged
+         * @private
+         */
+        this.handleMouseDown = function(e, oDD) {
+            this.dragCurrent = oDD;
+
+            var el = oDD.getEl();
+
+            // track start position
+            this.startX = UTIL.Event.getPageX(e);
+            this.startY = UTIL.Event.getPageY(e);
+
+            this.deltaX = this.startX - el.offsetLeft;
+            this.deltaY = this.startY - el.offsetTop;
+
+            this.dragThreshMet = false;
+
+            this.clickTimeout = setTimeout(
+               "var DDM=YAHOO.util.DDM;DDM.startDrag(DDM.startX, DDM.startY)",
+               this.clickTimeThresh );
+        };
+
+        /**
+         * Fired when either the drag pixel threshol or the mousedown hold
+         * time threshold has been met.
+         *
+         * @param x {int} the X position of the original mousedown
+         * @param y {int} the Y position of the original mousedown
+         */
+        this.startDrag = function(x, y) {
+            clearTimeout(this.clickTimeout);
+            if (this.dragCurrent) {
+                this.dragCurrent.b4StartDrag(x, y);
+                this.dragCurrent.startDrag(x, y);
+            }
+            this.dragThreshMet = true;
+        };
+
+        /**
+         * Internal function to handle the mouseup event.  Will be invoked
+         * from the context of the document.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseUp = function(e) {
+
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            clearTimeout(this.clickTimeout);
+
+            if (this.dragThreshMet) {
+                this.fireEvents(e, true);
+            } else {
+            }
+
+            this.stopDrag(e);
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Utility to stop event propagation and event default, if these
+         * features are turned on.
+         *
+         * @param {Event} e the event as returned by this.getEvent()
+         */
+        this.stopEvent = function(e) {
+            if (this.stopPropagation) {
+                UTIL.Event.stopPropagation(e);
+            }
+
+            if (this.preventDefault) {
+                UTIL.Event.preventDefault(e);
+            }
+        };
+
+        /**
+         * Internal function to clean up event handlers after the drag
+         * operation is complete
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.stopDrag = function(e) {
+
+            // Fire the drag end event for the item that was dragged
+            if (this.dragCurrent) {
+                if (this.dragThreshMet) {
+                    this.dragCurrent.b4EndDrag(e);
+                    this.dragCurrent.endDrag(e);
+                }
+
+                this.dragCurrent.onMouseUp(e);
+            }
+
+            this.dragCurrent = null;
+            this.dragOvers = {};
+        };
+
+        /**
+         * Internal function to handle the mousemove event.  Will be invoked
+         * from the context of the html element.
+         *
+         * @TODO figure out what we can do about mouse events lost when the
+         * user drags objects beyond the window boundary.  Currently we can
+         * detect this in internet explorer by verifying that the mouse is
+         * down during the mousemove event.  Firefox doesn't give us the
+         * button state on the mousemove event.
+         *
+         * @param {Event} e the event
+         * @private
+         */
+        this.handleMouseMove = function(e) {
+            if (! this.dragCurrent) {
+                return;
+            }
+
+            // var button = e.which || e.button;
+
+
+            // check for IE mouseup outside of page boundary
+            if (UTIL.Event.isIE && !e.button) {
+                this.stopEvent(e);
+                return this.handleMouseUp(e);
+            }
+
+            if (!this.dragThreshMet) {
+                var diffX = Math.abs(this.startX - UTIL.Event.getPageX(e));
+                var diffY = Math.abs(this.startY - UTIL.Event.getPageY(e));
+                if (diffX > this.clickPixelThresh ||
+                            diffY > this.clickPixelThresh) {
+                    this.startDrag(this.startX, this.startY);
+                }
+            }
+
+            if (this.dragThreshMet) {
+                this.dragCurrent.b4Drag(e);
+                this.dragCurrent.onDrag(e);
+                this.fireEvents(e, false);
+            }
+
+            this.stopEvent(e);
+        };
+
+        /**
+         * Iterates over all of the DragDrop elements to find ones we are
+         * hovering over or dropping on
+         *
+         * @param {Event} e the event
+         * @param {boolean} isDrop is this a drop op or a mouseover op?
+         * @private
+         */
+        this.fireEvents = function(e, isDrop) {
+            var dc = this.dragCurrent;
+
+            // If the user did the mouse up outside of the window, we could
+            // get here even though we have ended the drag.
+            if (!dc || dc.isLocked()) {
+                return;
+            }
+
+            var x = UTIL.Event.getPageX(e);
+            var y = UTIL.Event.getPageY(e);
+            var pt = new YAHOO.util.Point(x,y);
+
+            // cache the previous dragOver array
+            var oldOvers = [];
+
+            var outEvts   = [];
+            var overEvts  = [];
+            var dropEvts  = [];
+            var enterEvts = [];
+
+            // Check to see if the object we were hovering over is no longer
+            // being hovered over so we can fire the onDragOut event
+            for (var i in this.dragOvers) {
+
+                var ddo = this.dragOvers[i];
+
+                if (! this.isTypeOfDD(ddo)) {
+                    continue;
+                }
+
+                if (! this.isOverTarget(pt, ddo, this.mode)) {
+                    outEvts.push( ddo );
+                }
+
+                oldOvers[i] = true;
+                delete this.dragOvers[i];
+            }
+
+            for (var sGroup in dc.groups) {
+
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+                    if (! this.isTypeOfDD(oDD)) {
+                        continue;
+                    }
+
+                    if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
+                        if (this.isOverTarget(pt, oDD, this.mode)) {
+                            // look for drop interactions
+                            if (isDrop) {
+                                dropEvts.push( oDD );
+                            // look for drag enter and drag over interactions
+                            } else {
+
+                                // initial drag over: dragEnter fires
+                                if (!oldOvers[oDD.id]) {
+                                    enterEvts.push( oDD );
+                                // subsequent drag overs: dragOver fires
+                                } else {
+                                    overEvts.push( oDD );
+                                }
+
+                                this.dragOvers[oDD.id] = oDD;
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (this.mode) {
+                if (outEvts.length > 0) {
+                    dc.b4DragOut(e, outEvts);
+                    dc.onDragOut(e, outEvts);
+                }
+
+                if (enterEvts.length > 0) {
+                    dc.onDragEnter(e, enterEvts);
+                }
+
+                if (overEvts.length > 0) {
+                    dc.b4DragOver(e, overEvts);
+                    dc.onDragOver(e, overEvts);
+                }
+
+                if (dropEvts.length > 0) {
+                    dc.b4DragDrop(e, dropEvts);
+                    dc.onDragDrop(e, dropEvts);
+                }
+
+            } else {
+                // fire dragout events
+                for (i=0; i < outEvts.length; ++i) {
+                    dc.b4DragOut(e, outEvts[i].id);
+                    dc.onDragOut(e, outEvts[i].id);
+                }
+
+                // fire enter events
+                for (i=0; i < enterEvts.length; ++i) {
+                    // dc.b4DragEnter(e, oDD.id);
+                    dc.onDragEnter(e, enterEvts[i].id);
+                }
+
+                // fire over events
+                for (i=0; i < overEvts.length; ++i) {
+                    dc.b4DragOver(e, overEvts[i].id);
+                    dc.onDragOver(e, overEvts[i].id);
+                }
+
+                // fire drop events
+                for (i=0; i < dropEvts.length; ++i) {
+                    dc.b4DragDrop(e, dropEvts[i].id);
+                    dc.onDragDrop(e, dropEvts[i].id);
+                }
+
+            }
+
+        };
+
+        /**
+         * Helper function for getting the best match from the list of drag
+         * and drop objects returned by the drag and drop events when we are
+         * in INTERSECT mode.  It returns either the first object that the
+         * cursor is over, or the object that has the greatest overlap with
+         * the dragged element.
+         *
+         * @param  {ygDragDrop[]} dds The array of drag and drop objects
+         * targeted
+         * @return {ygDragDrop}       The best single match
+         */
+        this.getBestMatch = function(dds) {
+            var winner = null;
+            // Return null if the input is not what we expect
+            //if (!dds || !dds.length || dds.length == 0) {
+               // winner = null;
+            // If there is only one item, it wins
+            //} else if (dds.length == 1) {
+
+            if (dds.length == 1) {
+                winner = dds[0];
+            } else {
+                // Loop through the targeted items
+                for (var i=0; i<dds.length; ++i) {
+                    var dd = dds[i];
+                    // If the cursor is over the object, it wins.  If the
+                    // cursor is over multiple matches, the first one we come
+                    // to wins.
+                    if (dd.cursorIsOver) {
+                        winner = dd;
+                        break;
+                    // Otherwise the object with the most overlap wins
+                    } else {
+                        if (!winner ||
+                            winner.overlap.getArea() < dd.overlap.getArea()) {
+                            winner = dd;
+                        }
+                    }
+                }
+            }
+
+            return winner;
+        };
+
+        /**
+         * Refreshes the cache of the top-left and bottom-right points of the
+         * drag and drop objects in the specified groups
+         *
+         * @param {Array} aGroups an associative array of groups to refresh
+         */
+        this.refreshCache = function(aGroups) {
+            for (sGroup in aGroups) {
+                if ("string" != typeof sGroup) {
+                    continue;
+                }
+                for (i in this.ids[sGroup]) {
+                    var oDD = this.ids[sGroup][i];
+
+                    if (this.isTypeOfDD(oDD)) {
+                        var loc = this.getLocation(oDD);
+                        if (loc) {
+                            this.locationCache[oDD.id] = loc;
+                        } else {
+                            delete this.locationCache[oDD.id];
+                            // this will unregister the drag and drop object if
+                            // the element is not in a usable state
+                            oDD.unreg();
+                        }
+                    }
+                }
+            }
+        };
+
+        /**
+         * This checks to make sure an element exists and is in the DOM.  The
+         * main purpose is to handle cases where innerHTML is used to remove
+         * drag and drop objects from the DOM.  IE provides an 'unspecified
+         * error' when trying to access the offsetParent of such an element
+         * @param {HTMLElement} el the element to check
+         * @return {boolean} true if the element looks usable
+         */
+        this.verifyEl = function(el) {
+            try {
+                if (el) {
+                    var parent = el.offsetParent;
+                    if (parent) {
+                        return true;
+                    }
+                }
+            } catch(e) {
+            }
+
+            return false;
+        };
+
+        /**
+         * Returns the an array containing the drag and drop element's position
+         * and size, including the ygDragDrop.padding configured for it
+         *
+         * @param {ygDragDrop} oDD the drag and drop object to get the
+         * location for
+         * @return array containing the top left and bottom right points of the
+         * element
+         */
+        this.getLocation = function(oDD) {
+            if (! this.isTypeOfDD(oDD)) {
+                return null;
+            }
+
+            var el = oDD.getEl();
+
+            if (!this.verifyEl(el)) {
+                return null;
+            }
+
+
+            // var aPos = ygPos.getPos(el);
+            var aPos = YAHOO.util.Dom.getXY(el);
+
+            x1 = aPos[0];
+            x2 = x1 + el.offsetWidth;
+
+            y1 = aPos[1];
+            y2 = y1 + el.offsetHeight;
+
+            var t = y1 - oDD.padding[0];
+            var r = x2 + oDD.padding[1];
+            var b = y2 + oDD.padding[2];
+            var l = x1 - oDD.padding[3];
+
+            return new YAHOO.util.Region( t, r, b, l );
+
+        };
+
+        /**
+         * Checks the cursor location to see if it over the target
+         *
+         * @param {YAHOO.util.Point} pt The point to evaluate
+         * @param {ygDragDrop} oDDTarget the DragDrop object we are inspecting
+         * @return {boolean} true if the mouse is over the target
+         * @private
+         */
+        this.isOverTarget = function(pt, oDDTarget, intersect) {
+            // use cache if available
+            var loc = this.locationCache[oDDTarget.id];
+            if (!loc || !this.useCache) {
+                loc = this.getLocation(oDDTarget);
+                this.locationCache[oDDTarget.id] = loc;
+
+            }
+
+
+            // var cursorIsOver =  (x >= loc[3] && x <= loc[1] && y >= loc[0] && y <= loc[2]);
+            //oDDTarget.cursorIsOver = loc.contains( new YAHOO.util.Point(x, y) );
+            oDDTarget.cursorIsOver = loc.contains( pt );
+            oDDTarget.overlap = null;
+
+            // if (this.INTERSECT == this.mode) {
+            if (intersect) {
+
+                var curRegion =
+                    YAHOO.util.Region.getRegion(this.dragCurrent.getDragEl());
+                var overlap = curRegion.intersect(loc);
+
+                if (overlap) {
+                    oDDTarget.overlap = overlap;
+                    return true;
+                } else {
+                    return false;
+                }
+
+            } else {
+                return oDDTarget.cursorIsOver;
+            }
+        };
+
+        /**
+         * @private
+         */
+        this._onUnload = function(e, me) {
+            this.unregAll();
+        };
+
+        /**
+         * Cleans up the drag and drop events and objects.
+         *
+         * @private
+         */
+        this.unregAll = function() {
+
+            if (this.dragCurrent) {
+                this.stopDrag();
+                this.dragCurrent = null;
+            }
+
+            this._execOnAll("unreg", []);
+
+            for (i in this.elementCache) {
+                delete this.elementCache[i];
+            }
+
+            this.elementCache = {};
+            this.ids = {};
+        };
+
+        /**
+         * A cache of DOM elements
+         *
+         * @private
+         */
+        this.elementCache = {};
+
+        /**
+         * Get the wrapper for the DOM element specified
+         *
+         * @param {String} id the id of the elment to get
+         * @return {YAHOO.util.DDM.ElementWrapper} the wrapped element
+         * @private
+         */
+        this.getElWrapper = function(id) {
+            var oWrapper = this.elementCache[id];
+            if (!oWrapper || !oWrapper.el) {
+                oWrapper = this.elementCache[id] =
+                    new this.ElementWrapper(document.getElementById(id));
+            }
+            return oWrapper;
+        };
+
+        /**
+         * Returns the actual DOM element
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The element
+         */
+        this.getElement = function(id) {
+            // return this.getElWrapper(id).el;
+            return document.getElementById(id);
+        };
+
+        /**
+         * Returns the style property for the DOM element (i.e.,
+         * document.getElById(id).style)
+         *
+         * @param {String} id the id of the elment to get
+         * @return {Object} The style property of the element
+         */
+        this.getCss = function(id) {
+            // return this.getElWrapper(id).css;
+            var css = null;
+            var el = document.getElementById(id);
+            if (el) {
+                css = el.style;
+            }
+
+            return css;
+        };
+
+        /**
+         * Inner class for cached elements
+         */
+        this.ElementWrapper = function(el) {
+                /**
+                 * @private
+                 */
+                this.el = el || null;
+                /**
+                 * @private
+                 */
+                this.id = this.el && el.id;
+                /**
+                 * @private
+                 */
+                this.css = this.el && el.style;
+            };
+
+        /**
+         * Returns the X position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the X coordinate
+         */
+        this.getPosX = function(el) {
+            return YAHOO.util.Dom.getX(el);
+        };
+
+        /**
+         * Returns the Y position of an html element
+         * @param el the element for which to get the position
+         * @return {int} the Y coordinate
+         */
+        this.getPosY = function(el) {
+            return YAHOO.util.Dom.getY(el);
+        };
+
+        /**
+         * Swap two nodes.  In IE, we use the native method, for others we
+         * emulate the IE behavior
+         *
+         * @param n1 the first node to swap
+         * @param n2 the other node to swap
+         */
+        this.swapNode = function(n1, n2) {
+            if (n1.swapNode) {
+                n1.swapNode(n2);
+            } else {
+                // the node reference order for the swap is a little tricky.
+                var p = n2.parentNode;
+                var s = n2.nextSibling;
+                n1.parentNode.replaceChild(n2,n1);
+                p.insertBefore(n1,s);
+            }
+        };
+
+        /**
+         * @private
+         */
+        this.getScroll = function () {
+            var t, l;
+            if (document.documentElement && document.documentElement.scrollTop) {
+                t = document.documentElement.scrollTop;
+                l = document.documentElement.scrollLeft;
+            } else if (document.body) {
+                t = document.body.scrollTop;
+                l = document.body.scrollLeft;
+            }
+            return { top: t, left: l };
+        };
+
+        /**
+         * Returns the specified element style property
+         * @param {HTMLElement} el          the element
+         * @param {string}      styleProp   the style property
+         * @return {string}     The value of the style property
+         */
+        this.getStyle = function(el, styleProp) {
+            if (el.style.styleProp) {
+                return el.style.styleProp;
+            } else if (el.currentStyle) {
+                return el.currentStyle[styleProp];
+            } else if (document.defaultView) {
+                return document.defaultView.getComputedStyle(el, null).
+                    getPropertyValue(styleProp);
+            }
+        };
+
+        /**
+         * Gets the scrollTop
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollTop = function () { return this.getScroll().top; };
+
+        /**
+         * Gets the scrollLeft
+         *
+         * @return {int} the document's scrollTop
+         */
+        this.getScrollLeft = function () { return this.getScroll().left; };
+
+        this.moveToEl = function (moveEl, targetEl) {
+            var aCoord = YAHOO.util.Dom.getXY(targetEl);
+            YAHOO.util.Dom.setXY(moveEl, aCoord);
+        };
+
+        /**
+         * Gets the client height
+         *
+         * @return {int} client height in px
+         */
+        this.getClientHeight = function() {
+            return (window.innerHeight) ? window.innerHeight :
+                (document.documentElement && document.documentElement.clientHeight) ?
+                document.documentElement.clientHeight : document.body.offsetHeight;
+        };
+
+        /**
+         * Gets the client width
+         *
+         * @return {int} client width in px
+         */
+        this.getClientWidth = function() {
+            return (window.innerWidth) ? window.innerWidth :
+                (document.documentElement && document.documentElement.clientWidth) ?
+                document.documentElement.clientWidth : document.body.offsetWidth;
+        };
+
+        /**
+         * numeric array sort function
+         */
+        this.numericSort = function(a, b) { return (a - b); };
+
+        /**
+         * @private
+         */
+        this._timeoutCount = 0;
+
+        /**
+         * @private
+         * Trying to make the load order less important.  Without this we get
+         * an error if this file is loaded before the Event Utility.
+         */
+        this._addListeners = function() {
+            if ( UTIL.Event &&
+                 document          &&
+                 document.body        ) {
+
+                this._onLoad();
+            } else {
+                if (this._timeoutCount > 500) {
+                } else {
+                    setTimeout("YAHOO.util.DDM._addListeners()", 10);
+                    this._timeoutCount += 1;
+                }
+            }
+
+        };
+
+        /**
+         * Recursively searches the immediate parent and all child nodes for
+         * the handle element in order to determine wheter or not it was
+         * clicked.
+         *
+         * @param node the html element to inspect
+         */
+        this.handleWasClicked = function(node, id) {
+            if (this.isHandle(id, node.id)) {
+                return true;
+            } else {
+                // check to see if this is a text node child of the one we want
+                var p = node.parentNode;
+
+                while (p) {
+                    if (this.isHandle(id, p.id)) {
+                        return true;
+                    } else {
+                        p = p.parentNode;
+                    }
+                }
+            }
+
+            return false;
+        };
+
+    };
+
+    // shorter alias, save a few bytes
+    YAHOO.util.DDM = YAHOO.util.DragDropMgr;
+    YAHOO.util.DDM._addListeners();
+
+}
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation where the linked element follows the
+ * mouse cursor.
+ *
+ * @extends DragDrop
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ */
+YAHOO.util.DD = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+    }
+};
+
+YAHOO.util.DD.prototype = new YAHOO.util.DragDrop();
+
+/**
+ * Should we auto-scroll? Defaults to true
+ *
+ * @type boolean
+ */
+YAHOO.util.DD.prototype.scroll = true;
+
+/**
+ * Sets the pointer offset to the distance between the linked element's top
+ * left corner and the location the element was clicked
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ */
+YAHOO.util.DD.prototype.autoOffset = function(iPageX, iPageY) {
+    var el = this.getEl();
+    var aCoord = YAHOO.util.Dom.getXY(el);
+    var x = iPageX - aCoord[0];
+    var y = iPageY - aCoord[1];
+    this.setDelta(x, y);
+};
+
+/**
+ * Sets the pointer offset.  You can call this directly to force the offset to
+ * be in a particular location (e.g., pass in 0,0 to set it to the center of the
+ * object, as done in ygDDSliderBG)
+ *
+ * @param {int} iDeltaX the distance from the left
+ * @param {int} iDeltaY the distance from the top
+ */
+YAHOO.util.DD.prototype.setDelta = function(iDeltaX, iDeltaY) {
+    this.deltaX = iDeltaX;
+    this.deltaY = iDeltaY;
+};
+
+/**
+ * Sets the drag element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+
+YAHOO.util.DD.prototype.setDragElPos = function(iPageX, iPageY) {
+    this.alignElWithMouse(this.getDragEl(), iPageX, iPageY);
+};
+
+/**
+ * Sets the element to the location of the mousedown or click event,
+ * maintaining the cursor location relative to the location on the element
+ * that was clicked.  Override this if you want to place the element in a
+ * location other than where the cursor is.
+ *
+ * @param {HTMLElement} el the element to move
+ * @param {int} iPageX the X coordinate of the mousedown or drag event
+ * @param {int} iPageY the Y coordinate of the mousedown or drag event
+ */
+YAHOO.util.DD.prototype.alignElWithMouse = function(el, iPageX, iPageY) {
+    var oCoord = this.getTargetCoord(iPageX, iPageY);
+    var aCoord = [oCoord.x, oCoord.y];
+    YAHOO.util.Dom.setXY(el, aCoord);
+
+    this.cachePosition(oCoord.x, oCoord.y);
+
+    this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
+};
+
+/**
+ * Saves the most recent position so that we can reset the constraints and
+ * tick marks on-demand.  We need to know this so that we can calculate the
+ * number of pixels the element is offset from its original position.
+ */
+YAHOO.util.DD.prototype.cachePosition = function(iPageX, iPageY) {
+    if (iPageX) {
+        this.lastPageX = iPageX;
+        this.lastPageY = iPageY;
+    } else {
+        var aCoord = YAHOO.util.Dom.getXY(this.getEl());
+        this.lastPageX = aCoord[0];
+        this.lastPageY = aCoord[1];
+    }
+};
+
+/**
+ * Auto-scroll the window if the dragged object has been moved beyond the
+ * visible window boundary.
+ *
+ * @param {int} x the drag element's x position
+ * @param {int} y the drag element's y position
+ * @param {int} h the height of the drag element
+ * @param {int} w the width of the drag element
+ * @private
+ */
+YAHOO.util.DD.prototype.autoScroll = function(x, y, h, w) {
+
+    if (this.scroll) {
+        // The client height
+        var clientH = this.DDM.getClientHeight();
+
+        // The client width
+        var clientW = this.DDM.getClientWidth();
+
+        // The amt scrolled down
+        var st = this.DDM.getScrollTop();
+
+        // The amt scrolled right
+        var sl = this.DDM.getScrollLeft();
+
+        // Location of the bottom of the element
+        var bot = h + y;
+
+        // Location of the right of the element
+        var right = w + x;
+
+        // The distance from the cursor to the bottom of the visible area,
+        // adjusted so that we don't scroll if the cursor is beyond the
+        // element drag constraints
+        var toBot = (clientH + st - y - this.deltaY);
+
+        // The distance from the cursor to the right of the visible area
+        var toRight = (clientW + sl - x - this.deltaX);
+
+
+        // How close to the edge the cursor must be before we scroll
+        // var thresh = (document.all) ? 100 : 40;
+        var thresh = 40;
+
+        // How many pixels to scroll per autoscroll op.  This helps to reduce
+        // clunky scrolling. IE is more sensitive about this ... it needs this
+        // value to be higher.
+        var scrAmt = (document.all) ? 80 : 30;
+
+        // Scroll down if we are near the bottom of the visible page and the
+        // obj extends below the crease
+        if ( bot > clientH && toBot < thresh ) {
+            window.scrollTo(sl, st + scrAmt);
+        }
+
+        // Scroll up if the window is scrolled down and the top of the object
+        // goes above the top border
+        if ( y < st && st > 0 && y - st < thresh ) {
+            window.scrollTo(sl, st - scrAmt);
+        }
+
+        // Scroll right if the obj is beyond the right border and the cursor is
+        // near the border.
+        if ( right > clientW && toRight < thresh ) {
+            window.scrollTo(sl + scrAmt, st);
+        }
+
+        // Scroll left if the window has been scrolled to the right and the obj
+        // extends past the left border
+        if ( x < sl && sl > 0 && x - sl < thresh ) {
+            window.scrollTo(sl - scrAmt, st);
+        }
+    }
+};
+
+/**
+ * Finds the location the element should be placed if we want to move
+ * it to where the mouse location less the click offset would place us.
+ *
+ * @param {int} iPageX the X coordinate of the click
+ * @param {int} iPageY the Y coordinate of the click
+ * @return an object that contains the coordinates (Object.x and Object.y)
+ * @private
+ */
+YAHOO.util.DD.prototype.getTargetCoord = function(iPageX, iPageY) {
+
+
+    var x = iPageX - this.deltaX;
+    var y = iPageY - this.deltaY;
+
+    if (this.constrainX) {
+        if (x < this.minX) { x = this.minX; }
+        if (x > this.maxX) { x = this.maxX; }
+    }
+
+    if (this.constrainY) {
+        if (y < this.minY) { y = this.minY; }
+        if (y > this.maxY) { y = this.maxY; }
+    }
+
+    x = this.getTick(x, this.xTicks);
+    y = this.getTick(y, this.yTicks);
+
+
+    return {x:x, y:y};
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4MouseDown = function(e) {
+    // this.resetConstraints();
+    this.autoOffset(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DD.prototype.b4Drag = function(e) {
+    this.setDragElPos(YAHOO.util.Event.getPageX(e),
+                        YAHOO.util.Event.getPageY(e));
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Debugging ygDragDrop events that can be overridden
+///////////////////////////////////////////////////////////////////////////////
+/*
+YAHOO.util.DD.prototype.startDrag = function(x, y) {
+};
+
+YAHOO.util.DD.prototype.onDrag = function(e) {
+};
+
+YAHOO.util.DD.prototype.onDragEnter = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragOver = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragOut = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.onDragDrop = function(e, id) {
+};
+
+YAHOO.util.DD.prototype.endDrag = function(e) {
+};
+*/
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that inserts an empty, bordered div into
+ * the document that follows the cursor during drag operations.  At the time of
+ * the click, the frame div is resized to the dimensions of the linked html
+ * element, and moved to the exact location of the linked element.
+ *
+ * @extends YAHOO.util.DD
+ * @constructor
+ * @param {String} id the id of the linked html element
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+YAHOO.util.DDProxy = function(id, sGroup) {
+    if (id) {
+        this.init(id, sGroup);
+        this.initFrame();
+    }
+};
+
+YAHOO.util.DDProxy.prototype = new YAHOO.util.DD();
+
+/**
+ * A reference to the one div element we create for all instances of this class
+ *
+ * @type Object
+ */
+YAHOO.util.DDProxy.frameDiv = null;
+
+/**
+ * the drag frame div id
+ *
+ * @type String
+ */
+YAHOO.util.DDProxy.dragElId = "ygddfdiv";
+
+/**
+ * The border width of the frame.  This is used when we resize the frame to
+ * the size of the linked element.  We substract the border width to make
+ * the div the correct size.
+ *
+ * @TODO find a better way to handle this
+ *
+ * @type int
+ */
+YAHOO.util.DDProxy.prototype.borderWidth = 2;
+
+/**
+ * By default we resize the drag frame to be the same size as the element
+ * we want to drag (this is to get the frame effect).  We can turn it off
+ * if we want a different behavior (ex: ygDDMy2)
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.resizeFrame = true;
+
+/**
+ * By default the frame is positioned exactly where the drag element is, so
+ * we use the cursor offset provided by YAHOO.util.DD.  Another option that works only if
+ * you do not have constraints on the obj is to have the drag frame centered
+ * around the cursor.  Set centerFrame to true for this effect.  Ex:
+ * ygDDMy2
+ *
+ * @type boolean
+ */
+YAHOO.util.DDProxy.prototype.centerFrame = false;
+
+/**
+ * Create the drag frame if needed
+ */
+YAHOO.util.DDProxy.createFrame = function() {
+    var THIS = YAHOO.util.DDProxy;
+
+    if (!document || !document.body) {
+        setTimeout(THIS.createFrame, 50);
+        return;
+    }
+
+    if (!THIS.frameDiv) {
+        THIS.frameDiv = document.createElement("div");
+        THIS.frameDiv.id = THIS.dragElId;
+        var s = THIS.frameDiv.style;
+        s.position = "absolute";
+        s.visibility = "hidden";
+        s.cursor = "move";
+        s.border = "2px solid #aaa";
+        s.zIndex = 999;
+
+        document.body.appendChild(THIS.frameDiv);
+    }
+};
+
+/**
+ * Initialization for the drag frame element.  Must be called in the
+ * constructor of all subclasses
+ */
+YAHOO.util.DDProxy.prototype.initFrame = function() {
+    YAHOO.util.DDProxy.createFrame();
+    this.setDragElId(YAHOO.util.DDProxy.dragElId);
+    this.useAbsMath = true;
+};
+
+/**
+ * Resizes the drag frame to the dimensions of the clicked object, positions
+ * it over the object, and finally displays it
+ *
+ * @param {int} iPageX X click position
+ * @param {int} iPageY Y click position
+ * @private
+ */
+YAHOO.util.DDProxy.prototype.showFrame = function(iPageX, iPageY) {
+    var el = this.getEl();
+
+    var s = this.getDragEl().style;
+
+    if (this.resizeFrame) {
+        s.width = (parseInt(el.offsetWidth) - (2*this.borderWidth)) + "px";
+        s.height = (parseInt(el.offsetHeight) - (2*this.borderWidth)) + "px";
+    }
+
+    if (this.centerFrame) {
+        this.setDelta(Math.round(parseInt(s.width)/2),
+                Math.round(parseInt(s.width)/2));
+    }
+
+    this.setDragElPos(iPageX, iPageY);
+
+    s.visibility = "";
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4MouseDown = function(e) {
+    var x = YAHOO.util.Event.getPageX(e);
+    var y = YAHOO.util.Event.getPageY(e);
+    this.autoOffset(x, y);
+    this.setDragElPos(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4StartDrag = function(x, y) {
+    // show the drag frame
+    this.showFrame(x, y);
+};
+
+// overrides YAHOO.util.DragDrop
+YAHOO.util.DDProxy.prototype.b4EndDrag = function(e) {
+
+    // hide the drag frame
+    var s = this.getDragEl().style;
+    s.visibility = "hidden";
+};
+
+// overrides YAHOO.util.DragDrop
+// By default we try to move the element to the last location of the frame.
+// This is so that the default behavior mirrors that of YAHOO.util.DD.
+YAHOO.util.DDProxy.prototype.endDrag = function(e) {
+    var lel = this.getEl();
+    var del = this.getDragEl();
+
+    // Show the drag frame briefly so we can get its position
+    del.style.visibility = "";
+
+    // Hide the linked element before the move to get around a Safari
+    // rendering bug.
+    lel.style.visibility = "hidden";
+    YAHOO.util.DDM.moveToEl(lel, del);
+    del.style.visibility = "hidden";
+    lel.style.visibility = "";
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that does not move, but can be a drop
+ * target.  You would get the same result by simply omitting implementation
+ * for the event callbacks, but this way we reduce the processing cost of the
+ * event listener and the callbacks.
+ *
+ * @extends YAHOO.util.DragDrop
+ * @constructor
+ * @param {String} id the id of the element that is a drop target
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+
+YAHOO.util.DDTarget = function(id, sGroup) {
+    if (id) {
+        this.initTarget(id, sGroup);
+    }
+};
+
+YAHOO.util.DDTarget.prototype = new YAHOO.util.DragDrop();
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/event.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/event.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/event.js	(revision 24065)
@@ -0,0 +1,901 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ * @param {String} type The type of event, which is passed to the callback
+ *                 when the event fires
+ * @param {Object} oScope The context the event will fire from.  "this" will
+ *                 refer to this object in the callback.  Default value:
+ *                 the window object.  The listener can override this.
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope) {
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from.  Defaults to the window obj
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * The subscribers to this event
+     * @type array
+     */
+    this.subscribers = [];
+
+    // Register with the event utility for automatic cleanup.  Made optional
+    // so that CustomEvent can be used independently of pe.event
+    if (YAHOO.util["Event"]) {
+        YAHOO.util.Event.regCE(this);
+    }
+};
+
+YAHOO.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0; i<this.subscribers.length; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     *
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        for (var i=0; i<this.subscribers.length; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, arguments, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     */
+    unsubscribeAll: function() {
+        for (var i=0; i<this.subscribers.length; ++i) {
+            this._delete(i);
+        }
+    },
+
+    /**
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        delete this.subscribers[index];
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * @class
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
+    /**
+     * The callback that will be execute when the event fires
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+// Only load this library once.  If it is loaded a second time, existing
+// events cannot be detached.
+if (!YAHOO.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @class
+ * @constructor
+ */
+    YAHOO.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of the custom events that have been defined.  Used for
+         * automatic cleanup
+         * @type array
+         * @private
+         */
+        var customEvents = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @private
+         */
+        var legacyHandlers = [];
+
+        return { // PREPROCESS
+
+            /**
+             * Element to bind, int constant
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @private
+             */
+            isSafari: (navigator.userAgent.match(/safari/gi)),
+
+            /**
+             * @private
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             */
+            isIE: (!this.isSafari && navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * Appends an event handler
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0; i< el.length; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete) {
+                        el = this.getEl(el);
+                    } else {
+                        // defer adding the event until onload fires
+                        delayedListeners[delayedListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    if (legacyIndex == -1) {
+
+                        legacyIndex = legacyEvents.length;
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                YAHOO.util.Event.fireLegacyEvent(
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    legacyHandlers[legacyIndex].push(index);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // Internet Explorer abstraction
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * Shorthand for YAHOO.util.Event.addListener
+             * @type function
+             */
+            // on: this.addListener,
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // alert("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                // var el = legacyEvents[YAHOO.util.Event.EL];
+
+                /* this is not working because the property may get populated
+                // fire the event we replaced, if it exists
+                var origHandler = legacyEvents[2];
+                alert(origHandler);
+                if (origHandler && origHandler.call) {
+                    var ret = origHandler.call(el, e);
+                    ok = (ret);
+                }
+                */
+
+                var le = legacyHandlers[legacyIndex];
+                for (i=0; i < le.length; ++i) {
+                    var index = le[i];
+                    // alert(index);
+                    if (index) {
+                        var li = listeners[index];
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                        // alert(ok);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                for (var i=0; i < legacyEvents.length; ++i) {
+                    var le = legacyEvents[i];
+                    if (le && le[0] == el && le[1] == sType) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+
+                return ( (!el.addEventListener && !el.attachEvent) ||
+                                (sType == "click" && this.isSafari) );
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn) {
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0; i< el.length; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                var cacheItem = null;
+                var index = this._getCacheIndex(el, sType, fn);
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // alert("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                delete listeners[index];
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+
+                if (resolveTextNode && t && "#text" == t.nodeName) {
+                    return t.parentNode;
+                } else {
+                    return t;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the event's related target
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return t;
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Returns the event, should not be necessary for user to call
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || (ev.type == "keypress") ? ev.keyCode : 0;
+            },
+
+            /**
+             * @private
+             * Locating the saved event handler data by function ref
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0; i< listeners.length; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             */
+            _isValidCollection: function(o) {
+                // alert(o.constructor.toString())
+                // alert(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @private
+             */
+            getEl: function(id) {
+                /*
+                // this is a problem when replaced via document.getElementById
+                if (! this.elCache[id]) {
+                    try {
+                        var el = document.getElementById(id);
+                        if (el) {
+                            this.elCache[id] = el;
+                        }
+                    } catch (er) {
+                    }
+                }
+                return this.elCache[id];
+                */
+
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             */
+            clearCache: function() {
+                for (i in this.elCache) {
+                    delete this.elCache[i];
+                }
+            },
+
+            /**
+             * Called by CustomEvent instances to provide a handle to the
+             * event * that can be removed later on.  Should be package
+             * protected.
+             * @private
+             */
+            regCE: function(ce) {
+                customEvents.push(ce);
+            },
+
+            /**
+             * @private
+             * hook up any deferred listeners
+             */
+            _load: function(e) {
+                loadComplete = true;
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting * to attach to DOM Nodes as soon as they are
+             * available
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+
+                for (var i=0; i < delayedListeners.length; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        }
+                    }
+                }
+
+                if (tryAgain) {
+                    setTimeout("YAHOO.util.Event._tryPreloadAttach()", 50);
+                }
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             */
+            _unload: function(e, me) {
+                for (var i=0; i < unloadListeners.length; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
+                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    for (i = 0; i < listeners.length; ++i) {
+                        l = listeners[i];
+                        if (l) {
+                            this.removeListener(l[this.EL], l[this.TYPE],
+                                    l[this.FN]);
+                        }
+                    }
+
+                    this.clearCache();
+                }
+
+                for (i = 0; i < customEvents.length; ++i) {
+                    customEvents[i].unsubscribeAll();
+                    delete customEvents[i];
+                }
+
+                for (i = 0; i < legacyEvents.length; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+            },
+
+            /**
+             * Returns scrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement; db = document.body;
+                if (dd && dd.scrollTop) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            }
+        };
+    } ();
+
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
+
+    if (document && document.body) {
+        YAHOO.util.Event._load();
+    } else {
+        YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load,
+                YAHOO.util.Event, true);
+    }
+
+    YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload,
+                YAHOO.util.Event, true);
+
+    YAHOO.util.Event._tryPreloadAttach();
+
+}
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/key.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/key.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/key.js	(revision 24065)
@@ -0,0 +1,34 @@
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+YAHOO.util.Key = new function() {
+	// this.logger	= new ygLogger("ygEventUtil");
+	// DOM key constants 
+	this.DOM_VK_UNDEFINED               = 0x0;
+	this.DOM_VK_RIGHT_ALT               = 0x12;
+	this.DOM_VK_LEFT_ALT                = 0x12;
+	this.DOM_VK_LEFT_CONTROL            = 0x11;
+	this.DOM_VK_RIGHT_CONTROL           = 0x11;
+	this.DOM_VK_LEFT_SHIFT              = 0x10;
+	this.DOM_VK_RIGHT_SHIFT             = 0x10;
+	this.DOM_VK_META                    = 0x9D;
+	this.DOM_VK_BACK_SPACE              = 0x08;
+	this.DOM_VK_CAPS_LOCK               = 0x14;
+	this.DOM_VK_DELETE                  = 0x7F;
+	this.DOM_VK_END                     = 0x23;
+	this.DOM_VK_ENTER                   = 0x0D;
+	this.DOM_VK_ESCAPE                  = 0x1B;
+	this.DOM_VK_HOME                    = 0x24;
+	this.DOM_VK_NUM_LOCK                = 0x90;
+	this.DOM_VK_PAUSE                   = 0x13;
+	this.DOM_VK_PRINTSCREEN             = 0x9A;
+	this.DOM_VK_SCROLL_LOCK             = 0x91;
+	this.DOM_VK_SPACE                   = 0x20;
+	this.DOM_VK_TAB                     = 0x09;
+	this.DOM_VK_LEFT                    = 0x25;
+	this.DOM_VK_RIGHT                   = 0x27;
+	this.DOM_VK_UP                      = 0x26;
+	this.DOM_VK_DOWN                    = 0x28;
+	this.DOM_VK_PAGE_DOWN               = 0x22;
+	this.DOM_VK_PAGE_UP                 = 0x21;
+};
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/ygDDOnTop.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/ygDDOnTop.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/ygDDOnTop.js	(revision 24065)
@@ -0,0 +1,46 @@
+
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+/**
+ * @class a DragDrop implementation that moves the object as it is being dragged,
+ * and keeps the object being dragged on top.  This is a subclass of ygDD rather
+ * than DragDrop, and inherits the implementation of most of the event listeners
+ * from that class.
+ *
+ * @extends ygDD
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop items
+ */
+function ygDDOnTop(id, sGroup) {
+	if (id) {
+		this.init(id, sGroup);
+	
+	}
+}
+
+ygDDOnTop.prototype = new YAHOO.util.DD();
+
+/**
+ * The inital z-index of the element, stored so we can restore it later
+ *
+ * @type int
+ */
+ygDDOnTop.prototype.origZ = 0;
+
+ygDDOnTop.prototype.startDrag = function(x, y) {
+
+	var style = this.getEl().style;
+
+	// store the original z-index
+	this.origZ = style.zIndex;
+
+	// The z-index needs to be set very high so the element will indeed be on top
+	style.zIndex = 999;
+}
+
+ygDDOnTop.prototype.endDrag = function(e) {
+
+	// restore the original z-index
+	this.getEl().style.zIndex = this.origZ;
+};
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/ygDDPlayer.js
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/ygDDPlayer.js	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/js/ygDDPlayer.js	(revision 24065)
@@ -0,0 +1,350 @@
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+
+function ygDDStack(id, sGroup) {
+	if (id) {
+		this.init(id, sGroup);
+		this.initFrame();
+	}
+}
+
+ygDDStack.prototype = new YAHOO.util.DDTarget();
+
+ygDDPlayer.TYPE = "ygDDPlayer";
+
+/**
+ * @class a YAHOO.util.DDFramed implementation. During the drag over event, the
+ * dragged element is inserted before the dragged-over element.
+ *
+ * @extends YAHOO.util.DDProxy
+ * @constructor
+ * @param {String} id the id of the linked element
+ * @param {String} sGroup the group of related DragDrop objects
+ */
+function ygDDPlayer(id, sGroup,bl) {
+    this.initPlayer(id, sGroup);
+    this.berryList = bl;     
+            
+}
+
+ygDDPlayer.prototype = new YAHOO.util.DDProxy();
+
+ygDDPlayer.prototype.berryList = new Array();
+
+ygDDPlayer.prototype.initPlayer = function(id, sGroup) {
+	if (!id) { return; }
+
+    this.init(id, sGroup);
+    this.initFrame();
+    var s = this.getDragEl().style;
+    s.borderColor = "transparent";
+    // s.backgroundColor = "#cccccc";
+    s.opacity = 0.76;
+    s.filter = "alpha(opacity=76)";
+
+    // specify that this is not currently a drop target
+    this.isTarget = false;
+
+    this.originalStyles = [];
+
+    this.type = ygDDPlayer.TYPE;
+    this.slot = null;
+    this.startPos = YAHOO.util.Dom.getXY( this.getEl() );
+   
+}
+
+ygDDPlayer.prototype.startDrag = function(x, y) {
+	
+	var dragEl = this.getDragEl();
+	var clickEl = this.getEl();
+       
+       	dragEl.innerHTML = clickEl.innerHTML;
+	//dragEl.className = clickEl.className;
+    	//dragEl.style.color = clickEl.style.color;
+	//dragEl.style.backgroundColor = clickEl.style.backgroundColor;
+        //dragEl.style.visibility = clickEl.style.visibility;
+               
+ 	while (dragEl.hasChildNodes())	{
+        	 dragEl.removeChild(dragEl.firstChild);
+	}	
+       
+         var img = document.createElement('img');
+              img.src = 'interfaces/default/images/berry3.png';
+              img.height = 15;
+              img.width = 15;
+             img.border = 0;              
+          dragEl.appendChild(img);
+       
+        var added = true;
+
+      	var s = clickEl.style;
+	s.opacity = .1;
+	s.filter = "alpha(opacity=10)";
+
+	var targets = YAHOO.util.DDM.getRelated(this, true);
+	
+	for (var i=0; i<targets.length; i++) {
+		
+		var targetEl = this.getTargetDomRef(targets[i]);
+
+		if (!this.originalStyles[targetEl.id]) {
+			this.originalStyles[targetEl.id] = targetEl.className;
+		}
+
+		targetEl.className = "target";
+	}
+};
+
+ygDDPlayer.prototype.getTargetDomRef = function(oDD) {
+	if (oDD.player) {
+		return oDD.player.getEl();
+	} else {
+		return oDD.getEl();
+	}
+};
+
+ygDDPlayer.prototype.endDrag = function(e) {
+	// reset the linked element styles
+	var s = this.getEl().style;
+	s.opacity = 1;
+	s.filter = "alpha(opacity=100)";
+
+	this.resetTargets();
+};
+
+ygDDPlayer.prototype.resetTargets = function() {
+
+	// reset the target styles
+	var targets = YAHOO.util.DDM.getRelated(this, true);
+	for (var i=0; i<targets.length; i++) {
+		var targetEl = this.getTargetDomRef(targets[i]);
+		var oldStyle = this.originalStyles[targetEl.id];
+		if (oldStyle) {
+			targetEl.className = oldStyle;
+		}
+	}
+};
+
+var request_type = "GET";
+var addurlPath ="?a=pr&rt=r&ro=1&s=AddItem&c=&s1.id=2&o=XML&s1.item=";
+var delurlPath ="?a=pr&rt=r&ro=1&s=DeleteItem&c=&o=XML&s1.item=";
+var postdata = null;
+
+ygDDPlayer.prototype.onDragDrop = function(e, id) {
+	// get the drag and drop object that was targeted
+     var oDD;
+     var player = this;
+   
+    if ("string" == typeof id) {
+        oDD = YAHOO.util.DDM.getDDById(id);
+    } else {
+        oDD = YAHOO.util.DDM.getBestMatch(id);
+    }
+
+
+   var el = this.getEl();
+
+	// check if the slot has a player in it already
+	if (oDD.player) {
+		// check if the dragged player was already in a slot
+		if (this.slot) {
+	  		// check to see if the player that is already in the
+			// slot can go to the slot the dragged player is in
+			// YAHOO.util.DDM.isLegalTarget is a new method
+			if ( YAHOO.util.DDM.isLegalTarget(oDD.player, this.slot) ) {
+				YAHOO.util.DDM.moveToEl(oDD.player.getEl(), el);
+				this.slot.player = oDD.player;
+				oDD.player.slot = this.slot;
+			} else {
+				YAHOO.util.Dom.setXY(oDD.player.getEl(), oDD.player.startPos);
+				this.slot.player = null;
+				oDD.player.slot = null
+			}
+		} else {
+		        // the player in the slot will be moved to the dragged
+			// players start position
+			//oDD.player.slot = null;
+			//YAHOO.util.DDM.moveToEl(oDD.player.getEl(), el);
+		}
+	}else {
+		// Move the player into the emply slot
+		// I may be moving off a slot so I need to clear the player ref
+	   	if (this.slot) {
+			this.slot.player = null;
+		}
+	}
+
+     var  addurl = addurlPath + el.id;	
+     var addSuccess = function(o){ 
+                 var text = o.responseText;
+	         var result = o.responseXML;
+                 var items = result.getElementsByTagName('item');
+                 if (items.length > 0){
+                    var item = items[0];
+                    var berrybasket = YAHOO.util.Dom.get('berrybasket');
+        	    var berries = YAHOO.util.Dom.get('berries');
+                    player.berryList[player.berryList.length]= item;     
+                
+                    var itemID = item.getAttribute('collection')+":"+item.getAttribute('name');
+                    var parent =el.parentNode;
+                    parent.removeChild(el);
+ 	        	
+                    if (parent !=null && parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(itemID+":root");
+                         var section = YAHOO.util.Dom.get(itemID+":section");
+                         if(root!=null && root.id.indexOf(itemID) !=-1){
+                             parent.removeChild(root);
+                          }
+     
+	                  if(section!=null && section.id.indexOf(itemID) !=-1){
+                             parent.removeChild(section);
+        	          }                                                
+                     }
+                   
+
+                    if (!YAHOO.util.Dom.get('hideview') && player.berryList.length <13){
+                       
+                       while (berries.hasChildNodes()) {
+       	                   berries.removeChild(berries.firstChild);
+	                }
+                        
+                     for (var i =0; i < player.berryList.length; i++ ){
+                             var img = document.createElement('img');
+                              img.src = 'interfaces/default/images/berry3.png';
+                              img.height = 15;
+                              img.width = 15;
+                              img.border = 0;              
+                              berries.appendChild(img);
+                       }
+      	                                   
+	          }
+                 else{
+                      
+        
+                    if (YAHOO.util.Dom.get('hideview')){
+                      
+                        var berryBasket  = YAHOO.util.Dom.get('berrybasket');
+                        var berries  = YAHOO.util.Dom.get('berries');
+                        var doclist = YAHOO.util.Dom.get('doclist'); 
+                        var tid = el.id;                                  
+                        var berryItem; 
+                        var berryElement = document.createElement('li');
+                         for (var i in player.berryList){
+                             berryItem = player.berryList[i];
+                             var id = berryItem.getAttribute('collection')+":"+berryItem.getAttribute('name');
+                             if (id == tid){
+                               var title = berryItem.getAttribute('title');
+                               var root_title = berryItem.getAttribute('root_title');  
+                                if (root_title != ""){
+                                      root_title +=":";
+                                     }
+	    
+                                title = root_title+title;	
+                                if (title.length > 50){
+                                   title = title.substring(0,20)+" ... "+title.substr(title.length-35,35);
+                                }
+                                
+                               berryElement.appendChild(document.createTextNode(title));
+                               berryElement.setAttribute("class","berryitem");
+                               doclist.appendChild(berryElement);
+                               var heightStr =  berryBasket.style.height+"";
+                               var height =parseInt(heightStr.substring(0,heightStr.length-2)) +18;                             
+                               berryBasket.style.height = height;
+                               berries.style.height = height;
+                               break;
+                            }
+                         }
+                         }    
+                 
+                 }
+               }
+                
+                       
+
+         }
+
+     var addFailure = function(o){ }
+
+
+     var addcallback = {
+        	success:addSuccess,
+     	        failure:addFailure,  
+                argument:player
+                }
+    
+
+    var  delurl = delurlPath + el.id;	
+     var delSuccess = function(o){ 
+ 		 var result = o.responseXML;
+                    var parent =el.parentNode;
+                    if (parent == null) return;                   
+
+                    parent.removeChild(el);
+                     
+                    for (var i in player.berryList){
+                       var berry = player.berryList[i];
+                  
+                       var id = berry['collection']+":"+berry['name'];
+                       
+                       if (id == el.id){
+                             player.berryList.splice(i,1);
+                                    
+                             break;
+                         }
+
+                   }
+
+                   if (!parent.hasChildNodes()){
+                         var content =  YAHOO.util.Dom.get('content');
+                           while (content.hasChildNodes()) {
+		              content.removeChild(content.firstChild);
+	                }  
+                        content.appendChild(document.createTextNode('Your berry basket is empty.'));
+                     }
+                   var trashbin =  YAHOO.util.Dom.get('trashbin');
+                   if ( trashbin !=null){
+                         trashbin.style.background = 'url("interfaces/default/images/trash-full.png") 0 0 no-repeat';
+                  }
+              }                                       
+         
+
+     var delFailure = function(o){ }
+
+
+     var delcallback = {
+        	success:delSuccess,
+     	        failure:delFailure,  
+                argument:player
+                }
+    
+
+  if (id == 'berrybasket'){
+       YAHOO.util.Connect.asyncRequest(request_type , addurl , addcallback);         
+  }
+  else{
+        if (id == 'trashbin'){
+             YAHOO.util.Connect.asyncRequest(request_type , delurl , delcallback); 
+         }
+   }
+
+   this.resetTargets();  	
+   this.slot = oDD;	
+   this.slot.player = this;
+ 
+};
+
+ygDDPlayer.prototype.swap = function(el1, el2) {
+    var dom = YAHOO.util.Dom;
+	var pos1 = dom.getXY(el1);
+	var pos2 = dom.getXY(el2);
+	dom.setXY(el1, pos2);
+	dom.setXY(el2, pos1);
+};
+
+ygDDPlayer.prototype.onDragOver = function(e, id) {};
+
+ygDDPlayer.prototype.onDrag = function(e, id) {};
+
+
+
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/berry.css
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/berry.css	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/berry.css	(revision 24065)
@@ -0,0 +1,1 @@
+div.globalwrapper{font-family:sans-serif,arial,helvetica;margin:0 2em 0 4em;padding:0}div#content{font-family:sans-serif,arial,helvetica;margin:.5em 0 .5em 0;padding:0}div.banner{margin:0;padding:0}div.pageinfo{float:right;text-align:right;padding:0;margin:0 0 3px 0;width:50%}div.basketimage{float:left;width:45%;padding:0;margin:0}div.bannerextra{clear:both;padding:.2em 0 0 0}p.bannerlinks{font-weight:bold;margin:0;padding:0}p.bannertitle{font-family:sans-serif,arial,helvetica;font-size:24px;font-weight:bold;white-space:nowrap;margin:0;padding:.5em 0 .5em 0;background:url("../images/tile13.jpeg") 0 0 repeat-y}a.navlink{vertical-align:top;padding:.2em .5em 0 0;color:black;text-decoration:none;background-image:url("../images/bg_off.png")}a.navlink:hover{background-image:url("../images/bg_on.png")}p.navbar{text-align:center;background:url("../images/bg_green.png") 0 0 repeat-x;font-weight:bold}span.navlink{margin:0 3em 0 3em;padding:0 .5em 0 .5em;background-image:url("../images/bg_off.png");cursor:pointer}span.navlink:hover{background-image:url("../images/bg_on.png")}img#trashbin{float:right}span.berryradio{cursor:pointer;margin:0 3em 0 3em;font-weight:bold}.berrycheck{font-size:80%;cursor:pointer;font-weight:bold;margin:0 0 0 .5em}#urlcheck{float:left;padding:0;margin:0}.pick{visibility:hidden}div#berrybasket{float:right;font-family:sans-serif;height:120px;width:100px;padding:4px 5px 4px 4px;background-color:#e0f0e0;background:url("../images/berrybasket.png") 0 0 no-repeat;margin:0;font-size:100%;text-align:center;#border:1px solid #2e8b57;z-index:10;cursor:pointer}div#baskethandle{padding:0;cursor:move;height:30px;width:auto;#background-color:#eee;background:transparent;margin:0}div#berries{text-align:left;height:auto;margin:0;padding:0;overflow:hidden}p#documentberries{font-weight:bold;font-size:90%}.documentberry{margin:0 2em 0 0;padding:0;visibility:hidden}#doclist{margin:0}.content{font-family:sans-serif;text-align:left}li.berryitem{padding:0;margin:0;color:black;font-size:90%}li.berrydoc{font-size:90%;cursor:pointer;padding:0;margin:0 1em 0 0}a.expandcontract{font-size:90%;color:red}.item{font-size:90%}a.fullview:visited{color:red}a#hideview:visited{color:red}a.fullview{float:left;font-size:90%;margin:0 0 0 20px;padding:0;cursor:pointer;color:red;text-decoration:none}a#hideView{float:right;font-size:90%;margin:0 20px 0 0;padding:0;color:red;cursor:pointer;text-decoration:none}.berrydelete{font-family:sans-serif;background-color:#e0f0e0;border:1px solid #2e8b57;padding:4px 4px 4px 4px;font-weight:bold;cursor:pointer;width:6em;color:red;font-size:90%}.sendbutton{font-family:sans-serif;background-color:#e0f0e0;border:1px solid #2e8b57;padding:4px 4px 4px 4px;font-weight:bold;cursor:pointer;width:5em;font-size:90%;margin:1em 0 0 0}.berrybutton{font-family:sans-serif;background-color:#e0f0e0;border:1px solid #2e8b57;padding:4px 4px 4px 4px;font-weight:bold;cursor:pointer;width:10em;font-size:90%}.mailinput{border:1px solid #2e8b57;width:20em;height:1.5em;font-size:90%}.mailitem{text-align:left}textarea#pretextarea{font-family:sans-serif;border:1px solid #2e8b57;width:100%;height:25em;font-size:90%;margin:.5em 0 0 0;padding:0}div#trashbin{float:right;height:60px;width:55px;padding:0;background:url("../images/trash-empty.png") 0 0 no-repeat;margin:0;z-index:10}div#binhandle{height:60px;width:55px;cursor:move}span.extralink{cursor:pointer;font-size:80%;font-weight:bold;margin:0 2em 0 0;color:black}span.extralink:hover{color:#2e8b57}
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/berry_whitespace.css
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/berry_whitespace.css	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/berry_whitespace.css	(revision 24065)
@@ -0,0 +1,317 @@
+
+
+div.globalwrapper{
+  font-family: sans-serif, arial, helvetica;
+  margin: 0 2em 0 4em; 
+  padding:0;
+ 
+}
+
+div#content{
+  font-family: sans-serif, arial, helvetica;
+  margin: 0.5em 0 0.5em 0;
+  padding: 0; 
+
+}
+
+div.banner{
+ margin:0;
+ padding:0;
+
+}
+
+div.pageinfo{
+  float:right;
+  text-align: right;
+  padding: 0;
+  margin:0 0 3px 0;	
+  width: 50%;
+}
+
+div.basketimage{
+  float:left;
+  width: 45%;
+  padding:0;
+  margin:0;
+
+}
+
+
+div.bannerextra {
+   clear: both;
+   padding: 0.2em 0 0 0;
+}
+
+/* home, help, preferences links */
+p.bannerlinks {
+  font-weight: bold;
+  margin:0;
+  padding:0;
+}
+
+
+p.bannertitle {
+  font-family: sans-serif, arial, helvetica;
+  font-size: 24px;
+  font-weight: bold;
+  white-space: nowrap;
+  margin: 0;
+  padding: 0.5em 0 0.5em 0em;
+  background: url("../images/tile13.jpeg") 0 0 repeat-y;
+ 
+}
+
+
+a.navlink{
+  vertical-align: top;
+  padding: 0.2em 0.5em 0 0;
+  color: black;
+  text-decoration: none; 
+  background-image: url("../images/bg_off.png");
+ }
+
+a.navlink:hover {
+   background-image: url("../images/bg_on.png");
+ }
+
+p.navbar{
+  text-align: center;
+   background: url("../images/bg_green.png") 0 0 repeat-x;
+   font-weight: bold;
+}
+
+span.navlink{
+   margin:0 3em  0 3em;
+   padding:0 0.5em 0 0.5em;
+   background-image: url("../images/bg_off.png");
+   cursor: pointer;
+}
+
+span.navlink:hover {
+   background-image: url("../images/bg_on.png");
+ }
+
+img#trashbin{
+ float:right;
+}
+
+span.berryradio{
+ cursor: pointer;
+ margin:0 3em  0 3em;
+ font-weight: bold;
+}
+
+.berrycheck{
+ font-size: 80%;  
+ cursor: pointer;
+ font-weight: bold;
+ margin: 0 0 0 0.5em;
+}
+
+#urlcheck{
+ float: left;
+ padding: 0;
+ margin: 0;
+ 
+}
+
+.pick {
+  visibility:hidden;
+}
+
+div#berrybasket {
+   float:right;
+   font-family:sans-serif;
+   height:120px;
+   width: 100px;
+   padding: 4px 5px 4px 4px;
+   background-color:#E0F0E0;
+   background: url("../images/berrybasket.png") 0 0 no-repeat;
+   margin:0;
+   font-size:100%;
+   text-align:center;
+   #border:1px solid #2E8B57;	
+   z-index:10;
+   cursor: pointer;
+ }
+
+div#baskethandle {
+  padding: 0;
+  cursor:move;
+  height: 30px;
+  width:auto;
+  #background-color:#eeeeee;
+   background:transparent;
+   margin:0 ;
+  }
+
+div#berries {
+  text-align:left;
+  height: auto;
+  margin: 0;
+  padding:0;
+  overflow: hidden;   
+}
+
+
+p#documentberries {
+   font-weight: bold;
+   font-size:90%;
+}
+
+.documentberry {
+  margin:0 2em 0 0;
+  padding:0;
+  visibility:hidden;
+}
+
+
+#doclist{
+  margin: 0;
+ 
+}
+
+.content{
+ font-family:sans-serif;
+ text-align:left;
+}
+
+li.berryitem {
+   padding: 0;
+   margin: 0 ;
+   color: black;
+   font-size: 90%;
+}
+
+li.berrydoc {
+  font-size: 90%;
+  cursor: pointer;
+  padding: 0 ;
+  margin: 0 1em 0 0; 
+}
+
+a.expandcontract {
+  font-size: 90%;
+  color: red
+}
+
+
+.item {
+  font-size: 90%;
+ 
+}
+
+a.fullview:visited{
+ color:red;
+}
+
+a#hideview:visited{
+ color:red;
+}
+
+a.fullview{
+  float:left;
+  font-size: 90%;
+  margin: 0 0 0 20px;
+  padding:0;
+  cursor: pointer;
+  color:red;  
+  text-decoration:none;
+ }
+
+a#hideView{
+  float:right;
+  font-size: 90%;
+  margin:0 20px 0 0;
+  padding:0;
+  color: red;
+  cursor: pointer;
+  text-decoration:none;
+}
+
+
+.berrydelete{
+   font-family:sans-serif;
+   background-color:#E0F0E0;
+   border:1px solid #2E8B57;   
+   padding: 4px  4px 4px 4px; 
+   font-weight: bold;
+   cursor: pointer;
+   width: 6em;
+   color: red;
+   font-size: 90%;
+}
+
+.sendbutton{
+   font-family:sans-serif;
+   background-color:#E0F0E0;
+   border:1px solid #2E8B57;   
+   padding: 4px  4px 4px 4px; 
+   font-weight: bold;
+   cursor: pointer;
+   width: 5em;
+   font-size: 90%;
+   margin: 1em 0 0 0;
+}
+
+.berrybutton{
+   font-family:sans-serif;
+   background-color:#E0F0E0;
+   border:1px solid #2E8B57;   
+   padding: 4px  4px 4px 4px; 
+   font-weight: bold;
+   cursor: pointer;
+   width: 10em;
+   font-size: 90%;
+}
+
+.mailinput {
+  border:1px solid #2E8B57; 
+  width: 20em;
+  height: 1.5em;
+  font-size: 90%
+}
+
+.mailitem{
+   text-align: left;
+ }
+
+
+textarea#pretextarea {
+  font-family:sans-serif;
+  border:1px solid #2E8B57; 
+  width: 100%;
+  height: 25em;
+  font-size: 90%;
+  margin: 0.5em 0 0 0;
+  padding:0;
+}
+
+div#trashbin{
+   float: right;
+   height: 60px;
+   width:  55px;
+   padding: 0;
+   background: url("../images/trash-empty.png") 0 0 no-repeat;
+   margin:0;
+   z-index:10;
+}
+
+div#binhandle{
+ height: 60px;
+ width:  55px;
+ cursor: move;
+}
+
+span.extralink {
+  cursor:pointer;
+  font-size:80%;
+  font-weight:bold;
+  margin:0 2em 0 0;
+  color:black;
+}
+
+span.extralink:hover {
+   color: #2E8B57;
+}
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/core.css
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/core.css	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/core.css	(revision 24065)
@@ -0,0 +1,1 @@
+body{padding:0;margin:0;font-family:sans-serif,arial,helvetica;background:#fff url('../images/chalk.gif') scroll repeat-y left top;color:#000}#page-wrapper{margin:.5em 3em 0 5em}a:link{color:#396}a:visited{color:#066}a:hover,a:active{color:#9c3}div#banner ul,ul#resultlist,ul#tocnodes,ul#docbuttons,ul.tocnode,ul#bannerlist,ul#navbarlist,ul#collectionlist,ul#servicelist,ul#classifierlist,ul#classifiernodelist,ul#queryitemlist{list-style-type:none;margin:0;padding:0}div#banner ul li,ul#bannerlist li,ul#navbarlist li{display:inline;margin:0;padding:0}ul li>select,ul li>input{padding:0;margin-left:5px}div#banner{margin:0;padding:0;overflow:hidden}div#banner p{margin:0;padding:0;float:left;font-size:16px;text-align:left;overflow:hidden}div#banner p a{background-image:url('../images/banner_bg.png');background-repeat:repeat-y}div#banner ul{margin:0;padding:0;float:right;font-size:12px}div#banner a{text-decoration:none;color:#000}ul#bannerlist li a{padding:0 10px 0 10px;text-decoration:none}ul#bannerlist li a:link,ul#bannerlist li a:visited{background-color:#dee79c;background-image:url('../images/bg_off.png');text-decoration:none}ul#bannerlist li a:hover{background-color:#ff6;background-image:url('../images/bg_on.png');text-decoration:none}div#navbar{clear:both}ul#navbarlist{margin:0;padding:0;list-style-type:none;text-align:center;width:100%;font-size:80%;background-image:url('../images/bg_green.png');background-color:#9c9}ul#navbarlist li a{padding:0 20px 0 20px;margin:0;color:#000;text-decoration:none}ul#navbarlist li a:link,ul#navbarlist li a:visited{background-image:url('../images/bg_off.png')}ul#navbarlist li a:hover{background-image:url('../images/bg_on.png')}ul#collectionlist li,ul#servicelist li{display:block;padding:0;margin:.2em 0 0 0;overflow:hidden}ul#collectionlist img{margin:0;padding:0;width:150px;height:45px;border:1px solid black;background-image:url('../images/collectimg_bg.png');background-repeat:repeat-y;overflow:hidden}ul#collectionlist li a.noimage{display:block;margin:0;width:145px;height:40px;border:1px solid black;background-image:url('../images/collectimg_bg.png');background-repeat:repeat-y;overflow:hidden;padding-left:5px;padding-right:0;padding-top:5px;padding-bottom:0}ul#collectionlist li a{font-size:16px;color:#000;text-decoration:none;font-weight:bold}ul#servicelist li a{margin:0 .5em 0 0}ul#queryitemlist li{display:block;margin:.2em 0 .2em 0}ul#classifierlist li{list-style:none;margin:0 0 5px 0;padding:0;display:block;color:#000}ul#classifierlist li#activeclassifier{font-weight:bold;padding:0 0 0 5px;margin:0 0 5px 0}ul#classifierlist li a:link,ul#classifierlist li a:visited{display:block;margin:0;background-image:url('../images/bg_off.png');text-decoration:none;color:#000;width:100%;padding-left:5px;padding-right:0;padding-top:2px;padding-bottom:2px}ul#classifierlist li a:hover,ul#classifierlist li a:active{display:block;margin:0;background-image:url('../images/bg_on.png');text-decoration:none;padding-left:5px;padding-right:0;padding-top:2px;padding-bottom:2px}ul#classifierlist{float:left;font-size:14px;text-align:left;width:15%;margin:0;padding:0}div#classifiers{float:left;width:75%;margin:0;padding:0 0 0 10px}ul#classifiernodelist li{list-style:none;margin:0;padding:5px 0 0 0;display:block}ul.childrenlist{margin:0;padding:0 0 0 20px;display:block;width:100%}div#content{clear:both;overflow:hidden;margin:.2em 0 0 0}div.divbar{clear:both;background-image:url('../images/bg_green.png');width:100%;text-align:center;font-size:80%}div.resultnavigation{margin:0;padding:0}ul#resultlist li{display:block}div.documenttext{clear:both}div#documentheading{font-size:16pt;font-weight:bold}div#documentinfo{float:left;padding:0;margin:0;width:24%}div#toc{float:left;text-align:left;width:60%;padding:0;margin:0}ul#docbuttons li{display:block;font-size:11px;font-weight:bold;background:#f7e7c5;margin:1px;border:1px solid #edb;text-align:center;vertical-align:middle;height:30px;width:110px}ul#tocnodes li{margin:0;padding:5px 0 0 0;display:block}ul.tocnode{margin:0;padding:5px 0 0 20px}ul.tocnode a{margin:0;padding:0 5px 0 0}span.bold{font-weight:bold}div.documentarrows{clear:both;margin:0;padding:1em 0 0 0}img.lessarrow{float:left;border:none}img.morearrow{float:right;border:none}div.formheading{font-size:16pt;font-weight:bold;margin:.5em 0 0;padding:0}ul#presprefs li,ul#berrybasketprefs li,ul#searchprefs li{display:block}div.phrasebrowse{text-align:center;padding:0;margin:.5em 0 .5em 0}div.QuickSearch{float:right}
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/core_whitespace.css
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/core_whitespace.css	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/style/core_whitespace.css	(revision 24065)
@@ -0,0 +1,376 @@
+
+body {
+  padding:0;
+  margin:0;
+  font-family: sans-serif, arial, helvetica;   
+  background: #fff url('../images/chalk.gif') scroll repeat-y left top;
+  color: #000000 
+}
+
+/* this contains everything - all the other divs */
+#page-wrapper {
+  margin: .5em 3em 0 5em;
+}
+
+a:link
+{
+color: #339966;
+}
+
+a:visited
+{
+color: #066;
+}
+
+a:hover, a:active
+{
+color: #99CC33;
+}
+
+div#banner ul, ul#resultlist, ul#tocnodes, ul#docbuttons, ul.tocnode, ul#bannerlist, ul#navbarlist, ul#collectionlist, ul#servicelist, ul#classifierlist, ul#classifiernodelist, ul#queryitemlist{
+  list-style-type:none;
+  margin:0;
+  padding:0;
+}
+
+div#banner ul li, ul#bannerlist li, ul#navbarlist li {
+  display: inline;
+  margin:0;
+  padding:0;	
+}
+
+
+ul li>select, ul li>input {
+  padding: 0;
+  margin-left:5px;
+}
+
+
+div#banner {
+  margin: 0;
+  padding:0;
+  overflow: hidden;
+}
+
+div#banner p {
+  margin:0;
+  padding: 0;
+  float:left;
+  font-size: 16px;
+  text-align: left;
+  overflow:hidden	
+}
+
+div#banner p a {
+  background-image: url('../images/banner_bg.png');
+  background-repeat: repeat-y;
+}
+
+
+div#banner ul{
+  margin:0;
+  padding:0; 
+  float:right; 
+  font-size: 12px;  
+}
+
+div#banner a{
+  text-decoration: none;
+  color:#000000;
+}
+
+
+ul#bannerlist li a {
+  padding: 0 10px 0 10px; 
+  text-decoration: none;
+}
+
+ul#bannerlist li a:link, ul#bannerlist li a:visited
+{
+ background-color: #DEE79C;
+ background-image: url('../images/bg_off.png');
+ text-decoration: none
+}
+
+ul#bannerlist li a:hover{
+ background-color: #FFFF66;
+ background-image: url('../images/bg_on.png') ;
+ text-decoration: none
+}
+
+
+div#navbar{
+  clear:both;
+}
+
+ul#navbarlist{
+  margin:0;
+  padding:0; 
+  list-style-type: none; 
+  text-align:center;
+  width: 100%;
+  font-size: 80%;
+  background-image: url('../images/bg_green.png');	  
+  background-color: #99CC99
+ }
+
+ul#navbarlist li a {
+  padding: 0 20px 0 20px; 
+  margin: 0;
+  color: #000000; 
+  text-decoration: none;
+}
+
+ul#navbarlist li a:link, ul#navbarlist li a:visited{
+   background-image: url('../images/bg_off.png') ;
+ }
+
+ul#navbarlist li a:hover{
+  background-image: url('../images/bg_on.png') ;
+}
+
+
+ul#collectionlist li, ul#servicelist li{
+  display:block;
+  padding:0;
+  margin: .2em 0 0 0;
+  overflow:hidden;
+}
+
+
+ul#collectionlist img{
+  margin:0;
+  padding:0;
+  width: 150px;
+  height: 45px;
+  border: 1px solid black;
+  background-image: url('../images/collectimg_bg.png');
+  background-repeat: repeat-y;
+  overflow:hidden
+}
+
+ul#collectionlist li a.noimage{
+  display: block;
+  margin:0;
+  width: 145px;
+  height: 40px;
+  border: 1px solid black;
+  background-image: url('../images/collectimg_bg.png');
+  background-repeat: repeat-y;
+  overflow:hidden; padding-left:5px; padding-right:0; padding-top:5px; padding-bottom:0
+
+}
+
+ul#collectionlist li a{
+  font-size: 16px;
+  color: #000000;
+  text-decoration: none;  
+  font-weight: bold;
+}
+
+ul#servicelist li a{
+  margin:0 .5em 0 0;
+}
+
+ul#queryitemlist li{
+  display:block;
+  margin: .2em 0 .2em 0;
+}
+
+ul#classifierlist li{
+  list-style: none;
+  margin: 0 0 5px 0;
+  padding: 0;
+  display: block;
+  color:#000;
+}
+
+ul#classifierlist li#activeclassifier{
+  font-weight:bold;
+  padding: 0 0 0 5px;
+  margin:0 0 5px 0;
+}
+
+ ul#classifierlist li a:link, ul#classifierlist li a:visited  
+{
+   display:block;
+   margin:0;
+   background-image: url('../images/bg_off.png');
+   text-decoration: none; 
+   color:#000;
+   width:100%; padding-left:5px; padding-right:0; padding-top:2px; padding-bottom:2px
+ } 
+
+ul#classifierlist li a:hover, ul#classifierlist li a:active
+{
+  display:block;
+  margin:0;
+  background-image: url('../images/bg_on.png');
+  text-decoration: none; padding-left:5px; padding-right:0; padding-top:2px; padding-bottom:2px
+  
+}
+
+ul#classifierlist{
+   float:left;
+   font-size: 14px;
+   text-align: left;
+   width: 15%;
+   margin:0;
+   padding:0;
+}
+
+div#classifiers{
+  float:left;
+  width: 75%;
+  margin:0;
+  padding:0 0 0 10px;
+ }
+
+ul#classifiernodelist li{
+  list-style: none;
+  margin: 0;
+  padding: 5px 0 0 0;
+  display: block;
+ }
+
+ul.childrenlist{
+  margin: 0 0 0 0;
+  padding: 0 0 0 20px;
+  display: block;
+  width: 100%;
+}
+
+div#content{
+ clear: both;
+ overflow: hidden;
+ margin: .2em 0 0 0;
+}
+
+/* bg image set in style macro */
+div.divbar { 
+  clear: both; 
+  background-image: url('../images/bg_green.png'); 
+  width: 100%; 
+  text-align: center;
+  font-size:80%
+}
+
+
+/** query form style**/
+div#queryform{
+
+}
+
+/** search result style */
+div#terminfo{
+
+}
+
+div#matchdocs{
+
+}
+
+div.resultnavigation{
+ margin: 0;
+ padding:0;
+}
+
+ul#resultlist li{
+  display:block;
+}
+
+
+div.documenttext { clear: both; } /* come after any floating divs */
+
+div#documentheading{
+  font-size: 16pt;
+  font-weight: bold;
+}
+
+div#documentinfo { 
+  float:left;
+  padding:0;
+  margin:0;
+  width:24%;
+} 
+
+div#toc{
+  float:left;
+  text-align:left;
+  width:60%;
+  padding:0;
+  margin:0; 
+}
+
+ul#docbuttons li {
+   display: block;
+  font-size: 11px;
+  font-weight: bold;
+  background: #f7e7c5;
+  margin: 1px;
+  border: 1px solid #eeddbb;
+  text-align: center;
+  vertical-align: middle;
+  height: 30px; /* IE6 and NS4 treat width/height as min-width/min-height */
+  width: 110px;
+}
+
+
+ul#tocnodes li{
+ margin: 0;
+ padding: 5px 0 0 0;
+ display:block;
+}
+
+ul.tocnode {
+  margin:0;
+  padding:5px 0 0 20px;
+}
+
+ul.tocnode  a{
+ margin: 0;
+ padding:0 5px 0 0;
+ }
+
+span.bold{
+  font-weight: bold;	   
+}
+
+div.documentarrows{
+  clear: both; 
+  margin: 0 0 0 0;
+  padding: 1em 0 0 0;   
+}
+
+img.lessarrow{
+  float:left;
+  border: none;  
+}
+
+img.morearrow{
+  float:right;
+  border:none; 
+}
+
+div.formheading{
+  font-size: 16pt;
+  font-weight: bold;
+  margin: .5em 0 0;
+  padding:0;
+}
+
+ul#presprefs li, ul#berrybasketprefs li, ul#searchprefs li{
+  display: block;
+} 
+
+
+div.phrasebrowse{
+  text-align:center;
+  padding:0;
+  margin: .5em 0 .5em 0;   
+}
+
+div.QuickSearch {
+  float: right;
+}
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/about.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/about.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/about.xsl	(revision 24065)
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:gslib="http://www.greenstone.org/skinning"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  
+  <xsl:template match="page">
+    
+    <!-- the page layout template is here -->
+    <html>
+      <head>
+	<title>
+	  <gslib:aboutCollectionPageTitle/>
+	</title>
+	<link rel="stylesheet" href="interfaces/default/style/core.css" type="text/css"/>
+      </head>
+      
+      <body><gslib:textDirectionAttribute/>
+
+	<div id="page-wrapper">
+	  <gslib:displayErrorsIfAny/>
+
+	  <div id="banner">    
+	    <p>
+	      <gslib:collectionHomeLinkWithLogoIfAvailable/>
+	    </p>
+	    <ul id="bannerlist"> 
+	      <li><gslib:homeButtonTop/></li>
+	      <li><gslib:helpButtonTop/></li>
+	      <li><gslib:preferencesButtonTop/></li>
+	    </ul>
+	  </div>
+	  
+	  <!--If some services are available for the current collection display the navigation bar-->
+	  <xsl:choose>
+	    <xsl:when test="$this-element/serviceList/service">
+	      <div id="navbar">
+		<ul id="navbarlist">
+		  <gslib:servicesNavigationBar/>
+		</ul>
+	      </div> 
+	    </xsl:when>
+	    <!--Otherwise simply display a blank divider bar-->
+	    <xsl:otherwise>
+	      <div class="divbar"><gslib:noTextBar/></div>          
+	    </xsl:otherwise>
+	  </xsl:choose>
+	  
+	  <div id="content" class="moz-output-escape"> 
+	    <!--Display the description text of the current collection,
+	    and if some services are available then create a list
+	    of links for each service within a <ul id="servicelist"> element.-->
+	    <gslib:collectionDescriptionTextAndServicesLinks/>
+	  </div>
+
+	  <div id="footer">
+	    <div class="divbar"><gslib:poweredByGS3TextBar/></div>
+	  </div>
+	</div>
+      	<span id="language" style="display: none;"><xsl:value-of select="/page/@lang" /></span>
+      	<span id="interface" style="display: none;"><xsl:value-of select="$interface_name" /></span>
+      	
+		<script type="text/javascript"><xsl:text>var placeholder = false;</xsl:text></script>
+		<script type="text/javascript" src="jquery.js"><xsl:comment>jQuery</xsl:comment></script>
+		<script type="text/javascript" src="test.js"><xsl:comment>Client side transforms</xsl:comment></script>
+		
+      </body>
+    </html>
+  </xsl:template>
+
+
+</xsl:stylesheet>  
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/applet.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/applet.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/applet.xsl	(revision 24065)
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  
+  <xsl:output method="html"/>
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="pageResponse/service/applet"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="../pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <div class="phrasebrowse">
+      <xsl:copy-of select="service/applet"/>
+    </div>
+  </xsl:template>
+</xsl:stylesheet>  
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/authen.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/authen.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/authen.xsl	(revision 24065)
@@ -0,0 +1,656 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+
+  <xsl:output method="html"/> 
+
+  <xsl:template name="pageTitle">
+    <!-- differred for page title --> <span class="getTextFor null document.title.authen.authentication"></span>
+  </xsl:template>
+
+  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+  <xsl:template name="pageHead">
+    <head>
+      <title>
+		<xsl:text> </xsl:text>
+      </title>
+      <xsl:call-template name="globalStyle"/>
+      <xsl:call-template name="pageStyle"/>
+    </head>
+  </xsl:template>
+
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="page">
+    <html>
+      <xsl:call-template name="pageHead" />
+      <xsl:call-template name="addGroup" />
+      <body>
+   
+   	<xsl:call-template name="pageTitle"/>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+ 	  <xsl:variable name="authen_service" select="/page/pageRequest/paramList/param[@name='s']/@value"/>
+	  <xsl:variable name="sub_action" select="/page/pageRequest/@subaction"/>
+	  <xsl:variable name="asn_param" select ="/page/pageRequest/paramList/param[@name='s1.asn']/@value"/>
+	  <xsl:variable name="uan" select ="/page/pageRequest/paramList/param[@name='s1.uan']/@value"/>
+	  <xsl:variable name="pro_action" select ="/page/pageResponse/authenticationNode/service/@aup"/>
+	  <xsl:variable name="au_node" select ="/page/pageResponse/authenticationNode"/>
+	  <xsl:variable name="asn" select ="/page/pageResponse/authenticationNode/service/@asn"/>
+	  <xsl:variable name="info" select ="/page/pageResponse/authenticationNode/service/@info"/>
+	  <xsl:variable name="err" select ="/page/pageResponse/authenticationNode/service/@err"/>
+	  <xsl:variable name="rt" select="/page/pageRequest/paramList/param[@name='rt']/@value"/>
+	  <xsl:variable name="un_s" select="/page/pageResponse/authenticationNode/service/@un"/>
+	  <xsl:variable name="pw_s" select="/page/pageResponse/authenticationNode/service/@pw"/>
+	  
+	  <div align="left" >
+	    <table align="left" border="0" width="100%">
+	      <tr align="left">
+		<td><h2 class="getTextFor authen.authentication"></h2></td>
+		<td><xsl:if test="$un_s!=''">
+		    <xsl:if test="$asn!='' and $asn!='0'">
+		      <span class="getTextFor authen.username"></span>  :  <xsl:value-of select="$un_s"/>
+		    </xsl:if>
+		  </xsl:if></td>
+	      </tr>
+	    </table>
+	  </div>
+
+	  <div id="navbar">
+	    <ul id="navbarlist">
+	      <!--greenstone home-->
+	      <li><a href="{$library_name}"><span class="getTextFor authen.greenstone_home"></span></a></li>
+	      
+	      <!--list users-->
+	      <li>
+		<xsl:choose>
+		  <xsl:when test="$asn!='' and $asn!='0' and $un_s!=''">
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.aup=ListUsers&amp;amp;s1.asn={$asn}&amp;amp;s1.uan=1&amp;amp;s1.un={$un_s}&amp;amp;s1.pw="><span class="getTextFor authen.list_users"></span></a>
+		  </xsl:when>
+		  <xsl:otherwise>
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.asn=&amp;amp;s1.aup=Login"><span class="getTextFor authen.list_users"></span></a>
+		  </xsl:otherwise>
+		</xsl:choose></li>
+	      
+	      <!--add a new user-->
+	      <li>
+		<xsl:choose>
+		  <xsl:when test="$asn!='' and $asn!='0' and $un_s!=''">
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.aup=AddUser&amp;amp;s1.asn={$asn}&amp;amp;s1.uan=1&amp;amp;s1.un={$un_s}&amp;amp;s1.pw=&amp;amp;s1.umun=&amp;amp;s1.umpw=&amp;amp;s1.umgp=&amp;amp;s1.umas=&amp;amp;s1.umc="><span class="getTextFor authen.add_a_new_user"></span></a> 
+		  </xsl:when>
+		  <xsl:otherwise>
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.asn=&amp;amp;s1.aup=Login"><span class="getTextFor authen.add_a_new_user"></span></a>
+		  </xsl:otherwise>
+		</xsl:choose>
+	      </li>
+	      
+	      <!-- change password-->
+	      <li>
+		<xsl:choose>
+		  <xsl:when test="$asn!='' and $asn!='0' and $un_s!=''">
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.aup=ModifyPassword&amp;amp;s1.asn={$asn}&amp;amp;s1.uan=1&amp;amp;s1.un={$un_s}&amp;amp;s1.pw=&amp;amp;s1.umpw1=&amp;amp;s1.umpw2=&amp;amp;s1.umpw="><span class="getTextFor authen.change_password"></span></a>
+		  </xsl:when>
+		  <xsl:otherwise>
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.asn=&amp;amp;s1.aup=Login"><span class="getTextFor authen.change_password"></span></a>
+		  </xsl:otherwise>
+		</xsl:choose>
+	      </li>
+
+	      <li>
+		<xsl:choose>
+		  <xsl:when test="$un_s!='' and $asn!='' and $asn!='0'">
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.asn=&amp;amp;s1.aup=Login&amp;amp;s1.un=&amp;amp;s1.pw="><span class="getTextFor authen.logout"></span></a>
+		  </xsl:when>
+		  <xsl:otherwise>
+		    <a href="{$library_name}?a=g&amp;amp;rt=r&amp;amp;sa=authen&amp;amp;s=Authentication&amp;amp;s1.asn=&amp;amp;s1.aup=Login"><span class="getTextFor authen.login"></span></a>
+		  </xsl:otherwise>
+		</xsl:choose>
+	      </li>
+	    </ul>
+	  </div>
+
+	  <table align="left" border="0" width="100%">
+	    <tr>
+	      <td>
+		<div id="content" align="center">
+		  <!-- login -->
+		  <xsl:if test="$pro_action='Login'">
+		    <xsl:choose>
+		      <xsl:when test="$asn!='' and $asn!='0'">
+			<p align="left"> <span class="getTextFor authen.login_successfully"></span></p>
+		      </xsl:when>
+		      <xsl:otherwise>
+
+			<p align="left">
+			  <span class="getTextFor authen.login_describe_line_3"></span><br/></p>
+			<xsl:if test="$err='un-pw-err'">
+			  <p align="left"><font color='red'><span class="getTextFor authen.wrong_password_warning"></span></font></p>
+			</xsl:if>
+			<xsl:if test="$err='no-permission' and $info='Login'">
+			  <p align="left"><font color='red'><span class="getTextFor authen.no_permission"></span></font></p>
+			</xsl:if>
+			<xsl:if test="$err='as-false'">
+			  <p align="left"><font color='red'><span class="getTextFor authen.account_status_false"></span></font></p>
+			</xsl:if>
+			<xsl:call-template name="login">
+			  <xsl:with-param name="sub_action" select="$sub_action"/>
+			  <xsl:with-param name="authen_service" select="$authen_service"/>
+			  <xsl:with-param name="pro_action" select="$pro_action"/>	
+			</xsl:call-template>
+
+		      </xsl:otherwise>
+		    </xsl:choose>
+		  </xsl:if>
+
+		  <!-- list users-->
+		  <xsl:if test="$pro_action='ListUsers'">
+		    
+		    <xsl:if test="$asn='1' and $info='all-un'">
+		      <xsl:call-template name="listusers" >
+		      </xsl:call-template>
+		    </xsl:if>
+
+		    <xsl:if test="$info='Login'">
+		      <p align="left">
+			<span class="getTextFor authen.login_describe_line_2"></span><br/></p>
+		      <xsl:if test="$err='no-permission' and $info='Login'">
+			<p align="left"><font color='red'><span class="getTextFor authen.no_permission"></span></font></p>
+		      </xsl:if>
+		    </xsl:if>
+		  </xsl:if>
+		  
+		  <!-- add a new user-->
+		  <xsl:if test="$pro_action='AddUser'"> 
+		    <xsl:if test="$err!='' and $err!='no-permission' and $err!='un-exist' and $err!='un-err' and $err!='pw-err'">
+		      <p align="left"><font color='red'><xsl:value-of select="$err" /></font></p>
+		    </xsl:if>
+
+		    <xsl:if test="$asn!='1'">
+		      <p align="left">
+			<span class="getTextFor authen.login_describe_line_2"></span><br/>
+		      </p>
+		      <xsl:if test="$err='no-permission'">
+			<p align="left"><font color='red'><span class="getTextFor authen.no_permission"></span></font></p>
+		      </xsl:if>
+		    </xsl:if>
+		    
+		    <xsl:if test="count(/page/pageResponse/authenticationNode/service/userNodeList) = 1">
+		      <xsl:call-template name="listusers" >
+		      </xsl:call-template>
+		    </xsl:if>
+		    
+		    <xsl:if test="$info='adduser_interface'">
+		      <h2 align="left"><span class="getTextFor authen.add_a_new_user_title"></span></h2>
+		      <xsl:if test="$err='pw-err'">
+			<p align="left"><font color="red"><span class="getTextFor authen.password_err"></span></font></p>
+		      </xsl:if>	
+		      <xsl:if test="$err='un-err'">
+		      <!-- not sure if this is meant to be unsername_err; if it is, disregard -->
+			<p align="left"><font color="red"><span class="getTextFor authen.unsername_err"></span></font></p>
+		      </xsl:if>	
+		      <xsl:if test="$err='un-exist'">
+			<p align="left"><font color='red'><span class="getTextFor authen.user_has_existed"></span></font></p>
+		      </xsl:if>
+		      <xsl:call-template name="edituser" >
+			<xsl:with-param name="sub_action" select="$sub_action"/>
+			<xsl:with-param name="authen_service" select="$authen_service"/>
+			<xsl:with-param name="pro_action" select="$pro_action"/>
+			<xsl:with-param name="umun_s" />
+			<xsl:with-param name="umpw_s" />
+			<xsl:with-param name="umas_s" />
+			<xsl:with-param name="umgp_s" />
+			<xsl:with-param name="umc_s" />
+			<xsl:with-param name="oumun_s" />
+			<xsl:with-param name="un_s" select="$un_s"/>
+			<xsl:with-param name="pw_s" select="$pw_s"/>
+			<xsl:with-param name="asn" select="$asn"/>
+		      </xsl:call-template>
+
+		    </xsl:if> 
+		  </xsl:if>
+		  
+		  <!-- modify the passwrod of a user-->
+		  <xsl:if test="$pro_action='ModifyPassword'">
+		    
+		    <xsl:if test="$err!='' and $err!='umpw1-err' and $err!='umpw2-err' and $err!='pw-umpw-nm-err' and $err!='umpw-null-err' and $err!='umpw1-umpw2-nm-err' and $err!='umpw1-umpw2-null-err'"><p align="left"><font color='red'><xsl:value-of select="$err" /></font></p>
+		    </xsl:if>
+
+		    <xsl:if test="$err=''">
+		      <h2 align="left"><span class="getTextFor authen.change_password_title"></span></h2>
+		      <p align="left"><span class="getTextFor authen.change_password_successed_content"></span></p>
+		    </xsl:if>
+		    
+		    <xsl:if test="$asn!='0' and $info='modify_interface'">
+		      <h2 align="left"><span class="getTextFor authen.change_password_title"></span></h2>
+		      <p align="left"><font color="grey"><span class="getTextFor authen.change_password_describe_line_1"></span></font></p>
+
+		      <xsl:if test="$err='umpw1-err'">
+			<p align="left"><font color="red"><span class="getTextFor authen.new_password_invalid"></span></font></p>
+		      </xsl:if>
+		      <xsl:if test="$err='umpw2-err'">
+			<p align="left"><font color="red"><span class="getTextFor authen.retyped_password_invalid"></span>></font></p>
+		      </xsl:if>
+		      <xsl:if test="$err='pw-umpw-nm-err' or $err='umpw-null-err'">
+			<p align="left"><font color="red"><span class="getTextFor authen.old_password_warning"></span></font></p>
+		      </xsl:if>  
+		      <xsl:if test="$err='umpw1-umpw2-nm-err'">
+			<p align="left"><font color="red"><span class="getTextFor authen.two_password_not_match"></span></font></p>
+		      </xsl:if> 
+		      <xsl:if test="$err='umpw1-umpw2-null-err'">
+			<p align="left"><font color="red"><span class="getTextFor authen.password_empty_warning"></span></font></p>
+		      </xsl:if> 
+		      
+		      <xsl:call-template name="modifypassword">
+			<xsl:with-param name="sub_action" select="$sub_action"/>
+			<xsl:with-param name="authen_service" select="$authen_service"/>
+			<xsl:with-param name="pro_action" select="$pro_action"/>
+			<xsl:with-param name="un_s" select="$un_s"/>
+			<xsl:with-param name="pw_s" select="$pw_s"/>
+			<xsl:with-param name="asn" select="$asn"/>
+		      </xsl:call-template>
+		    </xsl:if>
+		  </xsl:if> 
+
+		  <!-- delete a user -->
+		  <xsl:if test="$pro_action='DeleteUser'"> 
+		    <xsl:if test="$err!=''">
+		      <p align="left"><font color='red'><xsl:value-of select="$err" /></font></p>
+		    </xsl:if>
+
+		    <xsl:if test="$info='confirm'">
+		      <xsl:call-template name="deleteuser"> 
+			<xsl:with-param name="sub_action" select="$sub_action"/>
+			<xsl:with-param name="authen_service" select="$authen_service"/>
+			<xsl:with-param name="pro_action" select="$pro_action"/>
+			<xsl:with-param name="un_s" select="$un_s"/>
+			<xsl:with-param name="umun_s" select="/page/pageResponse/authenticationNode/service/@umun"/>	
+			<xsl:with-param name="asn" select="$asn"/>
+		      </xsl:call-template>
+		    </xsl:if>
+		    <xsl:if test="count(/page/pageResponse/authenticationNode/service/userNodeList) = 1">
+		      <xsl:call-template name="listusers" >
+		      </xsl:call-template>
+		    </xsl:if>
+		  </xsl:if>
+		  
+		  <!-- edit the user's info -->
+		  <xsl:if test="$pro_action='EditUser'"> 
+		    <xsl:if test="$err!='' and $err!='umpw-err' and $err!='umun-err' and $err!='ini-umpw-err' and $err!='un-exist'">
+		      <p align="left"><font color='red'><xsl:value-of select="$err" /></font></p>
+		    </xsl:if>
+
+		    <xsl:if test="$info='edituser-interface'"> 
+		      <h2 align="left"><span class="getTextFor authen.edit_user_information"></span></h2>
+		      <xsl:if test="$err='umpw-err'"> 
+			<p align="left"><font color="red"><span class="getTextFor authen.password_err"></span></font></p>
+		      </xsl:if>
+		      <xsl:if test="$err='umun-err'"> 
+			<p align="left"><font color="red"><span class="getTextFor authen.username_err"></span></font></p>
+		      </xsl:if>
+		      <xsl:if test="$err='ini-umpw-err'"> 
+			<p align="left"><font color="red"><span class="getTextFor authen.password_initial"></span></font></p>
+		      </xsl:if>
+		      <xsl:if test="$err='un-exist'">
+			<p align="left"><font color='red'><span class="getTextFor authen.user_has_existed"></span></font></p>
+		      </xsl:if>
+		      <xsl:call-template name="edituser" >
+			<xsl:with-param name="sub_action" select="$sub_action"/>
+			<xsl:with-param name="authen_service" select="$authen_service"/>
+			<xsl:with-param name="pro_action" select="$pro_action"/>
+			<xsl:with-param name="umun_s" select="/page/pageResponse/authenticationNode/service/@umun"/>
+			<xsl:with-param name="umpw_s" select="/page/pageResponse/authenticationNode/service/@umpw"/>
+			<xsl:with-param name="umas_s" select="/page/pageResponse/authenticationNode/service/@umas"/>
+			<xsl:with-param name="umgp_s" select="/page/pageResponse/authenticationNode/service/@umgp"/>
+			<xsl:with-param name="umc_s" select="/page/pageResponse/authenticationNode/service/@umc"/>
+			<xsl:with-param name="oumun_s" select="/page/pageResponse/authenticationNode/service/@oumun"/>
+			<xsl:with-param name="un_s" select="$un_s"/>
+			<xsl:with-param name="pw_s" select="$pw_s"/>
+			<xsl:with-param name="asn" select="$asn"/>
+		      </xsl:call-template>
+		    </xsl:if> 
+		    <xsl:if test="$info='all-un'">
+		      <xsl:if test="count(/page/pageResponse/authenticationNode/service/userNodeList) = 1">
+			<xsl:call-template name="listusers" >
+			</xsl:call-template>
+		      </xsl:if>
+		    </xsl:if>
+		  </xsl:if>
+		  
+		</div>
+	      </td>
+	    </tr>
+	  </table>
+	  <div id="navbar">	  
+	    <xsl:call-template name="greenstoneFooter" />
+	  </div>	  
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+  
+  <!--template name="login"-->
+  <xsl:template name="login">
+    <xsl:param name="sub_action"/>
+    <xsl:param name="authen_service"/>
+    <xsl:param name="pro_action"/>
+    <div>
+      <form id="LoginForm" method="get" action="{$library_name}">
+	<input type='hidden' name='a' value='g'/>
+	<input type='hidden' name='sa' value='{$sub_action}'/>
+	<input type='hidden' name='s' value='{$authen_service}'/>
+	<input type='hidden' name='rt' value='r'/>
+	<input type='hidden' name='s1.asn' value='0'/>
+	<input type='hidden' name='s1.uan' value='1'/>
+	<input type='hidden' name='s1.aup' value='{$pro_action}'/>
+	<input type='hidden' name='s1.umpw1' value=''/>
+	<input type='hidden' name='s1.umpw2' value=''/>
+	<input type='hidden' name='s1.umc' value=''/>
+	<input type='hidden' name='s1.umgp' value=''/>
+	<input type='hidden' name='s1.umun' value=''/>
+	<input type='hidden' name='s1.umpw' value=''/>
+	<input type='hidden' name='s1.umas' value=''/>
+
+	<table align="center">
+	  <tr>
+	    <td><span class="getTextFor authen.username"></span></td><td><input type="string" name="s1.un" size="10" value=""/></td><td></td>
+	  </tr>
+	  <tr>
+	    <td><span class="getTextFor authen.password"></span></td><td><input type="password" name="s1.pw" size="10" value=""/></td><td>
+	      <input type="submit" value="submit"></input></td>
+	  </tr>
+	</table>
+      </form>
+    </div>
+  </xsl:template>
+
+  <!--template name="listusers"-->
+  <xsl:template name="listusers" >
+    <h2 align="left"><span class="getTextFor authen.list_of_current_users_title"></span></h2>
+
+    <table id='mainTable' align="left" border="0" cellspacing="1" cellpadding="3" width="100%" >
+      <tr>
+	<th bgcolor="#d0d0d0" class="getTextFor authen.username"></th>
+	<th bgcolor="#d0d0d0" class="getTextFor authen.account_status"></th>
+	<th bgcolor="#d0d0d0" class="getTextFor authen.groups"></th>
+	<th bgcolor="#d0d0d0" class="getTextFor authen.comment"></th>
+	<th bgcolor="#d0d0d0"></th>
+      </tr>
+      <xsl:for-each select="/page/pageResponse/authenticationNode/service/userNodeList/userNode">
+	<tr>
+	  <td bgcolor="#eeeeee"><xsl:value-of select="@umun"/></td>
+	  <td id="status" bgcolor="#eeeeee">
+	    <script type="text/javascript">
+	      <xsl:text disable-output-escaping="yes">
+		var status="</xsl:text><xsl:value-of select="@umas"/><xsl:text disable-output-escaping="yes">";
+		if (status=="true"){
+		  document.getElementById("status").innerHTML="enabled";
+		}
+		if (status=="false"){
+		  document.getElementById("status").innerHTML="disabled";
+		}
+	      </xsl:text>		 
+	    </script>
+	  </td>
+	  <td id="group" bgcolor="#eeeeee">
+	    <script type="text/javascript">
+	      <xsl:text disable-output-escaping="yes">
+		var groups="</xsl:text><xsl:value-of select="@umgp"/><xsl:text disable-output-escaping="yes">";
+		var split_groups= groups.split(",");
+		var new_groups="";
+		for (j=0; j &lt; split_groups.length ; j++){
+		  new_groups+=split_groups[j]+" &lt;br /&gt; ";
+		}
+		document.getElementById('group').innerHTML=new_groups;
+	      </xsl:text>		 
+	    </script>
+	  </td>
+	  <td bgcolor="#eeeeee"><xsl:value-of select="@umc"/></td>
+	  <td bgcolor="#eeeeee">
+	    <form name="ListUsersForm" method="get" action="{$library_name}">
+	      <input type='hidden' name='a' value='g'/>
+	      <input type='hidden' name='sa' value='authen'/>
+	      <input type='hidden' name='s' value='Authentication'/>
+	      <input type='hidden' name='rt' value='r'/>
+	      <input type='hidden' name='s1.asn' value='1'/>
+	      <input type='hidden' name='s1.uan' value='1'/>
+
+	      <input type='hidden'><xsl:attribute name="name">s1.oumun</xsl:attribute><xsl:attribute name="value"><xsl:value-of select="@umun"/></xsl:attribute></input>
+	      <input type='hidden'><xsl:attribute name="name">s1.umun</xsl:attribute><xsl:attribute name="value"><xsl:value-of select="@umun"/></xsl:attribute></input>
+	      <input type='hidden' name='s1.cm' value=''/>
+
+	      <input type="submit"><xsl:attribute name="name">s1.aup</xsl:attribute><xsl:attribute name="value">EditUser</xsl:attribute></input>
+	      <input type="submit"><xsl:attribute name="name">s1.aup</xsl:attribute><xsl:attribute name="value">DeleteUser</xsl:attribute></input>
+	    </form>
+	  </td>
+	</tr>
+      </xsl:for-each>
+    </table>
+  </xsl:template>
+
+  <!--template name="modifypassword"-->
+  <xsl:template name="modifypassword" >
+    <xsl:param name="sub_action"/>
+    <xsl:param name="authen_service"/>
+    <xsl:param name="pro_action"/>
+    <xsl:param name="un_s"/>
+    <xsl:param name="pw_s"/>
+    <xsl:param name="asn"/>
+    <div>
+      <form id="modifyForm" method="get" action="{$library_name}">
+	<input type='hidden' name='a' value='g'/>
+	<input type='hidden' name='sa' value='{$sub_action}'/>
+	<input type='hidden' name='s' value='{$authen_service}'/>
+	<input type='hidden' name='rt' value='r'/>
+	<input type='hidden' name='s1.un' value='{$un_s}'/>
+	<input type='hidden' name='s1.pw' value='{$pw_s}'/>
+	<input type='hidden' name='s1.asn' value='{$asn}'/>
+	<input type='hidden' name='s1.uan' value='1'/>
+	<input type='hidden' name='s1.aup' value='{$pro_action}'/>
+	
+	<table align="center"><tr><td align="right" class="getTextFor authen.old_password">
+	      </td><td><input type="password" name="s1.umpw" size="10" value=""/></td></tr>
+	  <tr><td align="right" class="getTextFor authen.new_password">
+	      </td><td><input type="password" name="s1.umpw1" size="10" value=""/></td></tr>
+	  <tr><td align="right" class="getTextFor authen.retype_new_password">
+	      </td><td><input type="password" name="s1.umpw2" size="10" value=""/></td></tr>
+	  <tr><td></td><td>
+	      <input type="submit" value="submit"></input></td>
+	  </tr>
+	</table>
+      </form>
+    </div>
+  </xsl:template>
+
+  <!--template name="deleteuser"-->
+  <xsl:template name="deleteuser">
+    <xsl:param name="sub_action"/>
+    <xsl:param name="authen_service"/>
+    <xsl:param name="pro_action"/>
+    <xsl:param name="un_s"/>
+    <xsl:param name="umun_s"/>
+    <xsl:param name="asn"/>
+    <div >
+      <form id="deleteForm" method="get" action="{$library_name}">
+	<input type='hidden' name='a' value='g'/>
+	<input type='hidden' name='sa' value='{$sub_action}'/>
+	<input type='hidden' name='s' value='{$authen_service}'/>
+	<input type='hidden' name='rt' value='r'/>
+	<input type='hidden' name='s1.aup' value='{$pro_action}'/>
+	<input type='hidden' name='s1.asn' value='{$asn}'/>
+	<input type='hidden' name='s1.uan' value='1'/>
+	<input type='hidden' name='s1.umun' value='{$umun_s}'/>
+	<p><font color='red' class="getTextFor authen.do_you_really_want_to_permanently_remove_user"> <xsl:value-of select="$umun_s"/>" ?</font></p>
+	<input type="submit" value="yes"><xsl:attribute name="name">s1.cm</xsl:attribute></input>
+	<input type="submit" value="no"><xsl:attribute name="name">s1.cm</xsl:attribute></input>
+      </form>
+    </div>
+  </xsl:template>
+  
+  <!--template name="edituser"-->
+  <xsl:template name="edituser" >
+    <xsl:param name="sub_action"/>
+    <xsl:param name="authen_service"/>
+    <xsl:param name="pro_action"/>
+    <xsl:param name="un_s"/>
+    <xsl:param name="pw_s"/>
+    <xsl:param name="umun_s"/>
+    <xsl:param name="umpw_s"/>
+    <xsl:param name="umas_s"/>
+    <xsl:param name="umgp_s"/>
+    <xsl:param name="umc_s"/>
+    <xsl:param name="oumun_s"/>	
+    <xsl:param name="asn"/>
+    <div>
+      <form id="editForm" method="get" action="{$library_name}">
+	<input type='hidden' name='a' value='g'/>
+	<input type='hidden' name='sa' value='{$sub_action}'/>
+	<input type='hidden' name='s' value='{$authen_service}'/>
+	<input type='hidden' name='rt' value='r'/>
+	<input type='hidden' name='s1.asn' value='{$asn}'/>
+	<input type='hidden' name='s1.uan' value='1'/>
+	<input type='hidden' name='s1.aup' value='{$pro_action}'/>
+	<input type='hidden' name='s1.un' value='{$un_s}'/>
+	<input type='hidden' name='s1.pw' value='{$pw_s}'/>
+	
+	<table align="left" ><tr><td class="getTextFor authen.username">
+	      </td><td><input type="text" name="s1.umun" size="15" value="{$umun_s}"/></td><td><font color="gray" class="getTextFor authen.username_describe"></font></td></tr>
+	  <tr><td class="getTextFor authen.password">
+	      </td><td><input type="password" name="s1.umpw" size="15" value="{$umpw_s}"/></td><td><font color="gray" class="getTextFor authen.password_describe"></font></td></tr>
+	  <tr><td class="getTextFor authen.account_status">
+	      </td><td>	
+	      <select name="s1.umas">
+		<xsl:if test="$umas_s=''">
+		  <option value="true" selected="selected" class="getTextFor authen.enabled"></option>
+		  <option value="false" class="getTextFor authen.disabled"></option>
+		</xsl:if> 
+		<xsl:if test="$umas_s='true'">
+		  <option value="true" selected="selected" class="getTextFor authen.enabled"></option>
+		  <option value="false" class="getTextFor authen.disabled"></option>
+		</xsl:if> 
+		<xsl:if test="$umas_s='false'">
+		  <option value="true" class="getTextFor authen.enabled"></option>
+		  <option value="false" selected="selected" class="getTextFor authen.disabled"></option>
+		</xsl:if> 
+	      </select></td><td></td></tr>
+	  <tr><td class="getTextFor authen.groups">
+	      </td><td><input type="text" id="group" name="s1.umgp" size="70" value="{$umgp_s}"/></td><td><font color="gray" class="getTextFor authen.groups_describe"></font></td></tr>
+	  <tr>
+	    <td></td>
+	    <td  align="right"> <select id="groups" size="0">
+		<script type="text/javascript">
+		  <xsl:text disable-output-escaping="yes">
+		    var group_arr=Array("administrator","all-collections-editor","personal-collections-editor");
+		    var group_string=document.getElementById("group").value;
+		    var split_group_string=group_string.split(",");
+		    var find=0;
+		    for (i=0; i &lt; group_arr.length; i++){
+		      find=0;
+		      for (j=0; j &lt; group_arr.length; j++){
+		        if (split_group_string[j]==group_arr[i]){
+		          find=1;
+		        }
+		      }
+		      if (find==0){
+		        op = document.createElement('option');
+		        op.innerHTML = group_arr[i];
+		        op.setAttribute("value", group_arr[i]);
+		        document.getElementById("groups").appendChild(op);
+		      }
+	            }
+		    
+		  </xsl:text>		 
+		</script>
+	      </select></td><td><input type="button" name="addGroupButton" value="add" onClick="addGroup('groups')"/></td>
+	  </tr>
+	  <tr>
+	    <td></td>
+	    <td  align="right"> 
+	      <select  id="collects" size="0">
+		<xsl:for-each select="/page/pageResponse/collectionList/collection">
+		  <script type="text/javascript">
+		    <xsl:text disable-output-escaping="yes">
+		      var group="</xsl:text><xsl:value-of select="@name"/>-collection-editor<xsl:text disable-output-escaping="yes">";
+		      var group_string=document.getElementById("group").value;
+		      var split_group_string=group_string.split(",");
+		      var find=0;
+		      for (i=0; i &lt; split_group_string.length; i++){
+		        if (split_group_string[i]==group){
+		          find=1;
+		        }
+		      }
+		      if (find==0){
+		        op = document.createElement('option');
+		        op.innerHTML = group;
+		        op.setAttribute("value", group);
+		        document.getElementById("collects").appendChild(op);
+		      }
+		    </xsl:text>		 
+		  </script>
+		</xsl:for-each>
+	      </select>
+	    </td>
+	    <td><input type="button" name="addGroupButton" value="add" onClick="addGroup('collects')"/></td>
+	  </tr>
+	  <tr><td class="getTextFor authen.comment">
+	      </td><td colspan="2"><div><textarea cols="40" rows="5" name="s1.umc"><xsl:value-of select="$umc_s"/>
+
+		</textarea></div></td></tr> 
+	  <tr>
+
+	    <td></td><td>
+	      <input type="submit" value="submit"><xsl:attribute name="name">s1.cm</xsl:attribute></input>
+	      <xsl:if test="$pro_action!='AddUser'">
+		<input type="submit" value="cancel"><xsl:attribute name="name">s1.cm</xsl:attribute></input>
+	      </xsl:if>
+	    </td><td></td></tr>
+	</table>
+	<input type='hidden' name='s1.oumun' value='{$oumun_s}'/>
+      </form>
+    </div>
+  </xsl:template>
+
+  <!-- addGroup() javascript -->
+  <xsl:template name="addGroup">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+	function addGroup(g){
+	  var itemSelected;
+	  var splitGroup;
+	  var groupExit;
+
+	  if (document.getElementById("editForm")!=null){
+	    //itemSelected=document.getElementById("editForm").groups.options.selectedIndex;
+	    itemSelected=document.getElementById(g).options.selectedIndex;
+	    if (document.getElementById(g).options[itemSelected].text!=""){
+	      if (document.getElementById("group").value==""){
+	        document.getElementById("group").value=document.getElementById("group").value+document.getElementById(g).options[itemSelected].text;
+	      }else{
+	        splitGroup=document.getElementById("group").value.split(",");
+	        for (var i=0; i &lt; splitGroup.length; i++){
+	          if (splitGroup[i]==document.getElementById(g).options[itemSelected].text){
+	            alert(document.getElementById(g).options[itemSelected].text + " has been added.");
+	            groupExit=1;
+	            break;
+	          }
+	        }
+	        if (groupExit!=1) {
+	          document.getElementById("group").value=document.getElementById("group").value+","+document.getElementById(g).options[itemSelected].text;
+	        }
+	      }
+	      document.getElementById(g).options[itemSelected]=new Option("",itemSelected);
+	    }
+	  }
+	}
+      </xsl:text>
+    </script>    
+  </xsl:template>
+  
+</xsl:stylesheet>  
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/berry.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/berry.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/berry.xsl	(revision 24065)
@@ -0,0 +1,747 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  <!--<xsl:include href="style.xsl"/>-->
+  <xsl:include href="service-params.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/>  
+
+  <xsl:param name="library_name"/>
+  
+   <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <xsl:call-template name="pageHead"/>	 
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:apply-templates select="pageResponse"/>
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+
+  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+  <xsl:template name="pageHead">
+    <head>
+      <title>
+	<xsl:call-template name="pageTitle"/>
+      </title>
+      <xsl:call-template name="pageStyle"/>
+    </head>
+  </xsl:template>
+  
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/serviceCluster/metadataList/metadata[@name='Title']"/>
+    Berry Basket
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle" >
+    <xsl:call-template name="styleSheet" />
+    <xsl:call-template name="loadLibrary" />
+    <xsl:call-template name="buildContent" />   
+    <!-- <xsl:call-template name="showMailBox" />-->
+  </xsl:template>    
+  
+  <xsl:template match="pageResponse">
+    <xsl:variable name="clusterName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="berryPageBanner" />
+    <xsl:apply-templates select="paramList"/>
+    <div id="content" ><span></span></div> 
+    <xsl:call-template name="footBanner" />
+  </xsl:template>
+  
+
+  <xsl:template match="collection">
+    <xsl:for-each select="item">
+      <xsl:text disable-output-escaping="yes">
+	var  doc = new Array();             
+      </xsl:text>
+      <xsl:for-each select="@*">
+	<xsl:text disable-output-escaping="yes">
+	  doc["</xsl:text><xsl:value-of select="name()" /><xsl:text disable-output-escaping="yes">"]='</xsl:text><xsl:value-of select="." /><xsl:text disable-output-escaping="yes">'; </xsl:text>   
+      </xsl:for-each>
+      <xsl:text disable-output-escaping="yes"> 
+	docList[docList.length] = doc; 
+      </xsl:text>  
+    </xsl:for-each>     
+  </xsl:template>
+  
+  
+  <xsl:template name="buildContent">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+	var previousView;
+	var docList = new Array();
+	var urlonly = false;
+	var mailinfo = new Array();
+	mailinfo['address'] = "To: ";
+	mailinfo['cc'] = "CC: ";
+	mailinfo['bcc'] = "Bcc: ";
+	mailinfo['subject'] = "Subject: "; 
+	var textwin;
+	var mailwin;
+      </xsl:text>
+      <xsl:apply-templates select="/page/pageResponse/collection" />       
+      
+      <xsl:text disable-output-escaping="yes">
+    
+       function navigate(e){   
+             var target = e.target;
+       
+	     if (target.id.toLowerCase() == 'fullview'){  
+                  showFullView();
+              }
+
+             if (target.id.toLowerCase() == 'textview'){       
+               showTextView();
+             }
+
+             if (target.id.toLowerCase() == 'email'){       
+               showEmail();
+            }
+
+            if (target.id.toLowerCase() == 'sendmail'){       
+               sendMail();
+            }
+            
+           
+
+            if (target.id.toLowerCase() == 'urlcheck' &amp;amp;&amp;amp; urlonly){
+               var urlcheck = YAHOO.util.Dom.get('urlcheck');
+               urlcheck.src = 'interfaces/default/images/check3.gif';              
+               var parea  =YAHOO.util.Dom.get('pretextarea');       
+               urlonly = false;
+               populateUrlsAndMetadata(parea);
+               return;
+               
+            }
+
+            if (target.id.toLowerCase() == 'urlcheck' &amp;amp;&amp;amp; !urlonly ){ 
+                var urlcheck = YAHOO.util.Dom.get('urlcheck');
+                urlcheck.src = 'interfaces/default/images/check4.gif';                       
+                var parea  =YAHOO.util.Dom.get('pretextarea');
+                populateUrls(parea);        
+                urlonly = true;
+                return;
+             } 
+
+            if (target.id.toLowerCase() == 'extextview' ){
+               if (textwin != null){
+                   textwin.close();
+               }
+
+               textwin = window.open("","Berry basket plain text view","status=1,width=450,height=300");
+               textwin.moveTo(0,0);
+               var content = document.createElement('div');
+                buildPreview(content);
+                var body = textwin.document.getElementsByTagName('body')[0]; 
+                body.appendChild(content);
+                var prearea =  textwin.document.getElementsByTagName('textarea')[0];
+                prearea.cols = '55';
+                prearea.rows = '15';        
+             }
+
+             if (target.id.toLowerCase() == 'exemail' ){
+               if (mailwin != null){
+                   mailwin.close();
+               }
+               mailwin = window.open("","Berry basket mail to a friend","status=1,width=450,height=350");
+               mailwin.moveTo(0,0);
+               var content = document.createElement('div');
+               getEmailContent(content);
+               var body = mailwin.document.getElementsByTagName('body')[0]; 
+               body.appendChild(content);           
+                var prearea =  mailwin.document.getElementsByTagName('textarea')[0];
+                prearea.cols = '50';
+                prearea.rows = '11'; 
+             }
+              
+        }
+
+        function showFullView(){
+          
+             var content =  YAHOO.util.Dom.get('content'); 
+             var fullview =  YAHOO.util.Dom.get('fullview');
+
+              if (previousView != null){
+                 previousView.style.backgroundImage =  'url("interfaces/default/images/bg_on.png")'; 
+              } 
+              previousView = fullview;
+              previousView.style.backgroundImage =  'url("interfaces/default/images/bg_green.png")';
+
+               while (content.hasChildNodes()) {
+		 content.removeChild(content.firstChild);
+	       }                        
+           
+             if (docList.length == 0){
+                 content.appendChild(document.createTextNode("Your berry basket is empty."));
+                 return;
+              }
+
+ 
+            var trashbin = document.createElement('div');
+            trashbin.id ='trashbin';   
+            var binhandle = document.createElement('div');
+            binhandle.id = 'binhandle';   
+            binhandle.appendChild(document.createElement('span'));          
+            trashbin.appendChild(binhandle) 
+
+            content.appendChild(trashbin);
+
+            var dd = new ygDDOnTop('trashbin');
+            dd.setHandleElId('binhandle');      
+            new YAHOO.util.DDTarget('trashbin','trash');
+        
+            var dlist = document.createElement('div');
+            content.appendChild(dlist);                          
+            var ol =   document.createElement('ol');            
+            dlist.appendChild(ol); 
+
+             for (var i in docList){
+               var doc = docList[i];
+               var li = document.createElement('li'); 
+               var a = document.createElement('a'); 
+               var text ="";
+               a.href ="?a=d&amp;amp;c="+doc['collection']+"&amp;amp;d="+doc['name'];
+               a.appendChild(document.createTextNode(doc['title'])); 
+                if (doc['root_title'] != ""){
+                     li.appendChild(document.createTextNode(doc['root_title']+": ")); 
+                   }               
+               li.appendChild(a);
+               var metadata = "";
+               for (var metaItem in doc &amp;amp;&amp;amp; metaItem != 'title'){
+                    metadata = "\n"+metaItem+": "+ doc[metaItem]+"\n";
+               }
+               text +=metadata+"\n";
+               li.appendChild(document.createTextNode(text));
+               li.id = doc['collection']+":"+ doc['name']; 
+               li.className = 'berrydoc';
+               ol.appendChild(li);
+                new ygDDPlayer(li.id,'trash',docList); 
+         }
+
+         /**          
+           var extra = document.createElement('div');
+           var textview =  document.createElement('span'); 
+           textview.id = 'extextview';
+           textview.className = 'extralink';   
+           textview.appendChild(document.createTextNode("plain text version"));                   
+           var email =  document.createElement('span');
+           email.appendChild(document.createTextNode("email to a friend"));
+           email.id = 'exemail';      
+           email.className = 'extralink';    
+           extra.appendChild(textview);
+           extra.appendChild(email);
+           content.appendChild(extra);
+         **/ 
+        }
+
+       function showTextView(){
+             var content =  YAHOO.util.Dom.get('content'); 
+             var textview =  YAHOO.util.Dom.get('textview');
+
+              if (previousView != null &amp;amp;&amp;amp; textview !=null){
+                 previousView.style.backgroundImage =  'url("interfaces/default/images/bg_on.png")'; 
+              } 
+
+             if (textview !=null){
+               previousView = textview;
+               previousView.style.backgroundImage =  'url("interfaces/default/images/bg_green.png")';
+             }
+
+               while (content.hasChildNodes()) {
+		 content.removeChild(content.firstChild);
+	       }                        
+           
+             if (docList.length == 0){
+                content.appendChild(document.createTextNode("Your berry basket is empty."));
+                return;
+              }
+
+             buildPreview(content);   
+
+        
+       }
+
+       function getEmailContent(content){
+           var item ;
+           var tr;
+           var td;
+           var input;
+           
+           table = document.createElement('table');
+           table.setAttribute("class","mailtable");          
+
+          for (item in mailinfo){
+  	   tr = document.createElement('tr');       
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailinfo[item]));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", item);
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+          
+          }
+
+ 	   // an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+	   content.appendChild(table);
+          
+           buildPreview(content);   
+
+           //send button
+	   input = document.createElement('input'); 
+           input.setAttribute("id", 'sendmail');
+           input.setAttribute("class", "sendbutton");
+           input.setAttribute("type", "button");
+           input.setAttribute("value", "send");        
+           content.appendChild(input);
+           
+        }
+
+      
+        function showEmail(){
+          
+             var content =  YAHOO.util.Dom.get('content'); 
+             var email =  YAHOO.util.Dom.get('email');
+
+              if (previousView != null &amp;amp;&amp;amp; email !=null ){
+                 previousView.style.backgroundImage =  'url("interfaces/default/images/bg_on.png")'; 
+              } 
+              
+              if (email != null){
+                previousView = email;
+               previousView.style.backgroundImage =  'url("interfaces/default/images/bg_green.png")';
+             }
+               while (content.hasChildNodes()) {
+		 content.removeChild(content.firstChild);
+	       }                        
+           
+             if (docList.length == 0){
+                content.appendChild(document.createTextNode("Your berry basket is empty."));
+                return;
+              }
+
+                   
+           var item ;
+           var tr;
+           var td;
+           var input;
+           
+           table = document.createElement('table');
+           table.setAttribute("class","mailtable");          
+
+          for (item in mailinfo){
+  	   tr = document.createElement('tr');       
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailinfo[item]));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", item);
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+          
+          }
+
+ 	   // an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+	   content.appendChild(table);
+          
+           buildPreview(content);   
+
+           //send button
+	   input = document.createElement('input'); 
+           input.setAttribute("id", 'sendmail');
+           input.setAttribute("class", "sendbutton");
+           input.setAttribute("type", "button");
+           input.setAttribute("value", "send");        
+           content.appendChild(input);
+
+         }
+
+
+         function buildPreview(parent){
+             var div = document.createElement('div');
+         
+         
+             var img =  document.createElement('img');
+             img.src = 'interfaces/default/images/check3.gif';
+             img.id = 'urlcheck'; 
+             div.appendChild(img);
+       
+             var urls = document.createElement('span');
+             urls.id = 'urls';
+             urls.className = 'berrycheck';
+             urls.appendChild(document.createTextNode('URL only'));
+             div.appendChild(urls);
+
+            // var urlsmetadata = document.createElement('span');
+            // urlsmetadata.id = 'urlsmetadata'
+            // urlsmetadata.className = 'berryradio';
+            // urlsmetadata.appendChild(document.createTextNode('URLs and Metadata'));
+              
+            // div.appendChild(urlsmetadata);
+          
+          
+             parent.appendChild(div);
+
+                       
+             var parea  = document.createElement('textarea');
+             parea.id = 'pretextarea';                        
+
+             parent.appendChild(parea);        
+          
+         
+             populateUrlsAndMetadata(parea);	    
+               
+                       	
+         }
+
+        
+       function populateUrls(parea){
+          var urls="";
+          var doc_url = document.URL;
+          var root_url = doc_url.substring(0,doc_url.indexOf('?'));
+           
+          for (var i in docList){
+              var doc = docList[i];
+              urls +=root_url+"?a=d&amp;amp;c="+doc["collection"]+"&amp;amp;d="+doc["name"]+"\n\n";  
+                     
+          }
+
+           parea.value = urls;
+            
+         }
+
+	 function populateUrlsAndMetadata(parea){
+                       
+              var doc_url = document.URL;
+              var root_url = doc_url.substring(0,doc_url.indexOf('?'));
+              var fulltext="";
+
+              for (var i in docList){
+                   var doc = docList[i];
+                   var url =root_url+"?a=d&amp;amp;c="+doc['collection']+"&amp;amp;d="+doc['name']+"\n";  
+                    for (var metaItem in doc){
+                        var metadata = metaItem+": "+ doc[metaItem]+"\n";
+                      }
+                     fulltext +=url+metadata+"\n";
+                 
+              }
+
+               parea.value = fulltext;
+                  
+           }                                                    	    		 
+	                     
+          function sendMail(){
+              var  url = "?a=pr&amp;amp;rt=r&amp;amp;ro=1&amp;amp;s=SendMail&amp;amp;c=";
+                     var request_type = "POST";
+                     var postdata = ""; 
+ 	             var i;	     
+                     //get checked items
+                      for (i in mailinfo)
+			{ 
+                         
+                          var input = YAHOO.util.Dom.get(i);  
+                          var value = input.value;  
+			  postdata +="&amp;amp;s1."+i+"="+value;	
+			}                                   
+
+
+                       var content = YAHOO.util.Dom.get('pretextarea').value;
+                       
+                       content = content.replace(/&amp;amp;/g,'-------');  
+                       postdata +="&amp;amp;s1.content="+content;
+                                                                
+                      
+                        var callback = {
+     			   success:function(o){
+                                    var result = o.responseText;
+                                    alert(result);     
+	 			                                                                      
+                                	} ,
+     			    failure:function(o){
+                                        alert("Sending mail falied");    
+ 				     }    
+  			 }
+                                               
+ 	               
+   			YAHOO.util.Connect.asyncRequest(request_type , url , callback, postdata);         
+         }	
+
+        YAHOO.util.Event.addListener(window,'click', navigate);
+        YAHOO.util.Event.addListener(window,'load', showFullView);
+      </xsl:text>
+    </script>    
+  </xsl:template>
+
+  <xsl:template name="styleSheet">
+    <link rel="stylesheet" href="interfaces/default/style/core.css" type="text/css"/>  
+    <link rel="stylesheet" href="interfaces/default/style/berry.css" type="text/css"/>  
+  </xsl:template>
+  
+  <xsl:template name="showMailBox">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+	var show = false;	
+	var table;
+	var mailserver  = new Array();     
+	mailserver['host'] = "Mail Server: ";
+	mailserver['user'] = "User Name: ";
+	mailserver['password'] = "Password: ";
+	
+	var mailinfo = new Array();
+	mailinfo['address'] = "To: ";
+	mailinfo['cc'] = "CC: ";
+	mailinfo['bcc'] = "Bcc: ";
+	mailinfo['subject'] = "Subject: "; 
+	
+	function mailBoxUpdate(e) {
+		var target = e.target;
+		if (target.id.toLowerCase() == 'sendasemail' &amp;amp;&amp;amp; !show){
+	       	    showMailBox();
+                    show = true;
+                }
+                else{
+                    if (target.id.toLowerCase() == 'sendasemail' &amp;amp;&amp;amp; show){
+                       hideMailBox();
+                       show = false;
+                    }
+
+                     if (target.id.toLowerCase() == 'sendmail'){
+                      sendMail();
+                    }
+                }
+
+
+                	
+        }
+
+       function showMailBox(){
+           var mailbox = YAHOO.util.Dom.get('mailbox');  
+           if (table != null &amp;amp;&amp;amp; !show){
+               mailbox.appendChild(table);
+              return;
+           }
+                        
+           var item ;
+           var tr;
+           var td;
+           var input;
+           
+           table = document.createElement('table');
+           table.setAttribute("class","mailtable");          
+
+           // mail server
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailserver['host']));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'host');
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           td.appendChild(document.createTextNode(' e.g. webmail.cs.waikato.ac.nz'));
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+         
+           //user name 
+	   tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailserver['user']));
+           tr.appendChild(td);
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'user');
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+
+           //password 	
+	   tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailserver['password']));
+           tr.appendChild(td);
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'password');
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "password");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+
+           // an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+          for (item in mailinfo){
+  	   tr = document.createElement('tr');       
+           td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           td.appendChild(document.createTextNode(mailinfo[item]));
+           tr.appendChild(td);
+ 
+           td = document.createElement('td');
+           input = document.createElement('input'); 
+           input.setAttribute("id", item);
+           input.setAttribute("class", "mailinput");
+           input.setAttribute("type", "text");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+          
+          }
+
+ 	// an empty line
+           tr = document.createElement('tr');
+           td = document.createElement('td');
+           td.appendChild(document.createElement('br'));
+	   tr.appendChild(td);
+  	   table.appendChild(tr);
+
+	//send button
+	   tr = document.createElement('tr');
+       	   td = document.createElement('td');
+           td.setAttribute("class","mailitem");
+           input = document.createElement('input'); 
+           input.setAttribute("id", 'sendmail');
+           input.setAttribute("class", "sendbutton");
+           input.setAttribute("type", "button");
+           input.setAttribute("value", "send");
+           td.appendChild(input);
+           tr.appendChild(td);	        
+           table.appendChild(tr);
+
+           
+          mailbox.appendChild(table);
+         }            
+     
+
+       function hideMailBox(){
+          var mailbox = YAHOO.util.Dom.get('mailbox');	
+          while (mailbox.hasChildNodes()) {
+		mailbox.removeChild(mailbox.firstChild);
+	   }
+         }
+      
+         function sendMail(){
+              var  url = "?a=pr&amp;amp;rt=r&amp;amp;ro=1&amp;amp;s=SendMail&amp;amp;c=";
+                     var request_type = "POST";
+                     var postdata = ""; 
+ 	             var i;	     
+                     //get checked items
+                      for (i in mailinfo)
+			{ 
+                         
+                          var input = YAHOO.util.Dom.get(i);  
+                          var value = input.value;  
+			  postdata +="&amp;amp;s1."+i+"="+value;	
+			}                                   
+
+
+                       for (i in mailserver){
+                          var input = YAHOO.util.Dom.get(i);  
+                          var value = input.value; 
+                           postdata +="&amp;amp;s1."+i+"="+value;
+                        }
+
+                       var content = YAHOO.util.Dom.get('pretextarea').value;
+                       
+                       content = content.replace(/&amp;amp;/g,'-------');  
+                       postdata +="&amp;amp;s1.content="+content;
+                                                                
+                      
+                        var callback = {
+     			   success:function(o){
+                                    var response = o.responseXML;
+            	                       
+	 			         alert(response.getAttribute('status'));                                                               
+                                	} ,
+     			    failure:function(o){
+                                        alert("Sending mail falied");    
+ 				     }    
+  			 }
+                                               
+ 	               
+   			YAHOO.util.Connect.asyncRequest(request_type , url , callback, postdata);         
+                 }	
+
+              
+            YAHOO.util.Event.addListener(window,'click',mailBoxUpdate );
+
+      </xsl:text> 
+    </script>
+  </xsl:template>
+  
+  <xsl:template name="berryPageBanner">
+    <div class='banner'>
+      <div class='pageinfo'>
+	<p class='bannerlinks'>
+	  <a class='navlink' href='{$library_name}?a=p&amp;amp;sa=home' title='Library home page' >HOME</a>
+	  <a class='navlink' href='{$library_name}?a=p&amp;amp;sa=help&amp;amp;c='  title='Help pages' >HELP</a>
+	  <a class='navlink' href='{$library_name}?a=p&amp;amp;sa=pref&amp;amp;c=' title='Change your interface preferences'>PREFERENCES</a>
+	</p>      
+      </div>
+      <div class='basketimage'><p class='bannertitle'>Berry Basket</p></div>        
+    </div>
+    <div class="bannerextra"></div>
+    
+    <div >
+      <p class='navbar'><span id='fullview' class='navlink'>full view</span><span id='textview' class='navlink'>plain text version</span><span id='email' class='navlink'>email to a friend</span></p>
+    </div> 
+  </xsl:template>
+  
+  <xsl:template name="footBanner">
+    <div >
+      <p class='navbar'><span >powered by greenstone3</span></p>
+    </div> 
+  </xsl:template>
+  
+  <xsl:template name="direction">
+    <xsl:if test="/page/@lang='ar' or /page/@lang='fa' or /page/@lang='he' or /page/@lang='ur' or /page/@lang='ps' or /page/@lang='prs'">rtl</xsl:if>
+  </xsl:template>
+
+</xsl:stylesheet>  
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/berrytools.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/berrytools.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/berrytools.xsl	(revision 24065)
@@ -0,0 +1,401 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  <xsl:param name="berryBaskets"/>
+  
+  <xsl:template name="berrybasket">
+    <div id="berrybasket" class="hide" >
+      <div id="baskethandle"><span></span></div>
+      <div id ="berries"><span></span></div>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="documentBerryBasket">
+    <xsl:param name="collName"/>
+    <xsl:param name="selectedNode"/>
+    <xsl:param name="rootNode"/>
+    <xsl:param name="docType" />
+    <div id="berrybasket" class="hide" >
+      <div id="baskethandle"><span></span></div>
+      <div id ="berries" ><span></span></div>
+    </div>
+    <xsl:choose>
+      <xsl:when test="$selectedNode = $rootNode">
+	<p id="documentberries">    
+	  <img class='pick'  id="{$collName}:{$rootNode}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/><span id="{$collName}:{$rootNode}:root" class="documentberry">the whole document</span></p>       
+      </xsl:when>
+      <xsl:otherwise>
+	<p id="documentberries">    
+	  <img class='pick'  id="{$collName}:{$rootNode}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/><span id="{$collName}:{$rootNode}:root" class="documentberry">the whole document</span><img class='pick'  id="{$collName}:{$selectedNode}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/><span id="{$collName}:{$selectedNode}:section" class="documentberry">the current section</span></p>
+      </xsl:otherwise> 
+    </xsl:choose>
+  </xsl:template>
+
+  
+  <xsl:template name="loadLibrary">
+    <script type="text/javascript" src="interfaces/default/js/YAHOO.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/event.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/connection.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/dom.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/dragdrop.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/ygDDPlayer.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    <script type="text/javascript" src="interfaces/default/js/ygDDOnTop.js"><xsl:text disable-output-escaping="yes"> </xsl:text></script>
+    
+  </xsl:template>
+  
+  <xsl:template name="js-library">
+    <xsl:call-template name="loadLibrary" />	
+    <xsl:call-template name="basketCheckout" />
+  </xsl:template> 
+  
+  <!-- should be called for a documentNode -->
+  <xsl:template name="addBerry">
+    <xsl:param name="collName"/>
+    <td valign="top"><img class='pick' id="{$collName}:{@nodeID}" src="interfaces/default/images/berry3.png" alt="in basket" width="15" height="15" border="0"/></td>
+  </xsl:template>
+  
+  <xsl:template name="basketCheckout">
+    <script type="text/javascript">
+      <xsl:text disable-output-escaping="yes">
+      //used to stored the current items in berrybasket, including collection name, document id and dodument title 
+      //in the format of collection:id:[title], it is updated when the page is loaded (reloaded) or the user adds
+      // new items in the berry basket (see ygDDplayer.js). It is used to show the contents of the berry basket. 
+     var berryList =  new Array();
+     var show = false;    
+ 
+     // the default width and height of the berry basket
+     var oldHeight=90;
+     var oldWidth=140;
+     var oldBg;
+
+     var dd = new ygDDOnTop('berrybasket');
+     dd.setHandleElId('baskethandle');
+
+     var checkout = function(){
+       var request_type = "GET";
+       var url = "?a=pr&amp;amp;rt=r&amp;amp;ro=1&amp;amp;s=ItemNum&amp;amp;o=XML&amp;amp;c="; 
+ 
+         var responseSuccess = function(o){
+	     var response = o.responseXML;
+             var size = response.getElementsByTagName('size').item(0).getAttribute('value');       
+           
+             var items = response.getElementsByTagName('item');
+             
+             for (var i=0;i &lt; items.length ; i++ ){
+ 
+                 // remove berries images from if the berry basket has already contains this item  
+                
+                 var itemID = items[i].getAttribute('collection')+":"+items[i].getAttribute('name');
+                 var item =  YAHOO.util.Dom.get(itemID);
+                 if (item != null){
+                    var parent = item.parentNode;
+                    parent.removeChild(item);
+                   
+                   if (parent !=null &amp;amp;&amp;amp; parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(itemID+":root");
+                         var section = YAHOO.util.Dom.get(itemID+":section");
+                         if(root!=null &amp;amp;&amp;amp; root.id.indexOf(itemID) !=-1){
+                             parent.removeChild(root);
+                          }
+     
+	                  if(section!=null &amp;amp;&amp;amp; section.id.indexOf(itemID) !=-1){
+                             parent.removeChild(section);
+        	          }
+                      
+                          
+                     }
+                 }
+                                
+                  berryList[berryList.length] = items[i];                   	
+	      }
+
+               //add berryimage into the berry basket
+                updateBerryImages();         
+             
+                // set berries images visible
+             // they are set to be invisible to prevent flickering when first loaded (see berry.css) 
+            
+             var berries =document.getElementsByTagName('img');
+	     var berrybasket = new YAHOO.util.DDTarget('berrybasket','basket');
+           
+             for (var j=0; j &lt; berries.length; j++){
+          
+                  var berry = berries[j]; 
+                   var parent = berry.parentNode;
+                   
+                   
+                   if (parent !=null &amp;amp;&amp;amp; parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(berry.id+":root");
+                         var section = YAHOO.util.Dom.get(berry.id+":section");
+                         if(root!=null &amp;amp;&amp;amp; root.id.indexOf(berry.id) !=-1){
+                             root.style.visibility ="visible" ;
+                          }
+     
+	                  if(section!=null &amp;amp;&amp;amp; section.id.indexOf(berry.id) !=-1){
+                             section.style.visibility ="visible" ;
+        	          }
+                      
+                          
+                     }  
+
+               if (berry.className  &amp;amp;&amp;amp;  berry.className  == 'pick')
+                  { 
+                    berry.style.visibility = "visible";
+                    new ygDDPlayer(berry.id,'basket',berryList); 
+                  }   
+     	      
+             }
+           
+           }
+
+         var responseFailure = function(o){
+             
+          }  
+
+        var callback = {
+        success: responseSuccess,
+        failure: responseFailure 
+      }
+
+      YAHOO.util.Connect.asyncRequest(request_type , url , callback);
+   }
+
+    function updateBerryImages(){
+     
+      for (var i =0;i &lt; berryList.length &amp;amp;&amp;amp; i &lt;12 ; i++ ){
+               var berries = YAHOO.util.Dom.get('berries');
+               var img = document.createElement('img');
+               img.src = 'interfaces/default/images/berry3.png';
+               img.height = 15;
+               img.width = 15;
+               img.border = 0;              
+               berries.appendChild(img);
+          }
+
+    }
+
+    function basketUpdate(e) {
+		var target = e.target;
+               
+		if ((target.id.toLowerCase() == 'berrybasket' || target.id.toLowerCase() == 'berries')  &amp;amp;&amp;amp; !show){
+	       	    showBasket();
+                    show = true;
+                }
+                else{
+                    if (target.id.toLowerCase() == 'hideview' &amp;amp;&amp;amp; show){
+                       hideBasket();
+                       show = false;
+                    }
+                }
+           
+            if (target.className == 'pick'){
+              addBerry(target);
+            }
+            
+        }
+
+     function showBasket() {
+        var berryBasket  = YAHOO.util.Dom.get('berrybasket');  
+        var basketHandle = YAHOO.util.Dom.get('baskethandle'); 
+        var berries = YAHOO.util.Dom.get('berries');   
+        var div = document.createElement('div');
+        var list = document.createElement('ol');
+        var width = 500;
+        var height = 40;
+        var i=0;
+ 
+        list.id = 'doclist';
+      
+       //remove berryImages in the berry basket 
+       while (berries.hasChildNodes()) {
+       	  berries.removeChild(berries.firstChild);
+	}
+
+       while (basketHandle.hasChildNodes()) {
+       	  basketHandle.removeChild(basketHandle.firstChild);
+	}
+
+       for (i in berryList){
+            var berryItem = berryList[i];
+            var berryElement = document.createElement('li');
+            var title = berryItem.getAttribute('title');
+            var root_title = berryItem.getAttribute('root_title'); 
+            var id = berryItem.getAttribute('collection')+":"+berryItem.getAttribute('name'); 
+
+            if (root_title != ""){
+              root_title +=":";
+            }
+	    
+            title = root_title+title;	
+            if (title.length > 50){
+               title = title.substring(0,20)+" ... "+title.substr(title.length-35,35);
+             }
+  
+            berryElement.appendChild(document.createTextNode(title));
+            berryElement.setAttribute("class","berryitem");
+            list.appendChild(berryElement);
+            height +=18;
+          } 
+      	   
+        oldHeight = berryBasket.style.height;
+        oldWidth = berryBasket.style.width;
+        oldBg = berryBasket.style.background; 
+        berryBasket.style.height = height;
+        berryBasket.style.width = width;
+        berryBasket.style.background ='url("interfaces/default/images/kete2.png") 0 0 repeat';
+        berryBasket.style.cursor = "default";         
+        berryBasket.className = "show";
+        div.appendChild(list); 	
+        berries.appendChild(div);  
+        berries.style.height = height - 40;
+
+        var links = document.createElement('div');
+        var hideView = document.createElement('a');
+        var fullView = document.createElement('a');
+        links.appendChild(hideView);
+        links.appendChild(fullView);
+        basketHandle.appendChild(links);
+        hideView.appendChild(document.createTextNode("Hide"));
+        fullView.appendChild(document.createTextNode("Full View"));
+        hideView.setAttribute("id","hideview");
+        fullView.setAttribute("href","?a=g&amp;amp;sa=berry&amp;amp;c=&amp;amp;s=DisplayList&amp;amp;rt=r");
+        fullView.setAttribute("class","fullview");
+
+        }
+
+      function hideBasket() {
+          var i = 0;
+          var berryBasket  = YAHOO.util.Dom.get('berrybasket');  
+          var basketHandle  = YAHOO.util.Dom.get('baskethandle'); 
+          var berries = YAHOO.util.Dom.get('berries'); 
+          berryBasket.style.height = oldHeight;
+          berryBasket.style.width = oldWidth;
+          berryBasket.style.background = oldBg;
+          berryBasket.style.cursor = "pointer";
+          berryBasket.className = "hide";
+
+          while (berries.hasChildNodes()) {
+		berries.removeChild(berries.firstChild);
+	}
+         
+        while (basketHandle.hasChildNodes()) {
+		basketHandle.removeChild(basketHandle.firstChild);
+	}
+         
+        updateBerryImages();
+      }    
+
+
+     function addBerry(el){
+      var  addurl = "?a=pr&amp;amp;rt=r&amp;amp;ro=1&amp;amp;s=AddItem&amp;amp;c=&amp;amp;s1.id=2&amp;amp;o=XML&amp;amp;s1.item=" + el.id;	   
+      var addSuccess = function(o){ 
+ 		 var result = o.responseXML;
+                 var items = result.getElementsByTagName('item');
+                 if (items.length &gt; 0){
+                    var item = items[0];
+                    var berrybasket = YAHOO.util.Dom.get('berrybasket');
+        	    var berries = YAHOO.util.Dom.get('berries');
+                    berryList[berryList.length]= item;   
+                    var parent =el.parentNode;
+                    if (parent == null) return;     
+                    parent.removeChild(el);
+               
+                     var itemID = item.getAttribute('collection')+":"+item.getAttribute('name'); 
+                    if (parent !=null  &amp;amp;&amp;amp; parent.id == "documentberries"){
+                         var root = YAHOO.util.Dom.get(itemID+":root");
+                         var section = YAHOO.util.Dom.get(itemID+":section");
+                         if(root!=null  &amp;amp;&amp;amp; root.id.indexOf(itemID) !=-1){
+                             parent.removeChild(root);
+                          }
+     
+	                  if(section!=null  &amp;amp;&amp;amp; section.id.indexOf(itemID) !=-1){
+                             parent.removeChild(section);
+        	          }                                                
+                     }
+
+                    if (!YAHOO.util.Dom.get('hideview') &amp;amp;&amp;amp;  berryList.length &lt; 13){
+                      while (berries.hasChildNodes()) {
+       	                   berries.removeChild(berries.firstChild);
+	                }
+                        
+                     for (var i =0; i &lt; berryList.length; i++ ){
+                             var img = document.createElement('img');
+                              img.src = 'interfaces/default/images/berry3.png';
+                              img.height = 15;
+                              img.width = 15;
+                              img.border = 0;              
+                              berries.appendChild(img);
+                       }
+      	            
+                                                     
+	          }
+                 else{
+           
+                  if (YAHOO.util.Dom.get('hideview')){
+                        var berryBasket  = YAHOO.util.Dom.get('berrybasket');
+                        var berries  = YAHOO.util.Dom.get('berries');
+                        var doclist = YAHOO.util.Dom.get('doclist'); 
+                        var tid = el.id;                                  
+                        var berryItem; 
+                        var berryElement = document.createElement('li');
+                         for (var i in berryList){
+                             berryItem = berryList[i];
+                             var id = berryItem.getAttribute('collection')+":"+berryItem.getAttribute('name');
+                             if (id == tid){
+                               var title = berryItem.getAttribute('title');
+                               var root_title = berryItem.getAttribute('root_title');  
+                                if (root_title != ""){
+                                      root_title +=":";
+                                     }
+	    
+                                title = root_title+title;	
+                                if (title.length > 50){
+                                   title = title.substring(0,20)+" ... "+title.substr(title.length-35,35);
+                                }
+            
+                               berryElement.appendChild(document.createTextNode(title));
+                               berryElement.setAttribute("class","berryitem");
+                               doclist.appendChild(berryElement);
+                               var heightStr =  berryBasket.style.height+"";
+                               var height =parseInt(heightStr.substring(0,heightStr.length-2)) +18;                             
+                               berryBasket.style.height = height;
+                               berries.style.height = height;
+                               break;
+                            }
+                         }
+                             
+                      }
+                    
+                 }
+               }
+                                       
+             }
+
+           var addFailure = function(o){ }
+
+           var addcallback = {
+        	   success:addSuccess,
+     	           failure:addFailure
+                }
+
+            YAHOO.util.Connect.asyncRequest(request_type , addurl , addcallback);    
+
+         }
+
+  
+      
+     YAHOO.util.Event.addListener(window,'load', checkout); 
+     YAHOO.util.Event.addListener(window,'click', basketUpdate); 
+      </xsl:text>
+    </script>
+  </xsl:template>
+
+  <xsl:template name="berryStyleSheet">
+    <link rel="stylesheet" href="interfaces/default/style/berry.css" type="text/css"/>  
+  </xsl:template>
+  
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/classifier.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/classifier.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/classifier.xsl	(revision 24065)
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="classifiertools.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/> 
+
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+	<xsl:call-template name="pageTitle"/>
+      </body>
+    </html>
+  </xsl:template>
+  
+  <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+
+  <xsl:template name="pageTitle">
+    <span class="getTextFor null document.title.gsdl">&amp;amp;nbsp;</span>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle">
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="berryStyleSheet"/>  
+      <xsl:call-template name="js-library"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:variable name="serviceName"><xsl:value-of select="service/@name"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+  
+    <div id="content" class="moz-output-escape">
+      <xsl:apply-templates select="service/classifierList">
+        <xsl:with-param name="collName" select="$collName"/>
+        <xsl:with-param name="serviceName" select="$serviceName"/>
+      </xsl:apply-templates>
+      
+      <xsl:if test="$berrybasketswitch = 'on'">
+	<xsl:call-template name="berrybasket" />
+      </xsl:if>  
+      <xsl:apply-templates select="classifier">
+	<xsl:with-param name="collName" select="$collName"/>
+	<xsl:with-param name="serviceName" select="$serviceName"/>
+      </xsl:apply-templates>
+    </div>
+  </xsl:template>
+  
+  <xsl:template match="classifierList">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:variable name="selected" select="/page/pageResponse/classifier/@name"/>
+    <ul id="classifierlist">
+      <xsl:for-each select="classifier">
+	<xsl:choose>
+	  <xsl:when test="@name=$selected">
+	    <li id="activeclassifier"><xsl:value-of select="displayItem[@name='name']"/></li>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <li><a href="{$library_name}?a=b&amp;amp;rt=r&amp;amp;s={$serviceName}&amp;amp;c={$collName}&amp;amp;cl={@name}"><xsl:value-of select="displayItem[@name='name']"/></a></li></xsl:otherwise></xsl:choose>
+	
+      </xsl:for-each>
+    </ul>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+
+
+
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/classifiertools.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/classifiertools.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/classifiertools.xsl	(revision 24065)
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <xsl:template match="classifier">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <div id="classifiers">
+      <xsl:variable name="cl_name"><xsl:value-of select="@name"/></xsl:variable>
+      <xsl:choose>
+	<xsl:when test="/page/pageResponse/service/classifierList/classifier[@name=$cl_name]/@horizontalAtTop">
+	  <xsl:apply-templates select="." mode="horizontal-at-top">
+	    <xsl:with-param name="collName" select="$collName"/>
+	    <xsl:with-param name="serviceName" select="$serviceName"/>
+	  </xsl:apply-templates>
+	</xsl:when>
+	<xsl:otherwise>
+	  <xsl:apply-templates select="." mode="default">
+	    <xsl:with-param name="collName" select="$collName"/>
+	    <xsl:with-param name="serviceName" select="$serviceName"/>
+	  </xsl:apply-templates>
+	</xsl:otherwise>
+      </xsl:choose>
+    </div>
+  </xsl:template>
+  
+
+  <xsl:template match="classifier" mode="horizontal-at-top">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:choose>
+      <xsl:when test="classifierNode">
+	<ul id="classifiernodelist-horizontal">
+	  <xsl:for-each select='classifierNode'>
+	    <xsl:apply-templates select='.' mode="horizontal"><xsl:with-param name='collName' select='$collName'/><xsl:with-param name='serviceName' select='$serviceName'/></xsl:apply-templates>
+	  </xsl:for-each>
+	</ul>
+	<ul id="childrenlist">
+	  <li>
+            <table><tr>
+		<xsl:for-each select='classifierNode'>
+		  <xsl:apply-templates select='.' mode='process-all-children'><xsl:with-param name='collName' select='$collName'/><xsl:with-param name='serviceName' select='$serviceName'/></xsl:apply-templates>
+		</xsl:for-each>
+	      </tr></table>
+	  </li>
+	</ul>
+      </xsl:when>
+      <xsl:otherwise>
+	<!-- there were no classifier nodes -->
+	<ul id="childrenlist">
+          <xsl:for-each select='documentNode'>
+	    <li><table><tr><xsl:call-template name="documentNodeWrapper">
+		    <xsl:with-param name='collName' select='$collName'/>
+		    <xsl:with-param name='serviceName' select='$serviceName'/>
+		  </xsl:call-template></tr></table></li>
+	  </xsl:for-each>
+	</ul>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="classifier" mode="default"> <!-- the default -->
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <ul id="classifiernodelist">
+      <xsl:call-template name="processNodeChildren">
+	<xsl:with-param name='collName' select='$collName'/>
+	<xsl:with-param name='serviceName' select='$serviceName'/>
+      </xsl:call-template>
+    </ul>
+  </xsl:template>
+  
+  <!-- this is a wrapper node, which the interface can use to add stuff into the query results that isn't part of and doesn't depend on the documentNode template which may come from the collection -->
+  <xsl:template name="documentNodeWrapper">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/> 
+    <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="addBerry">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template> 
+    </xsl:if>
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="serviceName" select="$serviceName"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <a href="{$library_name}?a=d&amp;c={$collName}&amp;d={@nodeID}&amp;dt={@docType}&amp;p.a=b&amp;p.s={$serviceName}"><xsl:apply-templates select="." mode="displayNodeIcon"/></a><xsl:text>Test</xsl:text><xsl:value-of disable-output-escaping="yes"  select="metadataList/metadata[@name='Title']"/>
+  </xsl:template>
+
+  
+  
+  <!-- icon + title template-->
+  <xsl:template match="classifierNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <a><xsl:attribute name='href'><xsl:value-of select='$library_name'/>?a=b&amp;rt=r&amp;s=<xsl:value-of select='$serviceName'/>&amp;c=<xsl:value-of select='$collName'/>&amp;cl=<xsl:value-of select='@nodeID'/><xsl:if test="classifierNode|documentNode">.pr</xsl:if></xsl:attribute><xsl:call-template name="bookshelfimg"/></a><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/>
+
+  </xsl:template>
+  
+  <!-- the title is a link: an alternative template -->
+  <xsl:template match="classifierNode" mode="horizontal">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <li><xsl:choose>
+	<xsl:when test="classifierNode|documentNode"><b><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/><xsl:text> </xsl:text></b></xsl:when>
+	<xsl:otherwise>
+	  <a><xsl:attribute name='href'><xsl:value-of select='$library_name'/>?a=b&amp;rt=r&amp;s=<xsl:value-of select='$serviceName'/>&amp;c=<xsl:value-of select='$collName'/>&amp;cl=<xsl:value-of select='@nodeID'/></xsl:attribute><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></a><xsl:text> </xsl:text></xsl:otherwise>
+      </xsl:choose>
+    </li>
+  </xsl:template>
+  
+
+  <!-- processing for the recursive bit -->
+  <xsl:template match="classifierNode" mode="process-all-children">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:call-template name="processNodeChildren">
+      <xsl:with-param name='collName' select='$collName'/>
+      <xsl:with-param name='serviceName' select='$serviceName'/>
+    </xsl:call-template>
+  </xsl:template>
+  
+  <xsl:template name="processNodeChildren">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:for-each select='classifierNode|documentNode'>
+      <xsl:choose><xsl:when test="name()='documentNode'">
+	  <li><table><tr>
+		<xsl:call-template name="documentNodeWrapper">
+		  <xsl:with-param name='collName' select='$collName'/>
+		  <xsl:with-param name='serviceName' select='$serviceName'/>
+		</xsl:call-template>
+	      </tr></table>
+	  </li>
+	</xsl:when>
+	<xsl:otherwise>
+	  <li><table><tr>
+		<xsl:apply-templates select='.'>
+		  <xsl:with-param name='collName' select='$collName'/>
+		  <xsl:with-param name='serviceName' select='$serviceName'/>
+		</xsl:apply-templates>
+	      </tr></table>
+	  </li>
+	  <xsl:if test="child::classifierNode or child::documentNode">
+	    <!--recurse into the children-->
+	    <li><ul class="childrenlist">
+		<xsl:apply-templates select='.' mode='process-all-children'>
+		  <xsl:with-param name='collName' select='$collName'/>
+		  <xsl:with-param name='serviceName' select='$serviceName'/>
+		</xsl:apply-templates>
+	      </ul>
+	    </li>
+	  </xsl:if>
+	</xsl:otherwise>
+      </xsl:choose>
+    </xsl:for-each>
+  </xsl:template>
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/config_format.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/config_format.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/config_format.xsl	(revision 24065)
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:xslt="output.xsl"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+  extension-element-prefixes="java">
+  
+  <xsl:output method="xml"/>
+  <xsl:namespace-alias
+    stylesheet-prefix="xslt" result-prefix="xsl"/>
+
+  <xsl:template match="format">
+    <format>
+      <xsl:apply-templates/>
+    </format>
+  </xsl:template>
+  
+  <xsl:template match="gsf:template">
+    <xslt:template>
+      <xsl:copy-of select="@*"/>
+      <xsl:attribute name="priority">2</xsl:attribute> 
+      <xsl:if test=".//gsf:link">
+	<xslt:param name="serviceName"/>
+	<xslt:param name="collName"/>
+      </xsl:if>
+      <xsl:apply-templates/>
+    </xslt:template>
+  </xsl:template>
+  
+  <xsl:template match="gsf:link">
+    <xsl:choose>
+      <xsl:when test="@type='classifier'">
+	<a><xslt:attribute name='href'><xslt:value-of select='$library_name'/>?a=b&amp;rt=r&amp;s=<xslt:value-of select='$serviceName'/>&amp;c=<xslt:value-of select='$collName'/>&amp;cl=<xslt:value-of select='@nodeID'/><xslt:if test="classifierNode|documentNode">.pr</xslt:if><xslt:if test="parent::node()[@orientation='horizontal']">&amp;sib=1</xslt:if></xslt:attribute>
+	  <xsl:apply-templates/>
+	</a>
+      </xsl:when>
+      <xsl:otherwise> <!-- a document link -->
+	<xslt:variable name="bookswitch"><xslt:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xslt:variable>
+	<xslt:choose>
+	  <xslt:when test="$bookswitch = 'on' or $bookswitch = 'flashxml'">
+	    <a><xslt:attribute name="href"><xslt:value-of select='$library_name'/>?a=d&amp;ed=1&amp;book=on&amp;c=<xslt:value-of select='$collName'/>&amp;d=<xslt:value-of select='@nodeID'/>&amp;dt=<xslt:value-of select='@docType'/><xslt:if test="@nodeType='leaf'">&amp;sib=1</xslt:if>&amp;p.a=<xslt:value-of select="/page/pageRequest/@action"/>&amp;p.sa=<xsl:value-of select="/page/pageRequest/@subaction"/>&amp;p.s=<xslt:value-of select="$serviceName"/></xslt:attribute><xsl:apply-templates/></a>
+	  </xslt:when>
+	  <xslt:otherwise>
+	    <a><xslt:attribute name="href"><xslt:value-of select='$library_name'/>?a=d&amp;book=off&amp;c=<xslt:value-of select='$collName'/>&amp;d=<xslt:value-of select='@nodeID'/>&amp;dt=<xslt:value-of select='@docType'/><xslt:if test="@nodeType='leaf'">&amp;sib=1</xslt:if>&amp;p.a=<xslt:value-of select="/page/pageRequest/@action"/>&amp;p.sa=<xsl:value-of select="/page/pageRequest/@subaction"/>&amp;p.s=<xslt:value-of select="$serviceName"/></xslt:attribute><xsl:apply-templates/></a>
+	  </xslt:otherwise>
+	</xslt:choose>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template match="gsf:icon">
+    <xsl:choose>
+      <xsl:when test="@type='classifier'">
+	<xslt:call-template name="bookshelfimg"/>
+      </xsl:when>
+      <xsl:otherwise>
+	<xslt:apply-templates select="." mode="displayNodeIcon"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <xsl:template match="gsf:metadata[@format]">
+    <xslt:value-of disable-output-escaping="yes"><xsl:attribute name="select">java:org.greenstone.gsdl3.util.XSLTUtil.<xsl:value-of select="@format"/>(metadataList/metadata[@name='<xsl:apply-templates select="." mode="get-metadata-name"/>'], /page/@lang )</xsl:attribute></xslt:value-of>
+  </xsl:template>
+
+  <xsl:template match="gsf:metadata">
+    <xslt:value-of disable-output-escaping="yes"><xsl:attribute name="select">metadataList/metadata[@name='<xsl:apply-templates select="." mode="get-metadata-name"/>']</xsl:attribute></xslt:value-of>
+  </xsl:template>
+
+  <xsl:template match="gsf:metadata" mode="get-metadata-name">
+    <xsl:if test="@multiple='true'">all_</xsl:if><xsl:if test='@select'><xsl:value-of select='@select'/>_</xsl:if><xsl:if test="@separator">*<xsl:value-of select='@separator'/>*_</xsl:if><xsl:value-of select="@name"/>
+  </xsl:template>
+  
+  <xsl:template match="gsf:metadata-old">
+    <xslt:value-of disable-output-escaping="yes"><xsl:attribute name="select">metadataList/metadata[@name="<xsl:choose><xsl:when test="@select='parent'">parent_</xsl:when><xsl:when test="@select='root'">root_</xsl:when><xsl:when test="@select='ancestors'">ancestors'<xsl:value-of select='@separator'/>'_</xsl:when><xsl:when test="@select='siblings'">siblings_'<xsl:value-of select='@separator'/>'_</xsl:when></xsl:choose><xsl:value-of select="@name"/>"]</xsl:attribute></xslt:value-of>
+  </xsl:template>
+  
+  <xsl:template match="gsf:text">
+    <xslt:apply-templates select="nodeContent"/>
+  </xsl:template>
+  
+  <xsl:template match="gsf:choose-metadata">
+    <xslt:choose>
+      <xsl:for-each select="gsf:metadata">
+	<xslt:when><xsl:attribute name="test">metadataList/metadata[@name='<xsl:apply-templates select="." mode="get-metadata-name"/>']</xsl:attribute>
+	  <xsl:apply-templates select="."/>
+	</xslt:when>
+      </xsl:for-each>
+      <xsl:if test="gsf:default">
+	<xslt:otherwise><xsl:apply-templates select="gsf:default"/></xslt:otherwise>
+      </xsl:if>
+    </xslt:choose>
+  </xsl:template>
+  
+  <xsl:template match="gsf:switch">
+    <xsl:variable name="meta-name"><xsl:apply-templates select="gsf:metadata" mode="get-metadata-name"/></xsl:variable>
+    <xslt:variable name="meta"><xsl:choose><xsl:when test="@preprocess"><xslt:value-of select="util:{@preprocess}(metadataList/metadata[@name='{$meta-name}'])"/></xsl:when><xsl:otherwise><xslt:value-of select="metadataList/metadata[@name='{$meta-name}']"/></xsl:otherwise></xsl:choose></xslt:variable>
+    <xslt:choose>
+      <xsl:for-each select="gsf:when">
+	<xslt:when test="util:{@test}($meta, '{@test-value}')">
+	  <xsl:apply-templates/>
+	</xslt:when>
+      </xsl:for-each>
+      <xsl:if test="gsf:otherwise">
+	<xslt:otherwise>
+	  <xsl:apply-templates select="gsf:otherwise/node()"/>
+	</xslt:otherwise>
+      </xsl:if>
+    </xslt:choose>
+  </xsl:template>
+  
+  <xsl:template match="*">
+    <xsl:copy>
+      <xsl:copy-of select="@*"/>
+      <xsl:apply-templates/>
+    </xsl:copy>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/document.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/document.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/document.xsl	(revision 24065)
@@ -0,0 +1,648 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+	xmlns:java="http://xml.apache.org/xslt/java"
+	xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+	extension-element-prefixes="java"
+	exclude-result-prefixes="java gsf">
+	
+	<!-- style includes global params interface_name, library_name -->
+	<xsl:include href="style.xsl"/>
+	<xsl:include href="service-params.xsl"/>
+	<xsl:include href="berrytools.xsl"/>
+
+	<xsl:output method="html"/>
+  
+	<!-- the main page layout template is here -->
+	<xsl:template match="page">
+		<xsl:variable name="bookswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xsl:variable>
+		<xsl:variable name="a"><xsl:value-of select="/page/pageRequest/paramList/param[@name='a']/@value"/></xsl:variable>
+
+		<xsl:choose> 
+			<xsl:when test="$bookswitch = 'flashxml' and $a = 'd'">
+				<html>
+					<xsl:call-template name="response" />
+				</html>
+			</xsl:when>
+			<xsl:otherwise>    
+				<html>
+					<head>
+						<title>
+							<!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+							<xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+						</title>
+						<xsl:call-template name="globalStyle"/>
+						<xsl:call-template name="pageStyle"/>
+					</head>
+					<body>
+						<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+						<div id="page-wrapper">
+							<xsl:call-template name="response" />
+							<xsl:call-template name="greenstoneFooter"/>
+						</div>
+					</body>
+				</html>
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+  
+  
+	<xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+	<xsl:variable name="bookswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xsl:variable>
+  
+	<xsl:template name="pageTitle">
+		<xsl:variable name="docID" select="/page/pageResponse/document/@selectedNode"/>
+		<xsl:for-each select="/page/pageResponse/document/descendant::documentNode[@nodeID=$docID]/ancestor-or-self::documentNode"><xsl:if test='position()!=1'>::</xsl:if><xsl:value-of select="metadataList/metadata[@name='Title']"/></xsl:for-each>
+	</xsl:template>
+
+	<!-- this is hard coded for GATE, should somehow do it dynamically-->
+	<xsl:template name="pageStyle">
+		<style type="text/css">
+			<xsl:text disable-output-escaping="yes">
+				span.Location {  display:inline; color : red }
+				span.Person {  display:inline; color : green }
+				span.Organization {  display:inline; color : yellow }
+				span.Date {  display:inline; color : blue }
+				span.query_term {display: inline; background-color : yellow }
+			</xsl:text>
+		</style>
+
+		<xsl:if test="$berrybasketswitch = 'on'">
+			<xsl:call-template name="berryStyleSheet"/>  
+			<xsl:call-template name="js-library"/>
+		</xsl:if>
+	</xsl:template>
+  
+	<xsl:template match="pageResponse">
+		<xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+		<xsl:choose>
+			<xsl:when test="$bookswitch = 'on' or $bookswitch = 'off'">
+				<xsl:call-template name="standardPageBanner">
+					<xsl:with-param name="collName" select="$collName"/>
+				</xsl:call-template>
+				<xsl:call-template name="navigationBar">
+					<xsl:with-param name="collName" select="$collName"/>
+				</xsl:call-template>
+	
+				<xsl:if test="$berrybasketswitch = 'on'">
+					<xsl:call-template name="documentBerryBasket">
+						<xsl:with-param name="collName" select="$collName"/>
+						<xsl:with-param name="selectedNode" select="/page/pageResponse/document/@selectedNode"/>
+						<xsl:with-param name="rootNode" select="/page/pageResponse/document/documentNode[@nodeType='root']/@nodeID"/>
+						<xsl:with-param name="docType" select="/page/pageResponse/document/@docType"/>
+					</xsl:call-template>
+				</xsl:if>
+			</xsl:when>
+		</xsl:choose>	
+
+		<!-- display the document -->
+		<xsl:if test="$bookswitch != 'flashxml'">
+			<xsl:text disable-output-escaping="yes">&lt;div id="content"&gt;</xsl:text>
+		</xsl:if>
+		<xsl:apply-templates select="document">
+			<xsl:with-param name="collName" select="$collName"/>
+		</xsl:apply-templates>
+		<xsl:if test="$bookswitch != 'flashxml'">
+			<xsl:text disable-output-escaping="yes">&lt;/div&gt;</xsl:text>
+		</xsl:if>
+	</xsl:template>
+  
+	<xsl:template match="document">
+		<xsl:param name="collName"/>
+		<xsl:variable name="external"><xsl:value-of select="/page/pageResponse/document/@external"/></xsl:variable>
+		<xsl:choose>
+			<xsl:when test="$external != ''">
+				<xsl:call-template name="externalPage">
+					<xsl:with-param name="external" select="$external"/>
+				</xsl:call-template>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:choose>
+					<xsl:when test="$bookswitch = 'flashxml'">
+						<xsl:call-template name="xmldocumentContentPeeling">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>
+					</xsl:when>	
+					<xsl:when test="$bookswitch = 'on'">
+						<xsl:call-template name="documentHeading">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>
+						<div id="bookdiv"></div>
+						<script type="text/javascript">
+							<xsl:text disable-output-escaping="yes">
+								var doc_url = document.URL; 
+								doc_url = doc_url.replace(/(&amp;amp;|\?)book=[a-z]+/gi,'');
+								doc_url += '&amp;amp;book=flashxml';
+
+								var flash_plug_html = ""
+								flash_plug_html += '&amp;lt;OBJECT align="middle" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" \n';
+								flash_plug_html += '  codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" \n';
+								flash_plug_html += '  height="100%" id="Book" swLiveConnect="true" \n';
+								flash_plug_html += '  width="100%"&amp;gt;\n';
+								flash_plug_html += '    &amp;lt;PARAM name="allowScriptAccess" value="always" /&amp;gt;\n';
+								flash_plug_html += '    &amp;lt;PARAM name="movie" value="Book.swf';
+								flash_plug_html += '?src_image=' + escape(img_cover);
+								flash_plug_html += '&amp;amp;doc_url=' + escape(doc_url)
+								flash_plug_html += '" /&amp;gt;\n';
+								flash_plug_html += '    &amp;lt;PARAM name="quality" value="high" /&amp;gt;\n';
+								flash_plug_html += '    &amp;lt;PARAM name="bgcolor" value="#FFFFFF" /&amp;gt;\n';
+								flash_plug_html += '    &amp;lt;EMBED align="middle" \n';
+								flash_plug_html += '      allowScriptAccess="always" swLiveConnect="true" \n';
+								flash_plug_html += '      bgcolor="#FFFFFF" height="100%" name="Book" \n';
+								flash_plug_html += '      pluginspage="http://www.macromedia.com/go/getflashplayer" \n';
+								flash_plug_html += '      quality="high" \n';
+								flash_plug_html += '      src="Book.swf';
+								flash_plug_html += '?src_image=' + escape(img_cover);
+								flash_plug_html += '&amp;amp;doc_url=' + escape(doc_url);
+								flash_plug_html += '"\n'; 
+								flash_plug_html += '      type="application/x-shockwave-flash" width="100%" /&amp;gt;\n';
+								flash_plug_html += '&amp;lt;/OBJECT&amp;gt;\n';
+								var flash_div = document.getElementById("bookdiv");
+								flash_div.innerHTML = flash_plug_html;
+							</xsl:text>
+						</script>
+					</xsl:when> 
+					<xsl:otherwise>
+						<xsl:call-template name="documentHeading">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>
+						<xsl:call-template name="documentArrows">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>         
+						<xsl:call-template name="documentContent">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>
+						<xsl:call-template name="documentArrows">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>   
+					</xsl:otherwise>
+				</xsl:choose>
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+
+	<xsl:template name="documentHeading">
+		<xsl:param name="collName"/>
+		<xsl:variable name="doCoverImage" select="/page/pageResponse/format/gsf:option[@name='coverImages']/@value"/>
+		<xsl:variable name="doTOC" select="/page/pageResponse/format/gsf:option[@name='documentTOC']/@value"/>
+		<xsl:variable name="p.a" select="/page/pageRequest/paramList/param[@name='p.a']/@value"/>
+		<xsl:variable name="p.sa" select="/page/pageRequest/paramList/param[@name='p.sa']/@value"/>
+		<xsl:variable name="p.s" select="/page/pageRequest/paramList/param[@name='p.s']/@value"/>
+		<xsl:variable name="p.c"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='p.c']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.c']/@value"/></xsl:when><xsl:otherwise><xsl:value-of select="$collName"/></xsl:otherwise></xsl:choose></xsl:variable>
+		<div id="documentheading">
+			<a href="{$library_name}?a={$p.a}&amp;amp;sa={$p.sa}&amp;amp;s={$p.s}&amp;amp;c={$p.c}&amp;amp;rt=rd">
+				<xsl:call-template name="openbookimg">
+					<xsl:with-param name="title"><xsl:value-of select="'close_book'"/></xsl:with-param>
+				</xsl:call-template>
+			</a>
+			<xsl:choose>
+				<xsl:when test="@docType='simple'">
+					<xsl:value-of select="metadataList/metadata[@name='Title']" disable-output-escaping="yes"/>
+				</xsl:when>
+				<xsl:otherwise>
+					<xsl:value-of select="documentNode/metadataList/metadata[@name='Title']" disable-output-escaping="yes"/>
+				</xsl:otherwise>
+			</xsl:choose>
+		</div>
+    
+		<div id="docheadwrapper">
+			<div id="documentinfo">
+	
+				<xsl:choose>
+					<xsl:when test="$bookswitch = 'on'">
+						<xsl:if test="string($doCoverImage) != 'false' and (@docType='paged' or @docType='hierarchy')">
+							<div id="headingimage">
+								<xsl:call-template name="coverImage"/> 
+							</div>
+						</xsl:if>
+					</xsl:when>
+					<xsl:otherwise>
+						<xsl:if test="string($doCoverImage) != 'false' and (@docType='paged' or @docType='hierarchy')">
+							<div id="headingimage">
+								<xsl:call-template name="coverImage"/> 
+							</div>
+						</xsl:if>
+	    
+						<ul id="docbuttons" >
+							<xsl:call-template name="documentButtons">
+								<xsl:with-param name="collName" select="$collName"/>
+							</xsl:call-template>
+						</ul>
+					</xsl:otherwise>
+				</xsl:choose>     
+			</div>
+			<!--<div><xsl:call-template name="enrichServices">
+				<xsl:with-param name="collName" select="$collName"/>
+				</xsl:call-template></div>-->
+			<xsl:if test="$bookswitch = 'off'">
+				<xsl:if test="string($doTOC) != 'false'">
+					<div id="toc">
+						<xsl:call-template name="TOC">
+							<xsl:with-param name="collName" select="$collName"/>
+						</xsl:call-template>
+					</div>
+				</xsl:if>
+			</xsl:if>  
+		</div>
+	</xsl:template>
+
+	<xsl:template name="coverImage">
+		<xsl:choose>
+			<xsl:when test="$bookswitch = 'on'">
+				<script type="text/javascript">
+					<xsl:text disable-output-escaping="yes">var img_cover = '</xsl:text><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>/index/assoc/<xsl:value-of select="metadataList/metadata[@name='archivedir']"/>/cover.jpg<xsl:text disable-output-escaping="yes">';</xsl:text>
+				</script>
+			</xsl:when>
+			<xsl:otherwise>
+				<img><xsl:attribute name="src"><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>/index/assoc/<xsl:value-of select="metadataList/metadata[@name='archivedir']"/>/cover.jpg</xsl:attribute></img>
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+
+	<xsl:template name="documentButtons">
+		<xsl:param name="collName"/>
+		<xsl:variable name="docID" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+		<xsl:variable name="sib" select="/page/pageRequest/paramList/param[@name='sib']/@value"/>
+		<xsl:variable name="ec" select="/page/pageRequest/paramList/param[@name='ec']/@value"/>
+		<xsl:variable name="ed" select="/page/pageRequest/paramList/param[@name='ed']/@value"/>
+    
+    
+		<!-- expand document -->
+		<xsl:if test="@docType = 'hierarchy' or @docType = 'paged'">
+			<li>
+				<xsl:choose>
+					<xsl:when test="string($ed)='1'">
+						<a href="{$library_name}?a=d&amp;amp;d={$docID}&amp;amp;c={$collName}&amp;amp;sib={$sib}&amp;amp;ed=0" class="getTextFor doc.contract_doc_b this.title.doc.contract_doc_tip"></a>
+					</xsl:when>
+					<xsl:otherwise>
+						<a href="{$library_name}?a=d&amp;amp;d={$docID}&amp;amp;c={$collName}&amp;amp;sib={$sib}&amp;amp;ed=1" class="getTextFor doc.expand_doc_b this.title.doc.expand_doc_tip"></a>
+					</xsl:otherwise>
+				</xsl:choose>
+			</li>
+		</xsl:if> 
+    
+		<!-- expand contents -->
+		<xsl:if test="@docType = 'hierarchy' and string(/page/pageResponse/format/gsf:option[@name='documentTOC']/@value) != 'false'">
+			<li>
+				<xsl:choose>
+					<xsl:when test="string($ec)='1'">
+						<a href="{$library_name}?a=d&amp;amp;d={$docID}&amp;amp;c={$collName}&amp;amp;sib={$sib}&amp;amp;ec=0" class="getTextFor doc.contract_contents_b this.title.doc.contract_contents_tip"></a>
+					</xsl:when>
+					<xsl:otherwise>
+						<a  href="{$library_name}?a=d&amp;amp;d={$docID}&amp;amp;c={$collName}&amp;amp;sib={$sib}&amp;amp;ec=1" class="getTextFor doc.expand_contents_b this.title.doc.expand_contents_tip"></a>
+					</xsl:otherwise>
+				</xsl:choose>
+			</li>
+		</xsl:if>
+
+		<!-- detach page -->
+		<xsl:variable name="paramList" select="/page/pageRequest/paramList"/>
+		<li>
+			<a target="_blank" class="getTextFor doc.detach_page_b this.title.doc.detach_page_tip">
+				<xsl:attribute name="href">
+					<xsl:value-of select="$library_name"/>?a=d&amp;amp;d=<xsl:value-of select="$docID"/>&amp;amp;c=<xsl:value-of select="$collName"/>&amp;amp;sib=<xsl:value-of select="$sib"/>&amp;amp;dt=<xsl:value-of select="$paramList/param[@name='dt']/@value"/>&amp;amp;ec=<xsl:value-of select="$paramList/param[@name='ec']/@value"/>&amp;amp;et=<xsl:value-of select="$paramList/param[@name='et']/@value"/>&amp;amp;p.a=<xsl:value-of select="$paramList/param[@name='p.a']/@value"/>&amp;amp;p.s=<xsl:value-of select="$paramList/param[@name='p.s']/@value"/>&amp;amp;p.sa=<xsl:value-of select="$paramList/param[@name='p.sa']/@value"/>
+				</xsl:attribute>
+			</a>
+		</li>
+	</xsl:template>
+
+	<xsl:template name="TOC">
+		<xsl:param name="collName"/>
+		<xsl:choose>
+			<xsl:when test="@docType='hierarchy'">
+				<xsl:call-template name="hierarchicalContents">
+					<xsl:with-param name="collName" select="$collName"/>
+				</xsl:call-template>
+			</xsl:when>
+			<xsl:when test="@docType='paged'">
+				<xsl:call-template name="pagedContents">
+					<xsl:with-param name="collName" select="$collName"/>
+				</xsl:call-template>
+			</xsl:when>
+		</xsl:choose>
+	</xsl:template>
+  
+	<xsl:template name="hierarchicalContents">
+		<xsl:param name="collName"/>
+		<xsl:variable name="oc" select="/page/pageRequest/paramList/param[@name='oc']/@value"/>
+		<xsl:variable name="d" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+		<xsl:variable name="sib" select="/page/pageRequest/paramList/param[@name='sib']/@value"/>
+		<xsl:variable name="ec" select="/page/pageRequest/paramList/param[@name='ec']/@value"/>
+		<xsl:variable name="p.s" select="/page/pageRequest/paramList/param[@name='p.s']/@value"/>
+		<xsl:variable name="p.sa" select="/page/pageRequest/paramList/param[@name='p.sa']/@value"/>
+		<xsl:variable name="p.a" select="/page/pageRequest/paramList/param[@name='p.a']/@value"/>
+		<xsl:variable name="p.c"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='p.c']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='p.c']/@value"/></xsl:when><xsl:otherwise><xsl:value-of select="$collName"/></xsl:otherwise></xsl:choose></xsl:variable>
+		<script type="text/javascript">
+			<xsl:text>
+				// Load up the initial document using AJAX!
+				var initialHash = '</xsl:text>
+				<xsl:value-of select="$d" /><xsl:text>';
+			</xsl:text>
+		</script>
+		<xsl:if test="documentNode[@nodeID]">      
+			<ul id="tocnodes">
+				<li id="tocstart">
+					<xsl:choose>
+						<xsl:when test="string($oc)='0'">
+							<a href="{$library_name}?a=d&amp;amp;c={$collName}&amp;amp;d={$d}&amp;amp;sib={$sib}&amp;amp;oc=1&amp;amp;p.s={$p.s}&amp;amp;p.sa={$p.sa}&amp;amp;p.a={$p.a}&amp;amp;p.c={$p.c}"><xsl:call-template name="closedfolderimg"><xsl:with-param name="title"><xsl:value-of select="'doc.open_toc'"/></xsl:with-param></xsl:call-template></a>
+						</xsl:when>
+						<xsl:otherwise>
+							<a href="{$library_name}?a=d&amp;amp;c={$collName}&amp;amp;d={$d}&amp;amp;sib={$sib}&amp;amp;oc=0&amp;amp;p.s={$p.s}&amp;amp;p.sa={$p.sa}&amp;amp;p.a={$p.a}&amp;amp;p.c={$p.c}"><xsl:call-template name="openfolderimg"><xsl:with-param name="title"><xsl:value-of select="'doc.close_toc'"/></xsl:with-param></xsl:call-template></a>
+						</xsl:otherwise>
+					</xsl:choose>
+					<span class="getTextFor doc.table_of_contents">&amp;amp;nbsp;</span>
+					<xsl:if test="string($oc)!='0'">
+						<ul class="tocnode">
+							<xsl:for-each select="documentNode/documentNode[@nodeID]">
+								<xsl:apply-templates select='.'><xsl:with-param name="collName" select="$collName"/><xsl:with-param name="ec" select="$ec"/><xsl:with-param name="p.a" select="$p.a"/><xsl:with-param name="p.s" select="$p.s"/><xsl:with-param name="p.sa" select="$p.sa"/><xsl:with-param name="p.c" select="$p.c"/></xsl:apply-templates>
+							</xsl:for-each>
+						</ul>
+					</xsl:if>
+				</li> 
+			</ul>
+		</xsl:if>
+	</xsl:template>
+  
+	<!-- each icon-title pair is a row in a table. children go in a table in another row -->
+	<xsl:template match="documentNode">
+		<xsl:param name="collName"/>
+		<xsl:param name="ec"/>
+		<xsl:param name="p.a"/>
+		<xsl:param name="p.s"/>
+		<xsl:param name="p.sa"/>
+		<xsl:param name="p.c"/>
+		<!-- Display the appropriate image, depending on the node type -->
+		<li>
+			<a><xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;amp;c=<xsl:value-of select="$collName"/>&amp;amp;d=<xsl:value-of select="@nodeID"/><xsl:if test="documentNode">.pr</xsl:if>&amp;amp;sib=1<xsl:if test="string($ec) = '1'">&amp;amp;ec=1</xsl:if>&amp;amp;p.a=<xsl:value-of select="$p.a"/>&amp;amp;p.sa=<xsl:value-of select="$p.sa"/>&amp;amp;p.s=<xsl:value-of select="$p.s"/>&amp;amp;p.c=<xsl:value-of select="$p.c"/></xsl:attribute>
+				<xsl:apply-templates select="." mode="displayNodeIcon"/>
+			</a>
+		  
+			<!-- Display associated title, bolded if the node has content -->
+			<xsl:choose>
+				<xsl:when test="nodeContent">
+					<span class="bold"><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></span>
+				</xsl:when>
+				<xsl:otherwise>
+					<span><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></span>
+				</xsl:otherwise>
+			</xsl:choose>
+			<!-- Apply recursively to the children of this node -->
+			<xsl:if test="documentNode[@nodeID]">
+				<ul class="tocnode"> 
+					<xsl:apply-templates select="documentNode[@nodeID]">
+						<xsl:with-param name="collName" select="$collName"/>
+						<xsl:with-param name="ec" select="$ec"/>
+						<xsl:with-param name="p.a" select="$p.a"/><xsl:with-param name="p.s" select="$p.s"/><xsl:with-param name="p.sa" select="$p.sa"/><xsl:with-param name="p.c" select="$p.c"/>
+						<!--<xsl:with-param name="depth" select="$depth + 1"/>-->
+					</xsl:apply-templates>
+				</ul>
+			</xsl:if>
+		</li>
+	</xsl:template>
+  
+	<!-- default content is to print the title and content of any documentNodes that have nodeContent -->
+	<xsl:template name="documentContent">
+		<div class="documenttext"> 
+			<xsl:choose>
+				<xsl:when test="@docType='simple'"><xsl:apply-templates select="nodeContent"/></xsl:when>
+				<xsl:otherwise>
+					<!--<xsl:apply-templates select="descendant-or-self::node()/documentNode" mode="content"/>-->
+				</xsl:otherwise>
+			</xsl:choose>
+		</div>
+	</xsl:template>
+  
+	<xsl:template match="documentNode" mode="content">
+		<xsl:if test="nodeContent">
+			<xsl:if test="metadataList/metadata[@name='Title']">
+				<h3><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></h3>
+			</xsl:if>
+			<xsl:apply-templates select="nodeContent"/>
+		</xsl:if>
+	</xsl:template>
+
+	<!-- the actual text/content -->
+	<xsl:template match="nodeContent">
+		<xsl:for-each select="node()">
+			<xsl:choose>
+				<xsl:when test="not(name())">
+					<xsl:value-of select="." disable-output-escaping="yes" />
+				</xsl:when>
+				<xsl:otherwise><xsl:apply-templates select="."/></xsl:otherwise>
+			</xsl:choose>
+		</xsl:for-each>
+	</xsl:template>
+  
+	<xsl:template name="xmldocumentContentPeeling">
+		<xsl:choose>
+			<xsl:when test="@docType='simple'">
+				<xsl:apply-templates select="nodeContent"/>
+			</xsl:when>
+			<xsl:otherwise>
+				<xsl:call-template name="xmlpeelingContents" />
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+  
+	<xsl:template name="xmlpeelingContents">
+		<xsl:if test="documentNode">
+			<xsl:apply-templates select="documentNode" mode="xmlpeeling" />
+		</xsl:if>
+	</xsl:template>
+
+	<xsl:template match="documentNode" mode="xmlpeeling">
+		<!-- get title -->
+		<xsl:if test="nodeContent">
+			<xsl:text disable-output-escaping="yes">
+				&lt;Section&gt;
+				&lt;Description&gt;
+				&lt;Metadata name="Title"&gt;
+			</xsl:text>
+			<xsl:value-of select="normalize-space(metadataList/metadata[@name='Title'])"/>
+			<xsl:text disable-output-escaping="yes">
+				&lt;/Metadata&gt;
+				&lt;/Description&gt;
+			</xsl:text>
+			<xsl:value-of select="normalize-space(nodeContent)" disable-output-escaping="yes"/>
+			<xsl:text disable-output-escaping="yes">
+				&lt;/Section&gt;
+			</xsl:text>
+		</xsl:if>
+
+		<!-- recurse to the children -->
+		<xsl:if test="documentNode">
+			<xsl:apply-templates select="documentNode" mode="xmlpeeling" />
+		</xsl:if>
+
+		<xsl:if test="nodeContent">
+			<!-- end the section -->
+			<xsl:text disable-output-escaping="yes">
+		  		&amp;lt;/Section&amp;gt;
+			</xsl:text>
+		</xsl:if>
+	</xsl:template>
+  
+	<!-- match any file nodes -->
+	<xsl:template match="file">
+		<xsl:variable name="httpPath" select="/page/pageResponse/collection/metadataList/metadata[@name='httpPath']"/>
+		<xsl:choose>
+			<xsl:when test="starts-with(@mimeType, 'image/')">
+				<img src="{$httpPath}/{@href}"/>
+			</xsl:when>
+			<xsl:otherwise>
+				<a href="{$httpPath}/{@href}"><xsl:value-of select="@href"/></a>
+			</xsl:otherwise>
+		</xsl:choose>
+	</xsl:template>
+  
+	<!-- match any link nodes -->
+	<xsl:template match="link">
+		<xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/> 
+		<xsl:variable name="actionargs">
+			<xsl:choose>
+				<xsl:when test="@type='document'">a=d</xsl:when>
+				<xsl:when test="@type='query'">a=q&amp;amp;s=<xsl:value-of select="@service"/>&amp;amp;rt=rd</xsl:when>
+				<xsl:otherwise>
+					p
+				</xsl:otherwise>
+			</xsl:choose>
+		</xsl:variable>
+		<xsl:variable name="serviceargs">
+			<xsl:for-each select="param">&amp;amp;s1.<xsl:value-of select="@name"/>=<xsl:value-of select="@value"/></xsl:for-each>
+		</xsl:variable>
+		<a href="{$library_name}?{$actionargs}&amp;amp;c={$collName}{$serviceargs}"><xsl:value-of disable-output-escaping="yes" select="."/></a>
+	</xsl:template>
+
+	<!-- match any annotations and make them span elements -->
+	<xsl:template match="annotation">
+		<span class="{@type}"><xsl:value-of disable-output-escaping="yes" select="."/></span>
+	</xsl:template>
+  
+	<!-- paged naviagtion : INCOMPLETE!!-->
+	<xsl:template name="pagedContents">
+		<xsl:param name="collName"/>
+		<xsl:variable name="pos" select="nodeStructureInfo/info[@name='siblingPosition']/@value"/>
+		<xsl:variable name="length" select="nodeStructureInfo/info[@name='numSiblings']/@value"/>
+		<xsl:variable name="children" select="nodeStructureInfo/info[@name='numChildren']/@value"/>
+		<table>
+			<xsl:choose>
+				<xsl:when test="$pos=-1"><!-- a doc -->
+					<tr valign="top">
+						<td align="left">
+						</td>
+						<td align="center">
+							<center>
+								<b class="getTextFor doc.pages"></b>
+							</center>
+						</td>
+						<td align="right">
+							<a href="{$library_name}?a=d&amp;amp;c={$collName}&amp;amp;d={@selectedNode}.fc"><img src="interfaces/default/images/more.gif" border="0" align="absbottom" /></a>
+						</td>
+					</tr>
+				</xsl:when>
+
+				<xsl:otherwise> <!-- an internal node -->	  
+					<tr valign="top">
+						<td align="left">
+							<xsl:if test=" not ( $pos = 1 )">
+								<a href="{$library_name}?a=d&amp;amp;c={$collName}&amp;amp;d={@selectedNode}.ps"><img src="interfaces/default/images/less.gif" border="0" align="absbottom" /></a>
+							</xsl:if>
+						</td>
+						<td align="center">
+							<center>
+								<b><xsl:attribute name="class"><xsl:value-of select="concat('getTextFor null this.innerText.doc.pageof|', $pos, ';', $length)"/></xsl:attribute></b>
+							</center>
+						</td>
+						<td align="right">
+							<xsl:if test=" not($pos = $length)">
+								<a href="{$library_name}?a=d&amp;amp;c={$collName}&amp;amp;d={@selectedNode}.ns"><img src="interfaces/default/images/more.gif" border="0" align="absbottom" /></a>
+							</xsl:if>
+						</td>
+					</tr>
+				</xsl:otherwise>
+			</xsl:choose>
+			<tr valign="middle">
+				<td align='center' valign='top' colspan='3'>
+					<form name="GotoForm" method="get" action="{$library_name}">
+						<input type='hidden' name='a' value='d'/>
+						<input type='hidden' name='c' value='{$collName}'/>
+						<input type='hidden' name='d' value='{@selectedNode}'/>
+						<input type="text" name="gp" size="3" maxlength="4"/>
+						<input type="submit" class="getTextFor null this.value.doc.gotopage"></input>
+					</form>
+				</td>
+			</tr>
+		</table>
+	</xsl:template>
+  
+	<xsl:template name="enrichServices">
+		<xsl:param name="collName"/>
+		<xsl:variable name="docID" select="/page/pageRequest/paramList/param[@name='d']/@value"/>
+		<xsl:variable name="request-params" select="/page/pageRequest/paramList"/>
+		<xsl:for-each select="../serviceList/service">
+			 <table border='1' cellspacing='0'>
+				<tr><td>
+					<p /><xsl:value-of select="displayItem[@name='name']"/><p/>
+					<form name="EnrichForm" method="get" action="{$library_name}">
+						<xsl:apply-templates select="paramList"/>
+						<input type="hidden" name="a" value="d"/>
+						<input type="hidden" name="d" value="{$docID}"/>
+						<input type="hidden" name="c" value="{$collName}"/>
+						<xsl:if test="$request-params/param[@name='sib']">
+						<input type="hidden" name="sib"><xsl:attribute name="value"><xsl:value-of select="$request-params/param[@name='sib']/@value"/></xsl:attribute></input></xsl:if>
+						<input type="hidden" name="s" value="{@name}"/>
+						<input type="hidden" name="p.a"><xsl:attribute name="value"><xsl:value-of select="$request-params/param[@name='p.a']"/></xsl:attribute></input>
+						<input type="hidden" name="p.sa"><xsl:attribute name="value"><xsl:value-of select="$request-params/param[@name='p.sa']"/></xsl:attribute></input>
+						<input type="hidden" name="p.s"><xsl:attribute name="value"><xsl:value-of select="$request-params/param[@name='p.s']"/></xsl:attribute></input>
+						<input type="hidden" name="end" value='1'/>
+						<input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+					</form>
+				</td></tr>
+			 </table>
+		</xsl:for-each>
+	</xsl:template>
+
+	<xsl:template match="paramList" mode="hidden">
+		<xsl:for-each select="param">
+			<input type='hidden' name='{@name}' value='{@value}'/><xsl:text>
+			</xsl:text>
+		</xsl:for-each>
+	</xsl:template>
+  
+	<xsl:template name="documentArrows">
+		<xsl:param name="collName"/>
+		<xsl:variable name="ed" select="/page/pageRequest/paramList/param[@name='ed']/@value"/>
+
+		<div class="documentarrows">
+			<xsl:if test="not(string($ed)='1')">
+				<xsl:call-template name="documentArrow">
+					<xsl:with-param name="collName" select="$collName"/>
+					<xsl:with-param name="direction">back</xsl:with-param>
+				</xsl:call-template>
+				<xsl:call-template name="documentArrow">
+					<xsl:with-param name="collName" select="$collName"/>
+					<xsl:with-param name="direction">forward</xsl:with-param>
+				</xsl:call-template>
+			</xsl:if>
+		</div>
+
+	</xsl:template>
+  
+	<xsl:template name="documentArrow">
+		<xsl:param name="collName"/>
+		<xsl:param name="direction"/>
+		<xsl:variable name="request-params" select="/page/pageRequest/paramList"/>
+		<xsl:if test="$request-params/param[@name='dt']/@value != 'simple'">  
+			<a><xsl:attribute name="href"><xsl:value-of select="$library_name"/>?a=d&amp;amp;c=<xsl:value-of select="$collName"/>&amp;amp;d=<xsl:value-of select="@selectedNode"/><xsl:choose><xsl:when test="$direction='back'">.pp</xsl:when><xsl:otherwise>.np</xsl:otherwise></xsl:choose>&amp;amp;sib=1&amp;amp;p.s=<xsl:value-of select="$request-params/param[@name='p.s']/@value"/>&amp;amp;p.sa=<xsl:value-of select="$request-params/param[@name='p.sa']/@value"/>&amp;amp;p.a=<xsl:value-of select="$request-params/param[@name='p.a']/@value"/></xsl:attribute><xsl:choose><xsl:when test="$direction='back'"><img class="lessarrow" src="interfaces/default/images/less.gif" /></xsl:when><xsl:otherwise><img class="morearrow" src="interfaces/default/images/more.gif"  /></xsl:otherwise></xsl:choose></a>
+		</xsl:if> 
+	</xsl:template>
+
+	<xsl:template name="externalPage">
+		<xsl:param name="external"/>
+		<xsl:variable name="go_forward_link"><a class="getTextfor external.go_forward"><xsl:attribute name="href"><xsl:value-of select="$external"/></xsl:attribute></a></xsl:variable>
+		<h2 class="getTextFor external.title"></h2>
+		<p><xsl:attribute name="class"><xsl:value-of select="concat('getTextFor null this.innerText.external.text|', $go_forward_link)" /></xsl:attribute>
+		</p>
+	</xsl:template>
+
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/document_text.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/document_text.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/document_text.xsl	(revision 24065)
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:java="http://xml.apache.org/xslt/java"
+    xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+    extension-element-prefixes="java"
+    exclude-result-prefixes="java gsf">
+    
+    <xsl:output method="html" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />
+    
+    <xsl:template match="page">
+        <xsl:for-each select="//documentNode">
+            <xsl:if test="nodeContent">
+            <xsl:if test="metadataList/metadata[@name='Title']">
+                <h3><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></h3>
+            </xsl:if>
+            <xsl:value-of select="nodeContent" />
+            </xsl:if>
+        </xsl:for-each>
+    </xsl:template>
+    
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/gli4gs3.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/gli4gs3.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/gli4gs3.xsl	(revision 24065)
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  
+  <xsl:output method="html"/>  
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="pageResponse/service/applet"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="../pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <div >
+      <xsl:copy-of select="Applet"/>
+    </div>
+  </xsl:template>
+
+</xsl:stylesheet>  
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/help.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/help.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/help.xsl	(revision 24065)
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+		<xsl:call-template name="pageTitle"/>
+      </body>
+    </html>
+  </xsl:template>
+  
+  <xsl:template name="pageTitle">
+    <xsl:choose>
+    	<xsl:when test="/page/pageResponse/*/displayItem[@name='name']">
+    		<span>
+    			<xsl:attribute name="class">
+					<xsl:text>getTextFor null document.title.text:'</xsl:text>
+    				<xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/>
+					<xsl:text>'</xsl:text>
+    			</xsl:attribute>
+    		</span>
+    	</xsl:when>
+    	<xsl:otherwise>
+    		<span class="getTextFor null document.title.gsdl">&amp;amp;nbsp;</span>
+    	</xsl:otherwise>
+    </xsl:choose>
+    <span class="getTextFor null document.title.text:'&#160;:&#160;'[a],document.title.help_t[a]">&amp;amp;nbsp;</span>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="pageType">help</xsl:with-param>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    
+    some help text goes here
+  </xsl:template>
+  
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/home.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/home.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/home.xsl	(revision 24065)
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+xmlns="http://www.w3.org/1999/xhtml"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  xmlns:gslib="http://www.greenstone.org/skinning"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  
+  <xsl:template match="page/pageResponse">
+    
+    <!-- the page layout template is here -->
+    <html>
+      
+      <head>
+	<title>
+	  <xsl:text> </xsl:text>
+	</title>
+	<link rel="stylesheet" href="interfaces/default/style/core.css" type="text/css"/>
+      </head>
+      
+      <body>
+	
+	<div id="page-wrapper">
+	  <gslib:displayErrorsIfAny/>
+	  
+	  
+	  <div id="banner">
+	    <p>
+	      <img src="interfaces/default/images/gsdlhead.gif" class="getTextFor null this.alt.gsdl" />
+	    </p>
+	  </div>
+	  
+	  <div id="content" class="moz-output-escape">
+	    
+	    <div class="divbar"><gslib:selectACollectionTextBar/></div>
+	    
+	    <div class="QuickSearch">
+	      <gslib:crossCollectionQuickSearchForm/>
+	    </div>
+	    
+	    
+	    <ul id="collectionlist">
+	      <xsl:for-each select="collectionList/collection"> 
+		<li>
+		  <gslib:collectionLinkWithImage/>
+		</li>
+	      </xsl:for-each> 
+	    </ul>
+	    
+	    <gslib:serviceClusterList/>
+	    
+	    <div class="divbar"><gslib:noTextBar/></div>
+	    
+	    <ul id="servicelist">
+	      <xsl:for-each select="serviceList/service[@type='query']">
+		<li><gslib:serviceLink/></li>
+	      </xsl:for-each>
+	      
+	      <xsl:for-each select="serviceList/service[@type='authen']">
+		<li><gslib:authenticationLink/></li>
+	      </xsl:for-each>
+	    </ul>
+	    
+	  </div>
+
+	  
+	  <div id="footer">
+	    <div class="divbar">
+	    	<span class="getTextFor gs3power">&amp;nbsp;</span>	
+	    </div>
+	  </div>
+	  
+	</div>
+	
+	<span class="getTextFor null document.title.gsdl">&amp;nbsp;</span>
+	
+      	<span id="language" style="display: none;"><xsl:value-of select="/page/@lang" /></span>
+      	<span id="interface" style="display: none;"><xsl:value-of select="$interface_name" /></span>
+	
+		<script type="text/javascript">var placeholder = false;</script>
+		<script type="text/javascript" src="jquery.js">
+			<xsl:comment>Filler for browser</xsl:comment>
+		</script>
+		<script type="text/javascript" src="test.js">
+			<xsl:comment>Filler for browser</xsl:comment>
+		</script>
+	
+      </body>
+    </html>
+    
+    
+  </xsl:template>
+</xsl:stylesheet>  
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/html.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/html.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/html.xsl	(revision 24065)
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <xsl:output method="html"/>  
+
+  <xsl:template match="page">
+    <html>
+      <head>
+      	
+      </head>
+	  <body>
+      <frameset rows="68,*" noresize="" border="0">
+	<frame frameborder="0"><xsl:attribute name="src">?a=p&amp;amp;sa=nav&amp;amp;c=<xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value" /></xsl:attribute></frame>
+	<frame frameborder="0"><xsl:attribute name="src"><xsl:value-of select="/page/pageRequest/paramList/param[@name='url']/@value"/></xsl:attribute></frame>
+	<noframes>
+	  <p class="getTextFor textframebrowser">&amp;amp;nbsp;</p>
+	</noframes>
+      </frameset>
+		<script type="text/javascript" src="jquery.js"><!-- jQuery --></script>
+		<script type="text/javascript" src="test.js"><!-- Scripts for client side XSL transformations --></script>
+	  </body>
+    </html>
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/icons.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/icons.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/icons.xsl	(revision 24065)
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+ 
+  <!-- some global parameters - these are set by whoever is invoking the transformation -->
+  <xsl:param name="interface_name"/>
+
+  <!-- Display the appropriate image, depending on the node type -->
+  <xsl:template match="documentNode" mode="displayNodeIcon">
+    
+    <!-- Root node: book icon (open or closed) -->
+    <xsl:choose>
+      <xsl:when test="@nodeType='root'">
+	<xsl:choose>
+	  <xsl:when test="documentNode">
+	    <xsl:call-template name="openbookimg">
+	    </xsl:call-template>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:call-template name="closedbookimg">
+	    </xsl:call-template>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      
+      <!-- Internal node: folder icon (open or closed) -->
+      <xsl:when test="@nodeType='internal'">
+	<xsl:choose>
+	  <xsl:when test="documentNode">
+	    <xsl:call-template name="openfolderimg">
+	    </xsl:call-template>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:call-template name="closedfolderimg">
+	    </xsl:call-template>
+	  </xsl:otherwise>
+	</xsl:choose>
+      </xsl:when>
+      
+      <!-- Leaf node: page icon, and this is the default -->
+      <xsl:otherwise>
+	<xsl:call-template name="textpageimg">
+	</xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="openbookimg">
+  	<xsl:param name="title"/>
+    <xsl:param name="alt"/>
+    <img  border="0" width="28" height="23"
+      src="interfaces/default/images/openbook.gif"
+      alt="{$alt}" class="getTextFor null this.title.{$title}" />
+  </xsl:template>
+
+  <xsl:template name="closedbookimg">
+    <xsl:param name="alt"/>
+    <img border="0" width="18" height="11"
+      src="interfaces/default/images/book.gif"
+      alt="{$alt}" class="getTextFor null this.title.open_book" />
+  </xsl:template>
+
+  <xsl:template name="openfolderimg">
+  	<xsl:param name="title"/>
+    <xsl:param name="alt"/>
+    <img border="0" width="23" height="15"
+      src="interfaces/default/images/openfldr.gif"
+      alt="{$alt}" class="getTextFor null this.title.{$title}" />
+  </xsl:template>
+
+  <xsl:template name="closedfolderimg">
+  	<xsl:param name="title"/>
+    <xsl:param name="alt"/>
+    <img  border="0" width="23" height="15"
+      src="interfaces/default/images/clsdfldr.gif"
+      alt="{$alt}" class="getTextFor null this.title.{$title}" />
+  </xsl:template>
+
+  <xsl:template name="textpageimg">
+    <xsl:param name="alt"/>
+    <img  border="0" width="16" height="21"
+      src="interfaces/default/images/itext.gif"
+      alt="{$alt}" class="getTextFor null this.title.view_document,parent.class.text:'clientDocView'" />
+    <span><xsl:value-of select="$alt" /></span>
+  </xsl:template>
+
+  <xsl:template name="bookshelfimg">
+    <xsl:param name="alt"/>
+    <xsl:param name="title"/>
+    <img  border="0" width="20" height="16"
+      src="interfaces/default/images/bshelf.gif"  
+      alt="{$alt}" title="{$title}"/>
+  </xsl:template>
+
+  <xsl:template name="iconpdf">
+    <xsl:param name="alt">PDF</xsl:param>
+    <img border="0" width='26' height='26' 
+      src='interfaces/default/images/ipdf.gif' 
+      alt='{$alt}' class="getTextFor null this.title.texticonpdf" />
+  </xsl:template>
+  
+  <xsl:template name="icondoc">
+    <xsl:param name="alt">Word</xsl:param>
+    <img border="0" width='26' height='26' 
+      src='interfaces/default/images/imsword.gif' 
+      alt='{$alt}' class="getTextFor null this.title.texticonmsword" />
+  </xsl:template>
+
+</xsl:stylesheet>
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/library.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/library.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/library.xsl	(revision 24065)
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xsl:stylesheet version="1.0" 
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+  xmlns:gslib="http://www.greenstone.org/XSL/Library"
+  exclude-result-prefixes="gslib">
+  
+  <xsl:output
+    method="html" 
+    doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" 
+    doctype-system="http://www.w3.org/TR/html4/loose.dtd"/>
+  
+  
+  <!--Load the Greenstone Utility file that contains all the code needed to expand all GSLib elements-->
+  <xsl:include href="util.xsl"/>
+  
+</xsl:stylesheet>
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/nav.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/nav.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/nav.xsl	(revision 24065)
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<base target="_top"/>
+      </head>
+      <body style="background-image: none;">
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<xsl:apply-templates select="pageResponse"/>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/>
+  </xsl:template>
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    <div align="right">
+      <xsl:call-template name="top-buttons">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    </div>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/pref.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/pref.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/pref.xsl	(revision 24065)
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+		<xsl:call-template name="pageTitleDeferred" />
+      </body>
+    </html>
+  </xsl:template>
+  
+  <xsl:template name="pageTitle">
+    <xsl:choose><xsl:when test="/page/pageResponse/*/displayItem[@name='name']"><xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/></xsl:when><xsl:otherwise></xsl:otherwise></xsl:choose>
+  </xsl:template>
+  
+  <xsl:template name="pageTitleDeferred">
+  	    <xsl:choose><xsl:when test="/page/pageResponse/*/displayItem[@name='name']"></xsl:when><xsl:otherwise><span class="getTextFor null document.title.gsdl,document.title.text:' : '[a],document.title.pref_t[a]"></span>:</xsl:otherwise></xsl:choose>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+    
+    <xsl:variable name="tidyoption"><xsl:value-of select="/page/pageResponse/collection/metadataList/metadata[@name='tidyoption']"/></xsl:variable>
+    
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="pageType">pref</xsl:with-param>
+    </xsl:call-template>
+
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>      
+    <div id="qureyform">
+      <form name="PrefForm" method="get" action="{$library_name}">
+	<input type='hidden' name='a' value='p'/>
+	<input type='hidden' name='sa' value='pref'/>
+	<input type='hidden' name='c' value="{$collName}"/>
+	<div class="formheading"><span class="getTextFor pref.prespref"></span></div>
+	<ul id="presprefs"><xsl:call-template name="pres-prefs"/></ul>
+	<ul id="berrybasketprefs" ><xsl:call-template name="berrybasket-prefs"/></ul>
+	
+	<xsl:if test="$tidyoption='tidy'">
+	  <ul id="bookprefs"><xsl:call-template name="book-prefs"/></ul>
+	</xsl:if>
+	
+	<div class="formheading"><span class="getTextFor pref.searchpref"></span></div>
+	<ul id="searchprefs"><xsl:call-template name="search-prefs"/></ul>
+	<input type='submit' class="getTextFor null this.value.pref.set_prefs" id="test"></input>
+      </form>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="pres-prefs">
+  	<li><span class="getTextFor pref.interfacelang"></span></li>
+    <li><xsl:call-template name="lang-list"/></li>
+    <li><span class="rightspace"><span class="getTextFor pref.encoding"></span></span>x</li>
+  </xsl:template>
+  
+  <xsl:template name="lang-list">
+    <xsl:variable name="current" select="/page/@lang"/>
+    <select name="l">
+      <xsl:for-each select="/page/pageResponse/languageList/language">
+	<option value="{@name}"><xsl:if test="@name=$current"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></option>
+      </xsl:for-each>
+    </select>
+  </xsl:template>
+  
+  <xsl:template name="search-prefs">
+    <xsl:variable name="hits"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='hitsPerPage']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='hitsPerPage']/@value"/></xsl:when><xsl:otherwise>20</xsl:otherwise></xsl:choose></xsl:variable> 
+    <li><span class="getTextFor pref.hitsperpage">&amp;amp;nbsp;</span> 
+      <select name="hitsPerPage">
+	<option value="20"><xsl:if test="$hits=20"><xsl:attribute name="selected"></xsl:attribute></xsl:if>20</option> 
+	<option value="50"><xsl:if test="$hits=50"><xsl:attribute name="selected"></xsl:attribute></xsl:if>50</option>
+	<option value="100"><xsl:if test="$hits=100"><xsl:attribute name="selected"></xsl:attribute></xsl:if>100</option>
+	<option value="-1" class="getTextFor pref.all"><xsl:if test="$hits=-1"><xsl:attribute name="selected"></xsl:attribute></xsl:if></option>
+      </select>
+    </li>
+  </xsl:template>
+
+  <xsl:template name="berrybasket-prefs">
+    <xsl:variable name="berrybasket"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='berrybasket']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:when><xsl:otherwise>off</xsl:otherwise></xsl:choose></xsl:variable>
+    
+    <li><span class="getTextFor pref.berrybasket">&amp;amp;nbsp;</span> <select name="berrybasket">
+        <option value="on" class="getTextFor pref.berrybasket.on"><xsl:if test="$berrybasket='on'"><xsl:attribute name="selected"></xsl:attribute></xsl:if></option> 
+	<option value="off" class="getTextFor pref.berrybasket.off"><xsl:if test="$berrybasket='off'"><xsl:attribute name="selected"></xsl:attribute></xsl:if></option>
+      </select>
+    </li>
+  </xsl:template>
+
+  <xsl:template name="book-prefs">
+    <xsl:variable name="book"><xsl:choose><xsl:when test="/page/pageRequest/paramList/param[@name='book']"><xsl:value-of select="/page/pageRequest/paramList/param[@name='book']/@value"/></xsl:when><xsl:otherwise>off</xsl:otherwise></xsl:choose></xsl:variable>
+    
+    <span class="getTextFor pref.book">&amp;amp;nbsp;</span> <select name="book">
+      <option value="on" class="getTextFor pref.berrybasket.on"><xsl:if test="$book='on'"><xsl:attribute name="selected"></xsl:attribute></xsl:if></option> 
+      <option value="off" class="getTextFor pref.berrybasket.off"><xsl:if test="$book='off'"><xsl:attribute name="selected"></xsl:attribute></xsl:if></option>
+    </select>
+    
+  </xsl:template>
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/process.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/process.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/process.xsl	(revision 24065)
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+
+  <xsl:output method="html"/>  
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:call-template name="pageTitle"/><xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:template name="pageTitle">
+    <xsl:value-of select="/page/pageResponse/serviceCluster/metadataList/metadata[@name='Title']"/>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="clusterName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable>
+    <center>
+      <xsl:call-template name="standardPageBanner">
+	<xsl:with-param name="collName" select="$clusterName"/>
+      </xsl:call-template>
+      <xsl:call-template name="navigationBar">
+	<xsl:with-param name="collName" select="$clusterName"/>
+      </xsl:call-template>      
+      <xsl:apply-templates select="service">
+	<xsl:with-param name="clusterName" select="$clusterName"/>
+      </xsl:apply-templates>
+      <xsl:apply-templates select="status">
+	<xsl:with-param name="clusterName" select="$clusterName"/>
+      </xsl:apply-templates>
+    </center>
+  </xsl:template>
+
+  <xsl:template match="service">
+    <xsl:param name="clusterName"/>
+    <xsl:variable name='subaction' select="/page/pageRequest/@subaction"/>
+    <xsl:variable name='action' select="/page/pageRequest/@action"/>
+    <xsl:variable name='lang' select="/page/@lang"/>
+    <p/>
+    <form name="BuildForm" method="get" action="{$library_name}">
+      <xsl:apply-templates select="paramList"/>
+      <input type="hidden" name="a" value="{$action}"/>
+      <input type="hidden" name="c" value="{$clusterName}"/>
+      <input type="hidden" name="sa" value="p"/>
+      <input type="hidden" name='l' value='{$lang}'/>
+      <input type="hidden" name="s" value="{@name}"/>
+      <input type="hidden" name="rt" value="r"/>
+      <input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+    </form>
+    <xsl:call-template name="dividerBar"/>
+  </xsl:template>
+  
+  <xsl:template match="status">
+    <xsl:param name="clusterName"/>
+    <center/>
+    <applet code="org.greenstone.gsdl3.build.StatusDisplay.class" codebase='lib' archive='gsdl3.jar, xercesImpl.jar, xml-apis.jar' width='600' height='150'>The status display applet.
+      <param name='library'><xsl:attribute name="value"><xsl:value-of select='$library_name'/>?a=pr&amp;amp;rt=s&amp;amp;c=<xsl:value-of select='$clusterName'/>&amp;amp;s=<xsl:value-of select='/page/pageResponse/service/@name'/>&amp;amp;o=xml&amp;amp;ro=1&amp;amp;l=<xsl:value-of select='/page/@lang'/>&amp;amp;pid=<xsl:value-of select="@pid"/><xsl:apply-templates select="/page/pageResponse/service/paramList" mode="cgi"/></xsl:attribute></param>
+      <param name='initial_text'><xsl:attribute name="value"><xsl:value-of select="."/></xsl:attribute></param>
+      <param name='initial_code'><xsl:attribute name="value"><xsl:value-of  select="@code"/></xsl:attribute></param></applet>
+    <xsl:call-template name="dividerBar"/>
+  </xsl:template>
+
+  
+</xsl:stylesheet>  
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/query.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/query.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/query.xsl	(revision 24065)
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  <xsl:include href="service-params.xsl"/>
+  <xsl:include href="querytools.xsl"/>
+  <xsl:include href="berrytools.xsl"/>
+
+  <xsl:output method="html"/>
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+    
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	</div>
+	<xsl:call-template name="pageTitle"/>
+      </body>
+    </html>
+  </xsl:template>
+
+  <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable> 
+
+  <xsl:template name="pageTitle">
+    <span class="getTextFor null document.title.gsdl"></span>
+  </xsl:template>
+
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle">     	
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="berryStyleSheet"/>
+      <xsl:call-template name="js-library"/>
+    </xsl:if>
+  </xsl:template>
+  
+
+  <xsl:template match="pageResponse">
+    <xsl:variable name="collName"><xsl:value-of select="/page/pageRequest/paramList/param[@name='c']/@value"/></xsl:variable> 
+    <xsl:variable name="requesttype"><xsl:value-of select="/page/pageRequest/paramList/param[@name='rt']/@value"/></xsl:variable> 
+    <xsl:call-template name="standardPageBanner">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template>
+    <xsl:call-template name="navigationBar">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:call-template> 
+    <div id="content">
+      <xsl:apply-templates select="service">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:apply-templates>
+      
+      <xsl:if test="$berrybasketswitch = 'on'">
+	<xsl:call-template name="berrybasket"/>
+      </xsl:if>
+      <xsl:if test="contains($requesttype, 'r')">
+	<xsl:call-template name="query-response">
+	  <xsl:with-param name="collName" select="$collName"/>
+	</xsl:call-template>
+      </xsl:if>
+      
+    </div>
+  </xsl:template>
+
+
+  <!-- layout the response -->
+  <xsl:template name="query-response">
+    <xsl:param name="collName"/>
+    <xsl:call-template name="dividerBar"><xsl:with-param name='text'>query.results</xsl:with-param></xsl:call-template>
+    
+    <!-- If query term information is available, display it -->
+    <xsl:call-template name="termInfo"/>
+    <xsl:call-template name="matchDocs"/>
+    
+    <xsl:if test="documentNodeList">
+
+      <!-- next and prev links at top of results-->     
+      <xsl:call-template name="resultNavigation">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+      
+      <!-- Display the matching documents -->        
+      <xsl:call-template name="resultList">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+      
+      <!-- next and prev links at bottom of page -->
+      <xsl:call-template name="resultNavigation">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    </xsl:if>
+  </xsl:template>
+  
+
+  <xsl:template match="service">
+    <xsl:param name="collName"/>
+    <xsl:variable name="subaction" select="../pageRequest/@subaction"/>
+    <div id="queryform">
+      <form name="QueryForm" method="get" action="{$library_name}">
+	<input type="hidden" name="a" value="q"/>
+	<input type="hidden" name="sa" value="{$subaction}"/>
+	<input type="hidden" name="rt" value="rd"/>
+	<input type="hidden" name="s" value="{@name}"/>
+	<input type="hidden" name="c" value="{$collName}"/>
+	<xsl:if test="not(paramList/param[@name='startPage'])">
+	  <input type="hidden" name="startPage" value="1"/>
+	</xsl:if>
+	<xsl:apply-templates select="paramList"/>
+	<input type="submit"><xsl:attribute name="value"><xsl:value-of select="displayItem[@name='submit']"/></xsl:attribute></input>
+      </form>
+    </div>
+  </xsl:template>
+  
+</xsl:stylesheet>  
+
+
+
+
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/querytools.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/querytools.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/querytools.xsl	(revision 24065)
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java"
+  exclude-result-prefixes="java">
+
+  <!-- have changed this so it uses service hitsPerPage and startPage if the service description has a param called hitsPerPage,  otherwise uses interface ones -->
+  <xsl:template name="resultNavigation">
+    <xsl:param name="collName"/>
+    <div class="resultnavigation">  
+      <!-- hits type -->
+      <xsl:variable name='ht'>
+	<xsl:choose>
+	  <xsl:when test="/page/pageResponse/service/paramList/param[@name='hitsPerPage']">s</xsl:when>
+	  <xsl:otherwise>i</xsl:otherwise>
+	</xsl:choose>
+      </xsl:variable>
+      
+      <xsl:variable name="param-list" select="/page/pageRequest/paramList"/>
+      <!-- hits per page -->
+      <xsl:variable name="hpp">
+	<xsl:choose>
+	  <xsl:when test="$ht='s'"><xsl:value-of select="$param-list/param[@name='s1.hitsPerPage']/@value"/></xsl:when>
+	  <xsl:when test="$param-list/param[@name='hitsPerPage']"><xsl:value-of select="$param-list/param[@name='hitsPerPage']/@value"/></xsl:when>
+	  <xsl:otherwise>20</xsl:otherwise>
+	</xsl:choose>
+      </xsl:variable>
+      <!-- total docs - this may be in numDocsMatched or numDocsReturned metadata -->
+      <xsl:variable name="td">
+	<xsl:choose>
+	  <xsl:when test="/page/pageResponse/metadataList/metadata[@name='numDocsReturned']">
+	    <xsl:value-of select="/page/pageResponse/metadataList/metadata[@name='numDocsReturned']"/>
+	  </xsl:when>
+	  <xsl:when test="/page/pageResponse/metadataList/metadata[@name='numDocsMatched']">
+	    <xsl:value-of select="/page/pageResponse/metadataList/metadata[@name='numDocsMatched']"/>
+	  </xsl:when>
+	  <xsl:otherwise> <!-- this is just a fall back - should always have the metadata -->
+	    <xsl:value-of select="count(/page/pageResponse/documentNodeList/documentNode)"/>
+	  </xsl:otherwise>	
+	</xsl:choose>
+      </xsl:variable>
+
+      <!-- only continue if hpp != -1 and td > hpp -->
+      <xsl:if test="not($hpp=-1) and $td &gt; $hpp">
+	<!-- start page -->
+	<xsl:variable name="here">
+	  <xsl:choose>
+	    <xsl:when test="$ht='s'"><xsl:value-of select="$param-list/param[@name='s1.startPage']/@value"/></xsl:when>
+	    <xsl:when test="$param-list/param[@name='startPage']"><xsl:value-of select="$param-list/param[@name='startPage']/@value"/></xsl:when>
+	    <xsl:otherwise>1</xsl:otherwise>
+	  </xsl:choose>
+	</xsl:variable>
+	<xsl:variable name="sa" select="/page/pageRequest/@subaction"/>
+	<xsl:variable name="service" select="$param-list/param[@name='s']/@value"/>
+	<xsl:variable name="prev" select="$here - 1"/>
+	<xsl:variable name="next" select="$here + 1"/>
+	<xsl:variable name="page-param"><xsl:if test="$ht='s'">s1.</xsl:if>startPage</xsl:variable>
+	
+	<div>   
+	  <div>
+	    <xsl:if test="$here &gt; 1"><a href="{$library_name}?a=q&amp;sa={$sa}&amp;c={$collName}&amp;s={$service}&amp;rt=rd&amp;{$page-param}={$prev}"><img src="interfaces/default/images/less.gif" width='30' height='16' border='0' align='top'/><span class="getTextFor query.matches"></span><xsl:text> </xsl:text><xsl:value-of select="number(($prev - 1)*$hpp + 1)"/> - <xsl:value-of select="number(($prev * $hpp))"/></a></xsl:if>
+	    
+	    
+	    <xsl:if test="(($here * $hpp) + 1)  &lt; $td">
+	      <xsl:variable name='m' select="number($next * $hpp)"/>
+	      <xsl:variable name='mm'><xsl:choose><xsl:when test="$m &lt; $td"><xsl:value-of select='$m'/></xsl:when><xsl:otherwise><xsl:value-of select='$td'/></xsl:otherwise></xsl:choose></xsl:variable>
+	      <a href="{$library_name}?a=q&amp;sa={$sa}&amp;c={$collName}&amp;s={$service}&amp;rt=rd&amp;{$page-param}={$next}"><span class="getTextFor query.matches"></span><xsl:text> </xsl:text><xsl:value-of select="number(($next - 1)*$hpp + 1)"/> - <xsl:value-of select="$mm"/><img src="interfaces/default/images/more.gif" width='30' height='16' border='0' align='top'/></a></xsl:if></div>
+	</div>
+      </xsl:if>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="matchDocs">
+    <!-- If the number of matching documents is known, display it -->
+    <div id="matchdocs">
+      <xsl:variable name="numDocsMatched" select="metadataList/metadata[@name='numDocsMatched']"/>
+      <xsl:variable name="numDocsReturned" select="metadataList/metadata[@name='numDocsReturned']"/>
+      <xsl:choose>
+	<xsl:when test="$numDocsMatched='0' or $numDocsReturned='0'">
+		<span class="getTextFor query.nodocsmatch"></span>
+	</xsl:when>
+	<xsl:when test="$numDocsMatched='1' or $numDocsReturned='1'">
+		<span class="getTextFor query.onedocsmatch"></span>
+	</xsl:when>
+	<xsl:when test="$numDocsMatched">
+	  <span><xsl:attribute name="class"><xsl:value-of select="concat('getTextFor null this.innerText.query.manydocsmatch|', $numDocsMatched)"/></xsl:attribute></span>
+	  <xsl:if test="$numDocsReturned"> <!--(<span><xsl:attribute name="class"><xsl:value-of select="concat('getTextFor null this.innerText.query.docsreturned|', $numDocsReturned)" /></xsl:attribute></span>)--></xsl:if>
+	</xsl:when>
+	<xsl:when test="$numDocsReturned">
+	  <span><xsl:attribute name="class"><xsl:value-of select="concat('getTextFor null this.innerText.query.atleastdocsmatch|', $numDocsReturned)" /></xsl:attribute></span>
+	</xsl:when>
+      </xsl:choose>
+    </div>
+  </xsl:template>
+
+  <!-- paging is now done by the query action, so here we just print out all the docs that we have -->
+  <xsl:template name="resultList">
+    <xsl:param name="collName"/>
+    <ul id="resultlist"> 
+      <xsl:for-each select="documentNodeList/documentNode">
+	<li><table>
+	    <xsl:call-template name="documentNodeWrapper">
+	      <xsl:with-param name="collName" select="$collName"/>
+	      <xsl:with-param name="serviceName" select="/page/pageResponse/service/@name"/>
+	    </xsl:call-template>
+	  </table>
+	</li>	    
+      </xsl:for-each>  
+    </ul>
+  </xsl:template>
+  
+  <!-- this is a wrapper node, which the interface can use to add stuff into the query results that isn't part of and doesn't depend on the documentNode template which may come from the collection -->
+  <xsl:template name="documentNodeWrapper">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <xsl:variable name="berrybasketswitch"><xsl:value-of select="/page/pageRequest/paramList/param[@name='berrybasket']/@value"/></xsl:variable>
+    <!--<xsl:if test="$berryBaskets = 'true'">-->
+    <xsl:if test="$berrybasketswitch = 'on'">
+      <xsl:call-template name="addBerry">
+	<xsl:with-param name="collName" select="$collName"/>
+      </xsl:call-template>
+    </xsl:if>
+    <xsl:apply-templates select=".">
+      <xsl:with-param name="collName" select="$collName"/>
+      <xsl:with-param name="serviceName" select="$serviceName"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  
+  <!-- the default doc node template for the query results -->
+  <!-- eventually shouldn't need sib arg here -->
+  <xsl:template match="documentNode">
+    <xsl:param name="collName"/>
+    <xsl:param name="serviceName"/>
+    <a><xsl:attribute name="href"><xsl:value-of select='$library_name'/>?a=d&amp;c=<xsl:value-of select='$collName'/>&amp;d=<xsl:value-of select='@nodeID'/><xsl:if test="@nodeType='leaf'">&amp;sib=1</xsl:if>&amp;dt=<xsl:value-of select='@docType'/>&amp;p.a=q&amp;&amp;p.sa=<xsl:value-of select="/page/pageRequest/@subaction"/>&amp;p.s=<xsl:value-of select="$serviceName"/></xsl:attribute>
+      <xsl:apply-templates select="." mode="displayNodeIcon"/><xsl:text>sample</xsl:text>
+    </a>
+    <span><xsl:text>Testing</xsl:text><xsl:value-of disable-output-escaping="yes" select="metadataList/metadata[@name='Title']"/></span>
+  </xsl:template>
+
+	<xsl:template name="termInfo">
+		<div class="terminfo">
+			<xsl:if test="count(termList/stopword) > 0">
+				<span class="getTextFor query.wordcount"></span>
+				<xsl:text>The following terms are too common and have been excluded from the search: </xsl:text>
+				<xsl:for-each select="termList/stopword">
+					<xsl:value-of select="@name"/><xsl:text> </xsl:text>
+				</xsl:for-each>
+				<br />
+			</xsl:if>
+			<xsl:if test="count(termList/term) > 0">
+				<span class="getTextFor query.wordcount"></span>
+				<xsl:for-each select="termList/term">
+					<xsl:if test="position() > 1">, </xsl:if>
+					<xsl:value-of select="@name"/>: <xsl:value-of select="@freq"/> 
+				</xsl:for-each>
+			</xsl:if>
+		</div>
+	</xsl:template>
+
+</xsl:stylesheet>
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/service-params.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/service-params.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/service-params.xsl	(revision 24065)
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java">
+  
+  <!-- handling of the different types of params on a service form 
+    - these now only output the selection box/text box etc, not the name -->
+  
+  <!-- the default param list handling -->
+  <xsl:template match="paramList">
+    <xsl:param name="ns">s1.</xsl:param>
+    <ul id="queryitemlist">
+      <xsl:for-each select="param">
+        <xsl:choose>
+          <xsl:when test="@type='multi'">
+            <li><xsl:apply-templates select='.'><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates></li>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:variable name="pvalue"><xsl:apply-templates select="." mode="calculate-default"><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates></xsl:variable>
+            <li><xsl:value-of select="displayItem[@name='name']"/><xsl:apply-templates select="."><xsl:with-param name="default" select="$pvalue"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates></li>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:for-each>
+    </ul>
+  </xsl:template>
+  
+  <!-- puts all the params into a=p&p=h type form - need to change this if use 
+    multi params  -->
+  <xsl:template match="paramList" mode="cgi">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:for-each select="param">
+      <xsl:variable name='pname' select="@name"/>
+      <xsl:text>&amp;</xsl:text><xsl:value-of select="$ns"/><xsl:value-of select="@name"/>=<xsl:apply-templates select="." mode="calculate-default"><xsl:with-param name='ns' select='$ns'/></xsl:apply-templates>
+    </xsl:for-each>
+  </xsl:template>
+  
+  <xsl:template match="param" mode="calculate-default">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:variable name="pname"><xsl:value-of select="$ns"/><xsl:value-of select="@name"/></xsl:variable>
+    <xsl:choose>
+      <xsl:when test="/page/pageRequest/paramList/param[@name=$pname]">
+        <xsl:choose>
+          <xsl:when test="@type='enum_multi'"><xsl:text>,</xsl:text>
+            <xsl:for-each select="/page/pageRequest/paramList/param[@name=$pname]">
+              <xsl:value-of select="@value"/>,
+            </xsl:for-each>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="/page/pageRequest/paramList/param[@name=$pname]/@value"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="@default"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <!-- invisible params - used by other stuff. in the query form, we set to teh default -->
+  <xsl:template match="param[@type='invisible']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <input type='hidden' name='concat($ns, @name)' value='{@default}'/>
+  </xsl:template>
+  <!-- boolean params -->
+  <xsl:template match="param[@type='boolean']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    
+    <select name='{$ns}{@name}'>
+      <option value="0"><xsl:if test="$default='0'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="option[@name='0']/displayItem[@name='name']"/></option>
+      <option value="1"><xsl:if test="$default='1'"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="option[@name='1']/displayItem[@name='name']"/></option>
+    </select>
+  </xsl:template>
+  
+  <!-- integer params -->
+  <xsl:template match="param[@type='integer']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/> 
+    
+    <input type="text" name="{$ns}{@name}" size="3" value="{$default}"/>
+  </xsl:template>
+  
+  <!-- single selection enum params -->
+  <xsl:template match="param[@type='enum_single']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    
+    <xsl:choose>
+      <xsl:when test="count(option) = 1">
+        <xsl:text> </xsl:text><xsl:value-of select="option/displayItem[@name='name']"/>
+        <input type='hidden' name='{$ns}{@name}'><xsl:attribute name='value'><xsl:value-of  select='option/@name'/></xsl:attribute></input>
+      </xsl:when>
+      <xsl:otherwise>
+        
+        <select name="{$ns}{@name}">
+          <xsl:for-each select="option">
+            <option value="{@name}"><!--<xsl:if test="@name=$default"><xsl:attribute name="selected"></xsl:attribute></xsl:if>--><xsl:value-of select="displayItem[@name='name']"/></option>
+          </xsl:for-each>
+        </select>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  
+  <!-- multiple selection enum params -->
+  <!-- how to do defaults for this?? -->
+  <!-- Don't need to do anything here, handled automatically in the list -->
+  <xsl:template match="param[@type='enum_multi']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    <select name="{$ns}{@name}" size='2'><xsl:attribute name="multiple"></xsl:attribute>
+      <xsl:for-each select="option">
+        <option value="{@name}"><xsl:if test="contains($default, concat(',', @name, ','))"><xsl:attribute name="selected"></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></option>
+      </xsl:for-each>
+    </select>
+  </xsl:template>
+  
+  <!-- string params -->
+  <xsl:template match="param[@type='string']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>
+    
+    <input type="text" name="{$ns}{@name}" size="50" value="{$default}"/>
+  </xsl:template>
+  
+  <!-- large string  params -->
+  <xsl:template match="param[@type='text']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="default"/>    
+    
+    <textarea name="{$ns}{@name}" cols="50" rows="3"><xsl:value-of select='$default'/></textarea>
+  </xsl:template>
+  
+  <!-- multi params - params that are combinations of other params -->
+  <xsl:template match="param[@type='multi']">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:variable name="parent" select="@name"/>
+    <table>
+      <tr class="queryfieldheading"><xsl:value-of select="displayItem[@name='name']"/>
+        <xsl:for-each select="param">
+          <td class="queryfieldname"><xsl:value-of select="displayItem[@name='name']"/></td>
+        </xsl:for-each>
+      </tr>
+      
+      <xsl:apply-templates select="." mode="contents"><xsl:with-param name="occurs" select="@occurs"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates>
+    </table>
+  </xsl:template>
+  
+  <xsl:template match="param[@type='multi']" mode="contents">
+    <xsl:param name="ns">s1.</xsl:param>
+    <xsl:param name="occurs">1</xsl:param>
+    <xsl:variable name="pos" select="@occurs - $occurs"/>	
+    <tr class="queryfieldrow"><xsl:for-each select="param">
+      <xsl:variable name="pname" select="@name"/>
+      <xsl:variable name="values" select="/page/pageRequest/paramList/param[@name=$pname]/@value"/>
+      <td class="queryfieldcell"><xsl:choose>
+        <xsl:when test="not(@ignore) or  @ignore != $pos">      
+          <xsl:apply-templates select='.'><xsl:with-param name="default" select="$values|$pos"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates>
+        </xsl:when>
+        <xsl:otherwise><!-- put in a hidden placeholder -->
+          <input type="hidden" name='{$ns}{@name}' value=''/>
+        </xsl:otherwise>
+      </xsl:choose></td>
+    </xsl:for-each></tr>
+    <!-- recursively call this template to get multiple entries -->
+    <xsl:if test="$occurs &gt; 1">
+      <xsl:apply-templates select="." mode="contents"><xsl:with-param name="occurs" select="$occurs - 1"/><xsl:with-param name="ns" select="$ns"/></xsl:apply-templates>
+    </xsl:if>
+  </xsl:template>
+  
+  
+</xsl:stylesheet>  
+
+<!-- a param list that puts params in pairs- wont work as is with new
+  param handling stuff -->
+<!--
+  <xsl:template match="paramList">
+  <p/><table width="537">
+  <xsl:choose>
+  <xsl:when test='count(param)>4'>
+  <xsl:for-each select="param[position() mod 2 = 1]"> 
+  <tr><xsl:apply-templates select="."/>
+  <xsl:if test="following-sibling::param[1]"><xsl:apply-templates select='following-sibling::param[1]'/></xsl:if></tr>
+  </xsl:for-each>
+  </xsl:when>
+  <xsl:otherwise>
+  <xsl:for-each select="param">
+  <tr><xsl:apply-templates select='.'/></tr>
+  </xsl:for-each>
+  </xsl:otherwise>
+  </xsl:choose>
+  </table>
+  </xsl:template>
+-->
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/style.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/style.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/style.xsl	(revision 24065)
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:include href="icons.xsl"/>
+
+  <!-- some global parameters - these are set by whoever is invoking the transformation -->
+  <xsl:param name="interface_name"/>
+  <xsl:param name="library_name"/>
+
+  <!-- global style info goes here  -->
+  <xsl:template name="globalStyle">
+    <link rel="stylesheet" href="interfaces/default/style/core.css" type="text/css"/>
+  </xsl:template>
+
+  <xsl:template name="response">
+    <xsl:apply-templates select="pageResponse"/>
+    <xsl:if test="descendant::error">
+      <script language="Javascript">
+	<xsl:text disable-output-escaping="yes">
+	  	  function removeAllChildren(node) {
+	  while (node.hasChildNodes()) {
+	  node.removeChild(node.firstChild);
+	  }
+	  }
+
+	  function toggleHideError(obj) {
+	  if (obj.style.display == "none") {
+	  obj.style.display = "";
+	  hide_link = document.getElementById("hide");
+	  removeAllChildren(hide_link);
+	  var theText = getText('hide_error', null);
+	  alert(theText);
+	  var hide_text = document.createTextNode(theText);
+	  hide_link.appendChild(hide_text));
+	  } else {
+	  obj.style.display = "none";
+	  hide_link = document.getElementById("hide");
+	  removeAllChildren(hide_link);
+	  var theText = getText('show_error', null);
+	  alert(theText);
+	  var show_text = document.createTextNode(theText);
+	  hide_link.appendChild(show_text);
+	  } 
+	  }
+	</xsl:text>
+      </script>
+      <p align='right'><a id="hide" href="javascript:toggleHideError($('#error'));"><xsl:call-template name="getTextFor"><xsl:with-param name="key" select="'show_error'" /><xsl:with-param name="affect" select="''" /></xsl:call-template></a></p>
+      <div id="error" style="display: none;">
+	<xsl:apply-templates select="descendant::error"/>
+      </div>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template name="greenstoneFooter">
+    <div id="footer">
+      <xsl:call-template name="dividerBar">
+      	<xsl:with-param name="text"><xsl:text>powered-by</xsl:text></xsl:with-param>
+      </xsl:call-template>
+	  	<script type="text/javascript">var placeholder = false;</script>
+	<script type="text/javascript" src="jquery.js">
+		<xsl:comment>Filler for browser</xsl:comment>
+	</script>
+	<script type="text/javascript" src="test.js">
+		<xsl:comment>Filler for browser</xsl:comment>
+	</script>
+    </div>
+  </xsl:template>
+  
+  <xsl:template match="error">
+    <span class="getTextFor error"></span> <xsl:value-of select="."/>
+  </xsl:template>
+
+  <xsl:template name="standardPageBanner">
+    <xsl:param name="collName"/>
+    <xsl:param name="pageType"/>
+    <xsl:variable name="this-element" select="/page/pageResponse/collection|/page/pageResponse/serviceCluster"/>
+    <div id="loading" style="display: none; position: fixed; top: 0; right: 0; padding: 10px;"><img src="interfaces/default/images/loading.gif" alt="Loading interface..." /></div>
+  	<span id="language" style="display: none;"><xsl:value-of select="/page/@lang" /></span>
+  	<span id="interface" style="display: none;"><xsl:value-of select="$interface_name" /></span>   
+  	<div id="banner">    
+      <p>
+	<a href="{$library_name}?a=p&amp;sa=about&amp;c={$collName}">
+	  <xsl:choose>
+	    <xsl:when test="$this-element/displayItem[@name='icon']">
+	      <img border="0">
+		<xsl:attribute name="src">
+		  <xsl:value-of select="$this-element/metadataList/metadata[@name='httpPath']"/>/images/<xsl:value-of select="$this-element/displayItem[@name='icon']"/>
+		</xsl:attribute>	
+		<xsl:attribute name="alt">
+		  <xsl:value-of select="$this-element/displayItem[@name='name']"/>
+		</xsl:attribute></img>
+	    </xsl:when>
+	    <xsl:otherwise>
+	      <xsl:value-of select="$this-element/displayItem[@name='name']"/>
+	    </xsl:otherwise>
+	  </xsl:choose>
+	</a>
+      </p>
+	  	<xsl:call-template name="getTextFor">
+			<xsl:with-param name="key" select="'null'" />
+			<xsl:with-param name="affect" select="'parent.title.aboutpage'" />
+			<xsl:with-param name="display" select="'none'" />
+		</xsl:call-template>
+      <ul id="bannerlist"> 
+	<xsl:call-template name="top-buttons">
+	  <xsl:with-param name="collName" select="$collName"/>
+	  <xsl:with-param name="pageType" select="$pageType"/>
+	</xsl:call-template>
+      </ul>
+    </div>
+  </xsl:template>
+  
+  <xsl:template name="top-buttons">
+    <xsl:param name="collName"/>
+    <xsl:param name="pageType"/>
+    <li><a href="{$library_name}?a=p&amp;sa=home">
+	  	<xsl:call-template name="getTextFor">
+  			<xsl:with-param name="key" select="'home_b'" />
+  			<xsl:with-param name="parentTip" select="'home_tip'" />
+  		</xsl:call-template>
+      </a></li>
+    <xsl:choose>
+      <xsl:when test="$pageType='help'">
+	<li><a>
+		  <xsl:call-template name="getTextFor">
+  			  <xsl:with-param name="key" select="'help_b'" />
+  			  <xsl:with-param name="affect" select="'parent.title.help_tip'" />
+  		  </xsl:call-template>	
+	</a></li>
+      </xsl:when>
+      <xsl:otherwise>
+	<li><a href="{$library_name}?a=p&amp;sa=help&amp;c={$collName}">
+	      <xsl:call-template name="getTextFor">
+  				<xsl:with-param name="key" select="'help_b'" />
+  				<xsl:with-param name="affect" select="'parent.title.help_tip'" />
+  			</xsl:call-template>
+	  </a></li>
+      </xsl:otherwise>
+    </xsl:choose>
+    <xsl:choose>
+      <xsl:when test="$pageType='pref'">
+	<li><a><xsl:call-template name="getTextFor"><xsl:with-param name="key" select="'pref_b'" /><xsl:with-param name="affect" select="''" /></xsl:call-template></a></li>
+      </xsl:when>
+      <xsl:otherwise>
+	<li><a href="{$library_name}?a=p&amp;sa=pref&amp;c={$collName}">
+	      <xsl:call-template name="getTextFor"><xsl:with-param name="key" select="'pref_b'" /><xsl:with-param name="affect" select="'parent.title.pref_tip'" /></xsl:call-template>
+	  </a></li>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  <xsl:template name="getTextFor">
+  	<xsl:param name="key" />
+  	<xsl:param name="affect" />
+  	<xsl:param name="display" select="'yes'" />
+
+	<xsl:variable name="extra">
+	<xsl:choose>
+	<xsl:when test="$affect!=''">
+		<xsl:text> </xsl:text>
+		<xsl:value-of select="$affect" />  	
+	</xsl:when>  	
+  	<xsl:otherwise>
+		<xsl:value-of select="' '" />  	
+  	</xsl:otherwise>
+  	</xsl:choose>
+  	</xsl:variable>
+
+  	<span class="getTextFor {$key}{$extra}"><xsl:if test="$display='none'"><xsl:attribute name="style"><xsl:text>display: </xsl:text><xsl:value-of select="$display" /><xsl:text>;</xsl:text></xsl:attribute></xsl:if><xsl:value-of select="$key" /></span>
+  </xsl:template>
+
+  <xsl:template name="navigationBar">
+    <xsl:param name="collName"/>
+    <xsl:variable name="this-element" select="/page/pageResponse/collection|/page/pageResponse/serviceCluster"/>
+    <xsl:variable name="this-service" select="/page/pageResponse/service/@name"/>
+    <xsl:choose>
+      <xsl:when test="$this-element/serviceList/service">
+	<div id="navbar">
+	  <ul id="navbarlist">
+	    <xsl:for-each select="$this-element/serviceList/service">
+	      <xsl:variable name="action"><xsl:choose>
+		  <xsl:when test="@hidden='true'">DO_NOT_DISPLAY</xsl:when>
+		  <xsl:when test="@name=$this-service">CURRENT</xsl:when>
+		  <xsl:when test="@type='query'">q</xsl:when>
+		  <xsl:when test="@type='browse'">b</xsl:when>
+		  <xsl:when test="@type='process'">pr</xsl:when>
+		  <xsl:when test="@type='applet'">a</xsl:when>
+		  <xsl:otherwise>DO_NOT_DISPLAY</xsl:otherwise>
+		</xsl:choose></xsl:variable>
+	      <xsl:choose>
+		<xsl:when test="$action='CURRENT'">
+		  <li><a ><xsl:value-of select="displayItem[@name='name']"/></a></li>
+		</xsl:when>
+		<xsl:when test="$action !='DO_NOT_DISPLAY'">
+		  <li><a href="{$library_name}?a={$action}&amp;rt=d&amp;s={@name}&amp;c={$collName}"><xsl:if test="displayItem[@name='description']"><xsl:attribute name='title'><xsl:value-of select="displayItem[@name='description']"/></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></a></li>
+		</xsl:when>
+	      </xsl:choose>
+	    </xsl:for-each>
+	  </ul>
+	</div> 
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="dividerBar">
+	  <xsl:with-param name="text" select="'&#160;'"/> 
+        </xsl:call-template>            
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+  
+  
+  <xsl:template name="dividerBar">
+    <xsl:param name='text'/>
+    <xsl:choose>
+      <xsl:when test="$text">
+		<div class="divbar"><xsl:choose><xsl:when test="$text='powered-by'"><span class="getTextFor gs3power">&amp;nbsp;</span></xsl:when><xsl:when test="$text='query.results'"><span class="getTextFor query.results">&amp;nbsp;</span></xsl:when><xsl:otherwise><xsl:value-of select="$text"/></xsl:otherwise></xsl:choose></div>
+      </xsl:when>
+      <xsl:otherwise>
+	<div class="divbar"><xsl:text disable-output-escaping="yes">&#160;</xsl:text></div>
+      </xsl:otherwise>
+    </xsl:choose> 
+  </xsl:template>
+	
+  <xsl:template name="direction">
+    <xsl:if test="/page/@lang='ar' or /page/@lang='fa' or /page/@lang='he' or /page/@lang='ur' or /page/@lang='ps' or /page/@lang='prs'">rtl</xsl:if>
+  </xsl:template>
+
+</xsl:stylesheet>  
+
+
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/system.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/system.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/system.xsl	(revision 24065)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:java="http://xml.apache.org/xslt/java"
+  extension-element-prefixes="java">
+  
+  <!-- style includes global params interface_name, library_name -->
+  <xsl:include href="style.xsl"/>
+  
+  <!-- the main page layout template is here -->
+  <xsl:template match="page">
+    <html>
+      <head>
+	<title>
+	  <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+	  <xsl:text> </xsl:text>
+	</title>
+	<xsl:call-template name="globalStyle"/>
+	<xsl:call-template name="pageStyle"/>
+      </head>
+      <body>
+	<xsl:attribute name="dir"><xsl:call-template name="direction"/></xsl:attribute>
+	<div id="page-wrapper">
+	  <xsl:call-template name="response" />
+	  <xsl:call-template name="greenstoneFooter"/>
+	  <xsl:call-template name="pageTitle"/>
+	</div>
+      </body>
+    </html>
+  </xsl:template>
+  
+  <xsl:template name="pageTitle">
+    <span class="getTextFor null document.title.gsdl">&amp;nbsp;</span>
+  </xsl:template>
+  
+  <!-- page specific style goes here -->
+  <xsl:template name="pageStyle"/>
+  
+  <xsl:template match="pageResponse">
+    <xsl:value-of select="status"/>
+  </xsl:template>
+  
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/util.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/util.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/util.xsl	(revision 24065)
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="1.0" 
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
+  xmlns:gslib="http://www.greenstone.org/XSL/Library"
+  xmlns:gsf="http://www.greenstone.org/greenstone3/schema/ConfigFormat"
+  exclude-result-prefixes="gslib gsf">
+  
+  <!-- some global parameters - these are set by whoever is invoking the transformation -->
+  <xsl:param name="interface_name"/>
+  <xsl:param name="library_name"/>
+
+  <!-- Get rid of XSLT parameters from view -->
+  <xsl:template match="xsltparams/param">
+    <xsl:text></xsl:text>
+  </xsl:template>
+  
+  <!-- every pages ................................................. -->
+  
+  <xsl:variable name="a"><xsl:value-of select="/page/pageRequest/paramList/param[@name='a']/@value"/></xsl:variable>
+  <xsl:variable name="collections" select="/page/pageResponse/collectionList/collection"/>
+  
+  
+  <xsl:template name="textDirectionAttribute">
+    <xsl:attribute name="dir">
+      <xsl:choose>
+	<xsl:when test="/page/@lang='ar' or /page/@lang='fa' or /page/@lang='he' or /page/@lang='ur' or /page/@lang='ps' or /page/@lang='prs'">rtl</xsl:when>
+	<xsl:otherwise>ltr</xsl:otherwise>
+      </xsl:choose> 
+    </xsl:attribute>
+  </xsl:template>
+  
+  
+  <xsl:template name="defaultDividerBar">
+    <xsl:param name='text'/>
+    <xsl:choose>
+      <xsl:when test="$text">
+	<div class="divbar"><xsl:value-of select="$text"/></div>
+      </xsl:when>
+      <xsl:otherwise>
+	<div class="divbar"><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text></div>
+      </xsl:otherwise>
+    </xsl:choose> 
+  </xsl:template>
+  
+  
+  <xsl:template match="error">
+    Error: <xsl:value-of select="."/>
+  </xsl:template>
+  
+  
+  <xsl:template name="displayErrorsIfAny">
+    <xsl:if test="descendant::error">
+      <script language="Javascript">
+	<xsl:text disable-output-escaping="yes">
+	  function removeAllChildren(node) {
+	  while (node.hasChildNodes()) {
+	  node.removeChild(node.firstChild);
+	  }
+	  }
+
+	  function toggleHideError(obj) {
+	  if (obj.style.display == "none") {
+	  obj.style.display = "";
+	  hide_link = document.getElementById("hide");
+	  removeAllChildren(hide_link);
+	  var theText = getText('hide_error', null);
+	  var hide_text = document.createTextNode(theText);
+	  hide_link.appendChild(hide_text));
+	  } else {
+	  obj.style.display = "none";
+	  hide_link = document.getElementById("hide");
+	  removeAllChildren(hide_link);
+	  var theText = getText('show_error', null);
+	  var show_text = document.createTextNode(theText);
+	  hide_link.appendChild(show_text);
+	  } 
+	  }
+	</xsl:text>
+      </script>
+      <p align='right'><a id="hide" href="javascript:toggleHideError(error);"></a></p>
+      <div id="error" style="display: none;">
+	<xsl:apply-templates select="descendant::error"/>
+      </div>
+    </xsl:if>
+  </xsl:template>
+
+
+  <xsl:template name="noTextBar">
+    <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>
+  </xsl:template>
+  
+  
+  <xsl:template name="poweredByGS3TextBar">
+    <span class="getTextFor gs3power">&amp;nbsp;</span>
+  </xsl:template>
+  
+  
+  <!-- site home ...................................................... -->
+
+  <xsl:template name="siteHomePageTitle">
+    <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+    <span class="getTextFor gsdl">&amp;nbsp;</span><xsl:text> </xsl:text>
+  </xsl:template>
+
+
+  <xsl:template name="selectACollectionTextBar">
+  	<span class="getTextFor home.select_a_collection">&amp;nbsp;</span>
+  </xsl:template>
+  
+  
+  <xsl:template name="crossCollectionQuickSearchForm">
+    <xsl:apply-templates select="serviceList/service[@name='TextQuery']" mode="quicksearch"/>
+  </xsl:template> 
+  
+  <xsl:template match="service[@name='TextQuery']" mode="quicksearch">
+    <form name="QuickSearch" method="get" action="{$library_name}">
+      <input type="hidden" name="a" value="q"/>
+      <input type="hidden" name="rt" value="rd"/>
+      <input type="hidden" name="s" value="{@name}"/>
+      <input type="hidden" name="s1.collection" value="all"/>
+      <input type="text" name="s1.query" size="20"/>
+      <input type="submit" class="getTextFor null this.value.home.quick_search" />
+    </form>
+  </xsl:template>
+  
+  
+  <xsl:template name="collectionLinkWithImage">
+    <xsl:choose>
+      <xsl:when test="displayItem[@name='icon']">
+	<a href="{$library_name}?a=p&amp;sa=about&amp;c={@name}">
+	  <img>
+	    <xsl:attribute name="src">
+	      <xsl:value-of select="metadataList/metadata[@name='httpPath']"/>/images/<xsl:value-of select="displayItem[@name='icon']"/>
+	    </xsl:attribute>
+	    <xsl:attribute name="alt">
+	      <xsl:value-of select="displayItem[@name='name']"/>
+	    </xsl:attribute>
+	  </img> 
+	</a>  
+      </xsl:when>
+      <xsl:otherwise>
+	<a class="noimage" href="{$library_name}?a=p&amp;sa=about&amp;c={@name}">  
+	  <xsl:value-of select="displayItem[@name='name']"/>
+	</a>
+      </xsl:otherwise>
+    </xsl:choose> 
+  </xsl:template>
+  
+  
+  <xsl:template name="serviceClusterList">
+    <xsl:apply-templates select="serviceClusterList"/>
+  </xsl:template> 
+  
+  <xsl:template match="serviceClusterList">
+    <xsl:for-each select="serviceCluster"> 
+      <a href="{$library_name}?a=p&amp;sa=about&amp;c={@name}"><xsl:value-of select='@name'/><xsl:value-of select="displayItem[@name='name']"/></a>
+    </xsl:for-each>
+  </xsl:template>
+
+  
+  <xsl:template name="serviceLink">
+    <a href="{$library_name}?a=q&amp;rt=d&amp;s={@name}"><xsl:value-of select="displayItem[@name='name']"/></a><xsl:value-of select="displayItem[@name='description']"/>
+  </xsl:template>
+
+  
+  <xsl:template name="authenticationLink">
+    <a href="{$library_name}?a=g&amp;rt=r&amp;sa=authen&amp;s={@name}&amp;s1.aup=Login&amp;s1.un=&amp;s1.asn="><xsl:value-of select="displayItem[@name='name']"/></a><xsl:value-of select="displayItem[@name='description']"/>
+  </xsl:template> 
+  
+  
+  <xsl:template name="libraryInterfaceLink">
+    <li><a href="{$library_name}?a=p&amp;sa=gli4gs3"><span class="getTextFor home.librarian_interface">&amp;nbsp;</span></a></li>
+  </xsl:template> 
+
+  <!-- about page - collection home ......................... -->
+  <xsl:variable name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+  <xsl:param name="collName" select="/page/pageRequest/paramList/param[@name='c']/@value"/>
+  <xsl:param name="pageType"/>
+  <xsl:variable name="this-element" select="/page/pageResponse/collection|/page/pageResponse/serviceCluster"/>
+  <xsl:variable name="this-service" select="/page/pageResponse/service/@name"/>
+
+  <xsl:template name="aboutCollectionPageTitle">
+    <!-- put a space in the title in case the actual value is missing - mozilla will not display a page with no title-->
+    <xsl:value-of select="/page/pageResponse/*/displayItem[@name='name']"/><xsl:text> </xsl:text>
+  </xsl:template>
+
+  
+  <xsl:template name="collectionHomeLinkWithLogoIfAvailable">
+    <a href="{$library_name}?a=p&amp;sa=about&amp;c={$collName}">
+      <xsl:choose>
+	<xsl:when test="$this-element/displayItem[@name='icon']">
+	  <img border="0" class="getTextFor null this.title.aboutpage">
+	    <xsl:attribute name="src">
+	      <xsl:value-of select="$this-element/metadataList/metadata[@name='httpPath']"/>/images/<xsl:value-of select="$this-element/displayItem[@name='icon']"/>
+	    </xsl:attribute>	
+	    <xsl:attribute name="alt">
+	      <xsl:value-of select="$this-element/displayItem[@name='name']"/>
+	    </xsl:attribute>
+	  </img>
+	</xsl:when>
+	<xsl:otherwise>
+	  <xsl:value-of select="$this-element/displayItem[@name='name']"/>
+	</xsl:otherwise>
+      </xsl:choose>
+    </a>
+  </xsl:template>
+
+
+  <xsl:template name="homeButtonTop">
+    <a href="{$library_name}?a=p&amp;sa=home" class="getTextFor home_b this.title.home_tip">&amp;nbsp;</a>
+  </xsl:template>
+
+
+  <xsl:template name="helpButtonTop">
+    <xsl:choose>
+      <xsl:when test="$pageType='help'">
+	<li><a class="getTextFor help_b"></a></li>
+      </xsl:when>
+      <xsl:otherwise>
+	<li><a href="{$library_name}?a=p&amp;sa=help&amp;c={$collName}" class="getTextFor help_b this.title.help_tip">&amp;nbsp;</a></li>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+
+  <xsl:template name="preferencesButtonTop">
+    <xsl:choose>
+      <xsl:when test="$pageType='pref'">
+	<li><a class="getTextFor pref_b">&amp;nbsp;</a></li>
+      </xsl:when>
+      <xsl:otherwise>
+	<li><a href="{$library_name}?a=p&amp;sa=pref&amp;c={$collName}" class="getTextFor pref_b this.title.pref_tip">&amp;nbsp;</a></li>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="servicesNavigationBar">
+    <xsl:for-each select="$this-element/serviceList/service">
+      <xsl:variable name="action"><xsl:choose>
+	  <xsl:when test="@hidden='true'">DO_NOT_DISPLAY</xsl:when>
+	  <xsl:when test="@name=$this-service">CURRENT</xsl:when>
+	  <xsl:when test="@type='query'">q</xsl:when>
+	  <xsl:when test="@type='browse'">b</xsl:when>
+	  <xsl:when test="@type='process'">pr</xsl:when>
+	  <xsl:when test="@type='applet'">a</xsl:when>
+	  <xsl:otherwise>DO_NOT_DISPLAY</xsl:otherwise>
+	</xsl:choose></xsl:variable>
+      <xsl:choose>
+	<xsl:when test="$action='CURRENT'">
+	  <li><a><xsl:value-of select="displayItem[@name='name']"/></a></li>
+	</xsl:when>
+	<xsl:when test="$action !='DO_NOT_DISPLAY'">
+	  <li><a href="{$library_name}?a={$action}&amp;rt=d&amp;s={@name}&amp;c={$collName}"><xsl:if test="displayItem[@name='description']"><xsl:attribute name='title'><xsl:value-of select="displayItem[@name='description']"/></xsl:attribute></xsl:if><xsl:value-of select="displayItem[@name='name']"/></a></li>
+	</xsl:when>
+      </xsl:choose>
+    </xsl:for-each>
+  </xsl:template>
+
+
+  <xsl:template name="collectionDescriptionTextAndServicesLinks">
+    <xsl:apply-templates select="pageResponse/collection|serviceCluster"/>
+  </xsl:template>
+
+  <xsl:template match="collection|serviceCluster">
+    <xsl:value-of select="displayItem[@name='description']" disable-output-escaping="yes"/>
+    
+    <xsl:apply-templates select="serviceList">
+      <xsl:with-param name="collName" select="$collName"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+
+  <xsl:template match="serviceList">
+    <xsl:param name="collName"/>
+    <h3 class="getTextFor about.services">&amp;nbsp;</h3>
+    <xsl:choose>
+      <xsl:when test="service">
+		<span class="getTextFor about.servicehelp">&amp;nbsp;</span>
+      </xsl:when>
+      <xsl:otherwise>
+		<span class="getTextFor about.noservices">&amp;nbsp;</span>
+      </xsl:otherwise>
+    </xsl:choose>
+    
+    
+    <xsl:if test="service">
+      <ul id="servicelist">  	
+	<xsl:for-each select="service">
+	  <xsl:variable name="action"><xsl:choose>
+	      <xsl:when test="@hidden='true'">DO_NOT_DISPLAY</xsl:when>
+	      <xsl:when test="@type='query'">q</xsl:when>
+	      <xsl:when test="@type='browse'">b</xsl:when>
+	      <xsl:when test="@type='process'">pr</xsl:when>
+	      <xsl:when test="@type='applet'">a</xsl:when>
+	      <xsl:otherwise>DO_NOT_DISPLAY</xsl:otherwise>
+	    </xsl:choose></xsl:variable>
+	  <xsl:if test="$action !='DO_NOT_DISPLAY'">
+	    <li><a href="{$library_name}?a={$action}&amp;rt=d&amp;s={@name}&amp;c={$collName}"><xsl:value-of select="displayItem[@name='name']"/></a><xsl:value-of select="displayItem[@name='description']"/></li>
+	  </xsl:if>
+  	</xsl:for-each>
+      </ul> 
+    </xsl:if> 
+  </xsl:template>
+
+</xsl:stylesheet>
Index: /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/xml-to-string.xsl
===================================================================
--- /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/xml-to-string.xsl	(revision 24065)
+++ /main/trunk/greenstone3/web/interfaces/default-client-xslt/transform/xml-to-string.xsl	(revision 24065)
@@ -0,0 +1,319 @@
+<!--
+Copyright (c) 2001-2009, Evan Lenz
+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 Lenz Consulting Group 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.
+
+Recent changes:
+
+2010-06-10: Added the $force-exclude-all-namespaces parameter
+2009-10-19: Added the $exclude-these-namespaces parameter 
+2009-10-08: Added $att-value parameter and template name to template rule for attributes.
+
+-->
+<xsl:stylesheet version="1.0"
+  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+  <xsl:output omit-xml-declaration="yes"/>
+
+  <xsl:param name="use-empty-syntax" select="true()"/>
+  <xsl:param name="exclude-unused-prefixes" select="true()"/>
+
+  <xsl:param name="force-exclude-all-namespaces" select="false()"/>
+
+  <!-- a node-set; each node's string-value
+       will be interpreted as a namespace URI to be
+       excluded from the serialization. -->
+  <xsl:param name="namespaces-to-exclude" select="/.."/>
+                                          <!-- initialized to empty node-set -->
+
+  <xsl:param name="start-tag-start"     select="'&lt;'"/>
+  <xsl:param name="start-tag-end"       select="'>'"/>
+  <xsl:param name="empty-tag-end"       select="'/>'"/>
+  <xsl:param name="end-tag-start"       select="'&lt;/'"/>
+  <xsl:param name="end-tag-end"         select="'>'"/>
+  <xsl:param name="space"               select="' '"/>
+  <xsl:param name="ns-decl"             select="'xmlns'"/>
+  <xsl:param name="colon"               select="':'"/>
+  <xsl:param name="equals"              select="'='"/>
+  <xsl:param name="attribute-delimiter" select="'&quot;'"/>
+  <xsl:param name="comment-start"       select="'&lt;!--'"/>
+  <xsl:param name="comment-end"         select="'-->'"/>
+  <xsl:param name="pi-start"            select="'&lt;?'"/>
+  <xsl:param name="pi-end"              select="'?>'"/>
+
+  <xsl:template name="xml-to-string">
+    <xsl:param name="node-set" select="."/>
+    <xsl:apply-templates select="$node-set" mode="xml-to-string">
+      <xsl:with-param name="depth" select="1"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+<!--
+  <xsl:template match="/" name="xml-to-string-root-rule">
+    <xsl:call-template name="xml-to-string"/>
+  </xsl:template>
+-->
+
+  <xsl:template match="/" mode="xml-to-string">
+    <xsl:param name="depth"/>
+    <xsl:apply-templates mode="xml-to-string">
+      <xsl:with-param name="depth" select="$depth"/>
+    </xsl:apply-templates>
+  </xsl:template>
+
+  <xsl:template match="*" mode="xml-to-string">
+    <xsl:param name="depth"/>
+    <xsl:variable name="element" select="."/>
+    <xsl:value-of select="$start-tag-start"/>
+    <xsl:call-template name="element-name">
+      <xsl:with-param name="text" select="name()"/>
+    </xsl:call-template>
+    <xsl:apply-templates select="@*" mode="xml-to-string"/>
+    <xsl:if test="not($force-exclude-all-namespaces)">
+      <xsl:for-each select="namespace::*">
+        <xsl:call-template name="process-namespace-node">
+          <xsl:with-param name="element" select="$element"/>
+          <xsl:with-param name="depth" select="$depth"/>
+        </xsl:call-template>
+      </xsl:for-each>
+    </xsl:if>
+    <xsl:choose>
+      <xsl:when test="node() or not($use-empty-syntax)">
+        <xsl:value-of select="$start-tag-end"/>
+        <xsl:apply-templates mode="xml-to-string">
+          <xsl:with-param name="depth" select="$depth + 1"/>
+        </xsl:apply-templates>
+        <xsl:value-of select="$end-tag-start"/>
+        <xsl:call-template name="element-name">
+          <xsl:with-param name="text" select="name()"/>
+        </xsl:call-template>
+        <xsl:value-of select="$end-tag-end"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$empty-tag-end"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="process-namespace-node">
+    <xsl:param name="element"/>
+    <xsl:param name="depth"/>
+    <xsl:variable name="declaredAbove">
+      <xsl:call-template name="isDeclaredAbove">
+        <xsl:with-param name="depth" select="$depth - 1"/>
+        <xsl:with-param name="element" select="$element/.."/>
+      </xsl:call-template>
+    </xsl:variable>
+
+    <xsl:variable name="is-used-on-this-element" select="($element    | $element/@*) [namespace-uri() = current()]"/>
+    <xsl:variable name="is-used-on-a-descendant" select="($element//* | $element//@*)[namespace-uri() = current()]"/>          
+    <xsl:variable name="is-unused" select="not($is-used-on-this-element) and
+                                           not($is-used-on-a-descendant)"/>
+    <xsl:variable name="exclude-ns" select="($is-unused and $exclude-unused-prefixes) or
+                                            (. = $namespaces-to-exclude)"/>
+
+    <xsl:variable name="force-include" select="$is-used-on-this-element and (. = $namespaces-to-exclude)"/>
+
+    <xsl:if test="(name() != 'xml') and ($force-include or (not($exclude-ns) and not(string($declaredAbove))))">
+      <xsl:value-of select="$space"/>
+      <xsl:value-of select="$ns-decl"/>
+      <xsl:if test="name()">
+        <xsl:value-of select="$colon"/>
+        <xsl:call-template name="ns-prefix">
+          <xsl:with-param name="text" select="name()"/>
+        </xsl:call-template>
+      </xsl:if>
+      <xsl:value-of select="$equals"/>
+      <xsl:value-of select="$attribute-delimiter"/>
+      <xsl:call-template name="ns-uri">
+        <xsl:with-param name="text" select="string(.)"/>
+      </xsl:call-template>
+      <xsl:value-of select="$attribute-delimiter"/>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template name="isDeclaredAbove">
+    <xsl:param name="element"/>
+    <xsl:param name="depth"/>
+    <xsl:if test="$depth > 0">
+      <xsl:choose>
+        <xsl:when test="$element/namespace::*[name(.)=name(current()) and .=current()]">1</xsl:when>
+        <xsl:when test="$element/namespace::*[name(.)=name(current())]"/>
+        <xsl:otherwise>
+          <xsl:call-template name="isDeclaredAbove">
+            <xsl:with-param name="depth" select="$depth - 1"/>
+            <xsl:with-param name="element" select="$element/.."/>
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="@*" mode="xml-to-string" name="serialize-attribute">
+    <xsl:param name="att-value" select="string(.)"/>
+    <xsl:value-of select="$space"/>
+    <xsl:call-template name="attribute-name">
+      <xsl:with-param name="text" select="name()"/>
+    </xsl:call-template>
+    <xsl:value-of select="$equals"/>
+    <xsl:value-of select="$attribute-delimiter"/>
+    <xsl:call-template name="attribute-value">
+      <xsl:with-param name="text" select="$att-value"/>
+    </xsl:call-template>
+    <xsl:value-of select="$attribute-delimiter"/>
+  </xsl:template>
+
+  <xsl:template match="comment()" mode="xml-to-string">
+    <xsl:value-of select="$comment-start"/>
+    <xsl:call-template name="comment-text">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+    <xsl:value-of select="$comment-end"/>
+  </xsl:template>
+
+  <xsl:template match="processing-instruction()" mode="xml-to-string">
+    <xsl:value-of select="$pi-start"/>
+    <xsl:call-template name="pi-target">
+      <xsl:with-param name="text" select="name()"/>
+    </xsl:call-template>
+    <xsl:value-of select="$space"/>
+    <xsl:call-template name="pi-text">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+    <xsl:value-of select="$pi-end"/>
+  </xsl:template>
+
+  <xsl:template match="text()" mode="xml-to-string">
+    <xsl:call-template name="text-content">
+      <xsl:with-param name="text" select="string(.)"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="element-name">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="attribute-name">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="attribute-value">
+    <xsl:param name="text"/>
+    <xsl:variable name="escaped-markup">
+      <xsl:call-template name="escape-markup-characters">
+        <xsl:with-param name="text" select="$text"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:choose>
+      <xsl:when test="$attribute-delimiter = &quot;'&quot;">
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="$escaped-markup"/>
+          <xsl:with-param name="replace" select="&quot;'&quot;"/>
+          <xsl:with-param name="with" select="'&amp;amp;apos;'"/>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:when test="$attribute-delimiter = '&quot;'">
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="$escaped-markup"/>
+          <xsl:with-param name="replace" select="'&quot;'"/>
+          <xsl:with-param name="with" select="'&amp;amp;quot;'"/>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="$escaped-markup"/>
+          <xsl:with-param name="replace" select="$attribute-delimiter"/>
+          <xsl:with-param name="with" select="''"/>
+        </xsl:call-template>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+  <xsl:template name="ns-prefix">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="ns-uri">
+    <xsl:param name="text"/>
+    <xsl:call-template name="attribute-value">
+      <xsl:with-param name="text" select="$text"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="text-content">
+    <xsl:param name="text"/>
+    <xsl:call-template name="escape-markup-characters">
+      <xsl:with-param name="text" select="$text"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="pi-target">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="pi-text">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="comment-text">
+    <xsl:param name="text"/>
+    <xsl:value-of select="$text"/>
+  </xsl:template>
+
+  <xsl:template name="escape-markup-characters">
+    <xsl:param name="text"/>
+    <xsl:variable name="ampEscaped">
+      <xsl:call-template name="replace-string">
+        <xsl:with-param name="text" select="$text"/>
+        <xsl:with-param name="replace" select="'&amp;amp;'"/>
+        <xsl:with-param name="with" select="'&amp;amp;amp;'"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:variable name="ltEscaped">
+      <xsl:call-template name="replace-string">
+        <xsl:with-param name="text" select="$ampEscaped"/>
+        <xsl:with-param name="replace" select="'&lt;'"/>
+        <xsl:with-param name="with" select="'&amp;amp;lt;'"/>
+      </xsl:call-template>
+    </xsl:variable>
+    <xsl:call-template name="replace-string">
+      <xsl:with-param name="text" select="$ltEscaped"/>
+      <xsl:with-param name="replace" select="']]>'"/>
+      <xsl:with-param name="with" select="']]&amp;amp;gt;'"/>
+    </xsl:call-template>
+  </xsl:template>
+
+  <xsl:template name="replace-string">
+    <xsl:param name="text"/>
+    <xsl:param name="replace"/>
+    <xsl:param name="with"/>
+    <xsl:variable name="stringText" select="string($text)"/>
+    <xsl:choose>
+      <xsl:when test="contains($stringText,$replace)">
+        <xsl:value-of select="substring-before($stringText,$replace)"/>
+        <xsl:value-of select="$with"/>
+        <xsl:call-template name="replace-string">
+          <xsl:with-param name="text" select="substring-after($stringText,$replace)"/>
+          <xsl:with-param name="replace" select="$replace"/>
+          <xsl:with-param name="with" select="$with"/>
+        </xsl:call-template>
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="$stringText"/>
+      </xsl:otherwise>
+    </xsl:choose>
+  </xsl:template>
+
+</xsl:stylesheet>
