NEW - bug 210: Babel or Babel-like Community Internationalization
https://foundation.eclipse.org/infrazilla/show_bug.cgi?id=210
diff --git a/html/.cvsignore b/html/.cvsignore
new file mode 100644
index 0000000..a8dbdb8
--- /dev/null
+++ b/html/.cvsignore
@@ -0,0 +1 @@
+eclipse.org-common
diff --git a/html/callback/getLanguages.php b/html/callback/getLanguages.php
new file mode 100644
index 0000000..be1bd18
--- /dev/null
+++ b/html/callback/getLanguages.php
@@ -0,0 +1,35 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+
+if(defined(BABEL_BASE_DIR)){
+ require_once(BABEL_BASE_DIR."html/global.php");
+}else{
+ require_once("../global.php");
+}
+
+InitPage("login");
+
+$query = "select * from languages where is_active = 1";
+
+$res = mysql_query($query,$dbh);
+
+while($line = mysql_fetch_array($res, MYSQL_ASSOC)){
+ $return .= "<li><a href='?language_id=".$line['language_id']."'>".$line['iso_code']. " - ". $line['name']. "</a>";
+}
+
+?>
+
+<ul id='language-choices'>
+ Please select a langue to translate:<br>
+ <?=$return;?>
+</ul>
\ No newline at end of file
diff --git a/html/callback/getProjects.php b/html/callback/getProjects.php
new file mode 100644
index 0000000..96b5355
--- /dev/null
+++ b/html/callback/getProjects.php
@@ -0,0 +1,29 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+
+*******************************************************************************/
+require("../global.php");
+
+InitPage("login");
+
+$query = "select * from projects where is_active = 1";
+$res = mysql_query($query,$dbh);
+
+$return = '<ul id="project-choices">';
+
+while($line = mysql_fetch_array($res, MYSQL_ASSOC)){
+ $return .= '<li><a href="project_id='.$line['project_id'].'">'.$line['project_id'].'</a>';
+}
+$return .= "</ul>";
+
+print $return;
+
+?>
\ No newline at end of file
diff --git a/html/callback/setCurrentLangue.php b/html/callback/setCurrentLangue.php
new file mode 100644
index 0000000..f7b5e3b
--- /dev/null
+++ b/html/callback/setCurrentLangue.php
@@ -0,0 +1,35 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+
+
+
+if(defined(BABEL_BASE_DIR)){
+ require_once(BABEL_BASE_DIR."html/global.php");
+}else{
+ require_once("../global.php");
+}
+
+InitPage("login");
+
+$language_post = $App->getHTTPParameter("lang", "POST");
+
+if($language_post){
+ $lang = explode("=",$language_post);
+ if($lang[1] and is_numeric($lang[1])){
+ # TODO check database before setting to make sure input is valid choice
+ $_SESSION['language'] = $lang[1];
+ print getLanguagebyID($lang[1]);
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/html/callback/setCurrentProject.php b/html/callback/setCurrentProject.php
new file mode 100644
index 0000000..d133415
--- /dev/null
+++ b/html/callback/setCurrentProject.php
@@ -0,0 +1,36 @@
+<?php
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+
+
+if(defined(BABEL_BASE_DIR)){
+ require_once(BABEL_BASE_DIR."html/global.php");
+}else{
+ require_once("../global.php");
+}
+
+InitPage("login");
+
+$language_post = $App->getHTTPParameter("proj", "POST");
+
+if($language_post){
+ $lang = explode("=",$language_post);
+ if($lang[1]){
+ # TODO check database before setting to make sure input is valid choice
+ $_SESSION['project'] = $lang[1];
+ print $lang[1];
+ }else{
+ echo "bad";
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/html/global.php b/html/global.php
index f7ea0f5..f2d31b6 100644
--- a/html/global.php
+++ b/html/global.php
@@ -10,7 +10,7 @@
* Paul Colton (Aptana)- initial API and implementation
* Eclipse Foundation
*******************************************************************************/
-define('BABEL_BASE_DIR', "../");
+define('BABEL_BASE_DIR', $_SERVER['DOCUMENT_ROOT']."/../");
define('USE_PHOENIX', true);
define("COOKIE_REMEMBER", "cBABEL");
define("COOKIE_SESSION" , "sBABEL");
@@ -123,4 +123,13 @@
return $varVal;
}
+function getLanguagebyID($id){
+ global $dbh;
+ $query = "select name from languages where language_id = '".addslashes($id)."' limit 1";
+ $res = mysql_query($query,$dbh);
+ $ret = mysql_fetch_array($res, MYSQL_ASSOC);
+ return $ret['name'];
+}
+
+
?>
\ No newline at end of file
diff --git a/html/index.php b/html/index.php
index 553459b..a0da173 100644
--- a/html/index.php
+++ b/html/index.php
@@ -1,12 +1,55 @@
<?php
-
-include("global.php");
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+require("global.php");
InitPage("login");
+$pageTitle = "Babel Project";
+$pageKeywords = "translation,language,nlpack,pack,eclipse,babel";
+
include("head.php");
+
echo $User->userid;
echo $User->first_name;
-include("foot.php");
+?>
+<div id="contentArea">
+ <h1 id="page-message">Welcome to the Babel Project</h1>
+ <div id="language-area">lang</div>
+ <div id="project-area">proj</div>
+ <div id="string-area">strings</div>
+ <div id="translation-area">translation</div>
+</div>
+
+<?php
+//$_SESSION['language'] = "";
+
+if(!$_SESSION['language']){
+ //NO LANGUAGE SELECT FOR EDITING
+ ?><script>getAjaxLanguages();</script><?php
+}else{
+ //SHOW CURRENT LANGUAGE
+ ?><script>showCurrentLanguage("<?=getLanguagebyID($_SESSION['language']);?>");</script><?php
+
+ //LIST PROJECTS TO EDIT
+ if(!$_SESSION['project']){
+ ?><script>getAjaxProjects();</script><?php
+ }else{
+ ?><script>showCurrentProject("<?=$_SESSION['project'];?>");</script><?php
+ }
+}
+?>
+
+<?php
+include("foot.php");
?>
\ No newline at end of file
diff --git a/html/js/global.js b/html/js/global.js
new file mode 100644
index 0000000..07e7d7d
--- /dev/null
+++ b/html/js/global.js
@@ -0,0 +1,14 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+
+YAHOO.widget.Logger.enableBrowserConsole();
+
diff --git a/html/js/language.js b/html/js/language.js
new file mode 100644
index 0000000..8a73ebc
--- /dev/null
+++ b/html/js/language.js
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+
+function getAjaxLanguages(){
+ var callback =
+ {
+ start:function(eventType, args){
+ },
+ success: function(o) {
+ YAHOO.log(o.responseText);
+ var langDomNode = document.getElementById('language-area');
+ langDomNode.innerHTML = o.responseText;
+ YAHOO.util.Event.onAvailable("language-choices",setupSelectLanguageCB);
+ },
+ failure: function(o) {
+ YAHOO.log('failed!');
+ }
+ }
+ YAHOO.util.Connect.asyncRequest('GET', "callback/getLanguages.php", callback, null);
+}
+
+function setupSelectLanguageCB(){
+ var langs = YAHOO.util.Dom.getElementsByClassName("","li","language-choices");
+ for(var i =0; i < langs.length; i++){
+ YAHOO.util.Event.addListener(langs[i],"click",setLanguagePref);
+ }
+}
+
+function setLanguagePref(e){
+ YAHOO.util.Event.stopEvent(e);
+ var callback =
+ {
+ start:function(eventType, args){
+ },
+ success: function(o) {
+ showCurrentLanguage(o.responseText);
+ },
+ failure: function(o) {
+ YAHOO.log('failed!');
+ }
+ }
+ var target = YAHOO.util.Event.getTarget(e)
+ YAHOO.util.Connect.asyncRequest('POST', "callback/setCurrentLangue.php", callback, "lang="+target);
+}
+
+function showCurrentLanguage(curLang){
+ var display = '<h3>Current Language: '+curLang+' (<a id="change-lang" href="#">change)</h3>';
+ YAHOO.util.Event.onAvailable("change-lang",function(){ YAHOO.util.Event.addListener("change-lang","click",getAjaxLanguages); });
+
+ var langDomNode = document.getElementById('language-area');
+ langDomNode.innerHTML = display;
+}
diff --git a/html/js/project.js b/html/js/project.js
new file mode 100644
index 0000000..f09cdc0
--- /dev/null
+++ b/html/js/project.js
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Eclipse Foundation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Paul Colton (Aptana)- initial API and implementation
+ * Eclipse Foundation
+*******************************************************************************/
+
+function getAjaxProjects(){
+ var callback =
+ {
+ start:function(eventType, args){
+ },
+ success: function(o) {
+ YAHOO.log(o.responseText);
+ var domNode = document.getElementById('project-area');
+ domNode.innerHTML = o.responseText;
+ YAHOO.util.Event.onAvailable("project-choices",setupSelectProjectCB);
+ },
+ failure: function(o) {
+ YAHOO.log('failed!');
+ }
+ }
+ YAHOO.util.Connect.asyncRequest('GET', "callback/getProjects.php", callback, null);
+}
+
+function setupSelectProjectCB(){
+ var langs = YAHOO.util.Dom.getElementsByClassName("","li","project-choices");
+ for(var i =0; i < langs.length; i++){
+ YAHOO.log(langs[i].innerHTML);
+ YAHOO.util.Event.addListener(langs[i],"click",setProjectPref);
+ }
+}
+
+function setProjectPref(e){
+ YAHOO.util.Event.stopEvent(e);
+ var callback =
+ {
+ start:function(eventType, args){
+ },
+ success: function(o) {
+ showCurrentProject(o.responseText);
+ },
+ failure: function(o) {
+ YAHOO.log('failed!');
+ }
+ }
+ var target = YAHOO.util.Event.getTarget(e)
+ YAHOO.log(target)
+ YAHOO.util.Connect.asyncRequest('POST', "callback/setCurrentProject.php", callback, "proj="+target);
+}
+
+function showCurrentProject(curProj){
+ var display = '<h3>Current Project: '+curProj+' (<a id="change-proj" href="#">change)</h3>';
+ YAHOO.util.Event.onAvailable("change-lang",function(){ YAHOO.util.Event.addListener("change-proj","click",getAjaxProjects); });
+
+ var langDomNode = document.getElementById('project-area');
+ langDomNode.innerHTML = display;
+}
diff --git a/html/js/yui2.3.1/connection/connection.js b/html/js/yui2.3.1/connection/connection.js
new file mode 100644
index 0000000..1fdcfa9
--- /dev/null
+++ b/html/js/yui2.3.1/connection/connection.js
@@ -0,0 +1,1357 @@
+/*
+Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.3.1
+*/
+/**
+ * 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 you create.
+ *
+ * @namespace YAHOO.util
+ * @module connection
+ * @requires yahoo
+ * @requires event
+ */
+
+/**
+ * The Connection Manager singleton provides methods for creating and managing
+ * asynchronous transactions.
+ *
+ * @class Connect
+ */
+
+YAHOO.util.Connect =
+{
+ /**
+ * @description Array of MSFT ActiveX ids for XMLHttpRequest.
+ * @property _msxml_progid
+ * @private
+ * @static
+ * @type array
+ */
+ _msxml_progid:[
+ 'Microsoft.XMLHTTP',
+ 'MSXML2.XMLHTTP.3.0',
+ 'MSXML2.XMLHTTP'
+ ],
+
+ /**
+ * @description Object literal of HTTP header(s)
+ * @property _http_header
+ * @private
+ * @static
+ * @type object
+ */
+ _http_headers:{},
+
+ /**
+ * @description Determines if HTTP headers are set.
+ * @property _has_http_headers
+ * @private
+ * @static
+ * @type boolean
+ */
+ _has_http_headers:false,
+
+ /**
+ * @description Determines if a default header of
+ * Content-Type of 'application/x-www-form-urlencoded'
+ * will be added to any client HTTP headers sent for POST
+ * transactions.
+ * @property _use_default_post_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _use_default_post_header:true,
+
+ /**
+ * @description The default header used for POST transactions.
+ * @property _default_post_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _default_post_header:'application/x-www-form-urlencoded; charset=UTF-8',
+
+ /**
+ * @description The default header used for transactions involving the
+ * use of HTML forms.
+ * @property _default_form_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _default_form_header:'application/x-www-form-urlencoded',
+
+ /**
+ * @description Determines if a default header of
+ * 'X-Requested-With: XMLHttpRequest'
+ * will be added to each transaction.
+ * @property _use_default_xhr_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _use_default_xhr_header:true,
+
+ /**
+ * @description The default header value for the label
+ * "X-Requested-With". This is sent with each
+ * transaction, by default, to identify the
+ * request as being made by YUI Connection Manager.
+ * @property _default_xhr_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _default_xhr_header:'XMLHttpRequest',
+
+ /**
+ * @description Determines if custom, default headers
+ * are set for each transaction.
+ * @property _has_default_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _has_default_headers:true,
+
+ /**
+ * @description Determines if custom, default headers
+ * are set for each transaction.
+ * @property _has_default_header
+ * @private
+ * @static
+ * @type boolean
+ */
+ _default_headers:{},
+
+ /**
+ * @description Property modified by setForm() to determine if the data
+ * should be submitted as an HTML form.
+ * @property _isFormSubmit
+ * @private
+ * @static
+ * @type boolean
+ */
+ _isFormSubmit:false,
+
+ /**
+ * @description Property modified by setForm() to determine if a file(s)
+ * upload is expected.
+ * @property _isFileUpload
+ * @private
+ * @static
+ * @type boolean
+ */
+ _isFileUpload:false,
+
+ /**
+ * @description Property modified by setForm() to set a reference to the HTML
+ * form node if the desired action is file upload.
+ * @property _formNode
+ * @private
+ * @static
+ * @type object
+ */
+ _formNode:null,
+
+ /**
+ * @description Property modified by setForm() to set the HTML form data
+ * for each transaction.
+ * @property _sFormData
+ * @private
+ * @static
+ * @type string
+ */
+ _sFormData:null,
+
+ /**
+ * @description Collection of polling references to the polling mechanism in handleReadyState.
+ * @property _poll
+ * @private
+ * @static
+ * @type object
+ */
+ _poll:{},
+
+ /**
+ * @description Queue of timeout values for each transaction callback with a defined timeout value.
+ * @property _timeOut
+ * @private
+ * @static
+ * @type object
+ */
+ _timeOut:{},
+
+ /**
+ * @description The polling frequency, in milliseconds, for HandleReadyState.
+ * when attempting to determine a transaction's XHR readyState.
+ * The default is 50 milliseconds.
+ * @property _polling_interval
+ * @private
+ * @static
+ * @type int
+ */
+ _polling_interval:50,
+
+ /**
+ * @description A transaction counter that increments the transaction id for each transaction.
+ * @property _transaction_id
+ * @private
+ * @static
+ * @type int
+ */
+ _transaction_id:0,
+
+ /**
+ * @description Tracks the name-value pair of the "clicked" submit button if multiple submit
+ * buttons are present in an HTML form; and, if YAHOO.util.Event is available.
+ * @property _submitElementValue
+ * @private
+ * @static
+ * @type string
+ */
+ _submitElementValue:null,
+
+ /**
+ * @description Determines whether YAHOO.util.Event is available and returns true or false.
+ * If true, an event listener is bound at the document level to trap click events that
+ * resolve to a target type of "Submit". This listener will enable setForm() to determine
+ * the clicked "Submit" value in a multi-Submit button, HTML form.
+ * @property _hasSubmitListener
+ * @private
+ * @static
+ */
+ _hasSubmitListener:(function()
+ {
+ if(YAHOO.util.Event){
+ YAHOO.util.Event.addListener(
+ document,
+ 'click',
+ function(e){
+ try
+ {
+ var obj = YAHOO.util.Event.getTarget(e);
+ if(obj.type.toLowerCase() == 'submit'){
+ YAHOO.util.Connect._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value);
+ }
+ }
+ catch(e){}
+ });
+ return true;
+ }
+ return false;
+ })(),
+
+ /**
+ * @description Custom event that fires at the start of a transaction
+ * @property startEvent
+ * @private
+ * @static
+ * @type CustomEvent
+ */
+ startEvent: new YAHOO.util.CustomEvent('start'),
+
+ /**
+ * @description Custom event that fires when a transaction response has completed.
+ * @property completeEvent
+ * @private
+ * @static
+ * @type CustomEvent
+ */
+ completeEvent: new YAHOO.util.CustomEvent('complete'),
+
+ /**
+ * @description Custom event that fires when handleTransactionResponse() determines a
+ * response in the HTTP 2xx range.
+ * @property successEvent
+ * @private
+ * @static
+ * @type CustomEvent
+ */
+ successEvent: new YAHOO.util.CustomEvent('success'),
+
+ /**
+ * @description Custom event that fires when handleTransactionResponse() determines a
+ * response in the HTTP 4xx/5xx range.
+ * @property failureEvent
+ * @private
+ * @static
+ * @type CustomEvent
+ */
+ failureEvent: new YAHOO.util.CustomEvent('failure'),
+
+ /**
+ * @description Custom event that fires when handleTransactionResponse() determines a
+ * response in the HTTP 4xx/5xx range.
+ * @property failureEvent
+ * @private
+ * @static
+ * @type CustomEvent
+ */
+ uploadEvent: new YAHOO.util.CustomEvent('upload'),
+
+ /**
+ * @description Custom event that fires when a transaction is successfully aborted.
+ * @property abortEvent
+ * @private
+ * @static
+ * @type CustomEvent
+ */
+ abortEvent: new YAHOO.util.CustomEvent('abort'),
+
+ /**
+ * @description A reference table that maps callback custom events members to its specific
+ * event name.
+ * @property _customEvents
+ * @private
+ * @static
+ * @type object
+ */
+ _customEvents:
+ {
+ onStart:['startEvent', 'start'],
+ onComplete:['completeEvent', 'complete'],
+ onSuccess:['successEvent', 'success'],
+ onFailure:['failureEvent', 'failure'],
+ onUpload:['uploadEvent', 'upload'],
+ onAbort:['abortEvent', 'abort']
+ },
+
+ /**
+ * @description 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.
+ * @method setProgId
+ * @public
+ * @static
+ * @param {string} id The ActiveX id to be added to initialize the XHR object.
+ * @return void
+ */
+ setProgId:function(id)
+ {
+ this._msxml_progid.unshift(id);
+ },
+
+ /**
+ * @description Member to override the default POST header.
+ * @method setDefaultPostHeader
+ * @public
+ * @static
+ * @param {boolean} b Set and use default header - true or false .
+ * @return void
+ */
+ setDefaultPostHeader:function(b)
+ {
+ if(typeof b == 'string'){
+ this._default_post_header = b;
+ }
+ else if(typeof b == 'boolean'){
+ this._use_default_post_header = b;
+ }
+ },
+
+ /**
+ * @description Member to override the default transaction header..
+ * @method setDefaultXhrHeader
+ * @public
+ * @static
+ * @param {boolean} b Set and use default header - true or false .
+ * @return void
+ */
+ setDefaultXhrHeader:function(b)
+ {
+ if(typeof b == 'string'){
+ this._default_xhr_header = b;
+ }
+ else{
+ this._use_default_xhr_header = b;
+ }
+ },
+
+ /**
+ * @description Member to modify the default polling interval.
+ * @method setPollingInterval
+ * @public
+ * @static
+ * @param {int} i The polling interval in milliseconds.
+ * @return void
+ */
+ setPollingInterval:function(i)
+ {
+ if(typeof i == 'number' && isFinite(i)){
+ this._polling_interval = i;
+ }
+ },
+
+ /**
+ * @description Instantiates a XMLHttpRequest object and returns an object with two properties:
+ * the XMLHttpRequest instance and the transaction id.
+ * @method createXhrObject
+ * @private
+ * @static
+ * @param {int} transactionId Property containing the transaction id for this transaction.
+ * @return 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 tId 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 conn and tId properties
+ obj = { conn:http, tId:transactionId };
+ break;
+ }
+ catch(e){}
+ }
+ }
+ finally
+ {
+ return obj;
+ }
+ },
+
+ /**
+ * @description This method is called by asyncRequest to create a
+ * valid connection object for the transaction. It also passes a
+ * transaction id and increments the transaction id counter.
+ * @method getConnectionObject
+ * @private
+ * @static
+ * @return {object}
+ */
+ getConnectionObject:function(isFileUpload)
+ {
+ var o;
+ var tId = this._transaction_id;
+
+ try
+ {
+ if(!isFileUpload){
+ o = this.createXhrObject(tId);
+ }
+ else{
+ o = {};
+ o.tId = tId;
+ o.isUpload = true;
+ }
+
+ if(o){
+ this._transaction_id++;
+ }
+ }
+ catch(e){}
+ finally
+ {
+ return o;
+ }
+ },
+
+ /**
+ * @description Method for initiating an asynchronous request via the XHR object.
+ * @method asyncRequest
+ * @public
+ * @static
+ * @param {string} method HTTP transaction method
+ * @param {string} uri Fully qualified path of resource
+ * @param {callback} callback User-defined callback function or object
+ * @param {string} postData POST body
+ * @return {object} Returns the connection object
+ */
+ asyncRequest:function(method, uri, callback, postData)
+ {
+ var o = (this._isFileUpload)?this.getConnectionObject(true):this.getConnectionObject();
+
+ if(!o){
+ return null;
+ }
+ else{
+
+ // Intialize any transaction-specific custom events, if provided.
+ if(callback && callback.customevents){
+ this.initCustomEvents(o, callback);
+ }
+
+ if(this._isFormSubmit){
+ if(this._isFileUpload){
+ this.uploadFile(o, callback, uri, postData);
+ return o;
+ }
+
+ // If the specified HTTP method is GET, setForm() will return an
+ // encoded string that is concatenated to the uri to
+ // create a querystring.
+ if(method.toUpperCase() == 'GET'){
+ if(this._sFormData.length !== 0){
+ // If the URI already contains a querystring, append an ampersand
+ // and then concatenate _sFormData to the URI.
+ uri += ((uri.indexOf('?') == -1)?'?':'&') + this._sFormData;
+ }
+ else{
+ uri += "?" + this._sFormData;
+ }
+ }
+ else if(method.toUpperCase() == 'POST'){
+ // If POST data exist in addition to the HTML form data,
+ // it will be concatenated to the form data.
+ postData = postData?this._sFormData + "&" + postData:this._sFormData;
+ }
+ }
+
+ o.conn.open(method, uri, true);
+
+ // Each transaction will automatically include a custom header of
+ // "X-Requested-With: XMLHttpRequest" to identify the request as
+ // having originated from Connection Manager.
+ if(this._use_default_xhr_header){
+ if(!this._default_headers['X-Requested-With']){
+ this.initHeader('X-Requested-With', this._default_xhr_header, true);
+ }
+ }
+
+ if(this._isFormSubmit == false && this._use_default_post_header){
+ this.initHeader('Content-Type', this._default_post_header);
+ }
+
+ if(this._has_default_headers || this._has_http_headers){
+ this.setHeader(o);
+ }
+
+ this.handleReadyState(o, callback);
+ o.conn.send(postData || null);
+
+ // Fire global custom event -- startEvent
+ this.startEvent.fire(o);
+
+ if(o.startEvent){
+ // Fire transaction custom event -- startEvent
+ o.startEvent.fire(o);
+ }
+
+ return o;
+ }
+ },
+
+ /**
+ * @description This method creates and subscribes custom events,
+ * specific to each transaction
+ * @method initCustomEvents
+ * @private
+ * @static
+ * @param {object} o The connection object
+ * @param {callback} callback The user-defined callback object
+ * @return {void}
+ */
+ initCustomEvents:function(o, callback)
+ {
+ // Enumerate through callback.customevents members and bind/subscribe
+ // events that match in the _customEvents table.
+ for(var prop in callback.customevents){
+ if(this._customEvents[prop][0]){
+ // Create the custom event
+ o[this._customEvents[prop][0]] = new YAHOO.util.CustomEvent(this._customEvents[prop][1], (callback.scope)?callback.scope:null);
+
+ // Subscribe the custom event
+ o[this._customEvents[prop][0]].subscribe(callback.customevents[prop]);
+ }
+ }
+ },
+
+ /**
+ * @description 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.
+ * @method handleReadyState
+ * @private
+ * @static
+ * @param {object} o The connection object
+ * @param {callback} callback The user-defined callback object
+ * @return {void}
+ */
+
+ handleReadyState:function(o, callback)
+
+ {
+ var oConn = this;
+
+ if(callback && callback.timeout){
+ this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+ }
+
+ this._poll[o.tId] = window.setInterval(
+ function(){
+ if(o.conn && o.conn.readyState === 4){
+
+ // Clear the polling interval for the transaction
+ // and remove the reference from _poll.
+ window.clearInterval(oConn._poll[o.tId]);
+ delete oConn._poll[o.tId];
+
+ if(callback && callback.timeout){
+ window.clearTimeout(oConn._timeOut[o.tId]);
+ delete oConn._timeOut[o.tId];
+ }
+
+ // Fire global custom event -- completeEvent
+ oConn.completeEvent.fire(o);
+
+ if(o.completeEvent){
+ // Fire transaction custom event -- completeEvent
+ o.completeEvent.fire(o);
+ }
+
+ oConn.handleTransactionResponse(o, callback);
+ }
+ }
+ ,this._polling_interval);
+ },
+
+ /**
+ * @description This method attempts to interpret the server response and
+ * determine whether the transaction was successful, or if an error or
+ * exception was encountered.
+ * @method handleTransactionResponse
+ * @private
+ * @static
+ * @param {object} o The connection object
+ * @param {object} callback The user-defined callback object
+ * @param {boolean} isAbort Determines if the transaction was terminated via abort().
+ * @return {void}
+ */
+ handleTransactionResponse:function(o, callback, isAbort)
+ {
+
+ var httpStatus, responseObject;
+
+ try
+ {
+ if(o.conn.status !== undefined && o.conn.status !== 0){
+ httpStatus = o.conn.status;
+ }
+ else{
+ httpStatus = 13030;
+ }
+ }
+ catch(e){
+
+ // 13030 is a custom code to indicate the condition -- in Mozilla/FF --
+ // when the XHR object's status and statusText properties are
+ // unavailable, and a query attempt throws an exception.
+ httpStatus = 13030;
+ }
+
+ if(httpStatus >= 200 && httpStatus < 300 || httpStatus === 1223){
+ responseObject = this.createResponseObject(o, (callback && callback.argument)?callback.argument:undefined);
+ if(callback){
+ if(callback.success){
+ if(!callback.scope){
+ callback.success(responseObject);
+ }
+ else{
+ // If a scope property is defined, the callback will be fired from
+ // the context of the object.
+ callback.success.apply(callback.scope, [responseObject]);
+ }
+ }
+ }
+
+ // Fire global custom event -- successEvent
+ this.successEvent.fire(responseObject);
+
+ if(o.successEvent){
+ // Fire transaction custom event -- successEvent
+ o.successEvent.fire(responseObject);
+ }
+ }
+ else{
+ switch(httpStatus){
+ // The following cases are wininet.dll error codes that may be encountered.
+ case 12002: // Server timeout
+ case 12029: // 12029 to 12031 correspond to dropped connections.
+ case 12030:
+ case 12031:
+ case 12152: // Connection closed by server.
+ case 13030: // See above comments for variable status.
+ responseObject = this.createExceptionObject(o.tId, (callback && callback.argument)?callback.argument:undefined, (isAbort?isAbort:false));
+ if(callback){
+ if(callback.failure){
+ if(!callback.scope){
+ callback.failure(responseObject);
+ }
+ else{
+ callback.failure.apply(callback.scope, [responseObject]);
+ }
+ }
+ }
+
+ break;
+ default:
+ responseObject = this.createResponseObject(o, (callback && callback.argument)?callback.argument:undefined);
+ if(callback){
+ if(callback.failure){
+ if(!callback.scope){
+ callback.failure(responseObject);
+ }
+ else{
+ callback.failure.apply(callback.scope, [responseObject]);
+ }
+ }
+ }
+ }
+
+ // Fire global custom event -- failureEvent
+ this.failureEvent.fire(responseObject);
+
+ if(o.failureEvent){
+ // Fire transaction custom event -- failureEvent
+ o.failureEvent.fire(responseObject);
+ }
+
+ }
+
+ this.releaseObject(o);
+ responseObject = null;
+ },
+
+ /**
+ * @description This method evaluates the server response, creates and returns the results via
+ * its properties. Success and failure cases will differ in the response
+ * object's property values.
+ * @method createResponseObject
+ * @private
+ * @static
+ * @param {object} o The connection object
+ * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
+ * @return {object}
+ */
+ createResponseObject:function(o, callbackArg)
+ {
+ var obj = {};
+ var headerObj = {};
+
+ try
+ {
+ var headerStr = o.conn.getAllResponseHeaders();
+ var header = headerStr.split('\n');
+ for(var i=0; i<header.length; i++){
+ var delimitPos = header[i].indexOf(':');
+ if(delimitPos != -1){
+ headerObj[header[i].substring(0,delimitPos)] = header[i].substring(delimitPos+2);
+ }
+ }
+ }
+ catch(e){}
+
+ obj.tId = o.tId;
+ // Normalize IE's response to HTTP 204 when Win error 1223.
+ obj.status = (o.conn.status == 1223)?204:o.conn.status;
+ // Normalize IE's statusText to "No Content" instead of "Unknown".
+ obj.statusText = (o.conn.status == 1223)?"No Content":o.conn.statusText;
+ obj.getResponseHeader = headerObj;
+ obj.getAllResponseHeaders = headerStr;
+ obj.responseText = o.conn.responseText;
+ obj.responseXML = o.conn.responseXML;
+
+ if(typeof callbackArg !== undefined){
+ obj.argument = callbackArg;
+ }
+
+ return obj;
+ },
+
+ /**
+ * @description 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 failure callback will be fired and this specific condition can be identified
+ * by a status property value of 0.
+ *
+ * If an abort was successful, the status property will report a value of -1.
+ *
+ * @method createExceptionObject
+ * @private
+ * @static
+ * @param {int} tId The Transaction Id
+ * @param {callbackArg} callbackArg The user-defined argument or arguments to be passed to the callback
+ * @param {boolean} isAbort Determines if the exception case is caused by a transaction abort
+ * @return {object}
+ */
+ createExceptionObject:function(tId, callbackArg, isAbort)
+ {
+ var COMM_CODE = 0;
+ var COMM_ERROR = 'communication failure';
+ var ABORT_CODE = -1;
+ var ABORT_ERROR = 'transaction aborted';
+
+ var obj = {};
+
+ obj.tId = tId;
+ if(isAbort){
+ obj.status = ABORT_CODE;
+ obj.statusText = ABORT_ERROR;
+ }
+ else{
+ obj.status = COMM_CODE;
+ obj.statusText = COMM_ERROR;
+ }
+
+ if(callbackArg){
+ obj.argument = callbackArg;
+ }
+
+ return obj;
+ },
+
+ /**
+ * @description Method that initializes the custom HTTP headers for the each transaction.
+ * @method initHeader
+ * @public
+ * @static
+ * @param {string} label The HTTP header label
+ * @param {string} value The HTTP header value
+ * @param {string} isDefault Determines if the specific header is a default header
+ * automatically sent with each transaction.
+ * @return {void}
+ */
+ initHeader:function(label, value, isDefault)
+ {
+ var headerObj = (isDefault)?this._default_headers:this._http_headers;
+ headerObj[label] = value;
+
+ if(isDefault){
+ this._has_default_headers = true;
+ }
+ else{
+ this._has_http_headers = true;
+ }
+ },
+
+
+ /**
+ * @description Accessor that sets the HTTP headers for each transaction.
+ * @method setHeader
+ * @private
+ * @static
+ * @param {object} o The connection object for the transaction.
+ * @return {void}
+ */
+ setHeader:function(o)
+ {
+ if(this._has_default_headers){
+ for(var prop in this._default_headers){
+ if(YAHOO.lang.hasOwnProperty(this._default_headers, prop)){
+ o.conn.setRequestHeader(prop, this._default_headers[prop]);
+ }
+ }
+ }
+
+ if(this._has_http_headers){
+ for(var prop in this._http_headers){
+ if(YAHOO.lang.hasOwnProperty(this._http_headers, prop)){
+ o.conn.setRequestHeader(prop, this._http_headers[prop]);
+ }
+ }
+ delete this._http_headers;
+
+ this._http_headers = {};
+ this._has_http_headers = false;
+ }
+ },
+
+ /**
+ * @description Resets the default HTTP headers object
+ * @method resetDefaultHeaders
+ * @public
+ * @static
+ * @return {void}
+ */
+ resetDefaultHeaders:function(){
+ delete this._default_headers;
+ this._default_headers = {};
+ this._has_default_headers = false;
+ },
+
+ /**
+ * @description This method assembles the form label and value pairs and
+ * constructs an encoded string.
+ * asyncRequest() will automatically initialize the transaction with a
+ * a HTTP header Content-Type of application/x-www-form-urlencoded.
+ * @method setForm
+ * @public
+ * @static
+ * @param {string || object} form id or name attribute, or form object.
+ * @param {boolean} optional enable file upload.
+ * @param {boolean} optional enable file upload over SSL in IE only.
+ * @return {string} string of the HTML form field name and value pairs..
+ */
+ setForm:function(formId, isUpload, secureUri)
+ {
+ this.resetFormState();
+
+ var oForm;
+ if(typeof formId == 'string'){
+ // Determine if the argument is a form id or a form name.
+ // Note form name usage is deprecated by supported
+ // here for legacy reasons.
+ oForm = (document.getElementById(formId) || document.forms[formId]);
+ }
+ else if(typeof formId == 'object'){
+ // Treat argument as an HTML form object.
+ oForm = formId;
+ }
+ else{
+ return;
+ }
+
+ // If the isUpload argument is true, setForm will call createFrame to initialize
+ // an iframe as the form target.
+ //
+ // The argument secureURI is also required by IE in SSL environments
+ // where the secureURI string is a fully qualified HTTP path, used to set the source
+ // of the iframe, to a stub resource in the same domain.
+ if(isUpload){
+
+ // Create iframe in preparation for file upload.
+ var io = this.createFrame(secureUri?secureUri:null);
+ // Set form reference and file upload properties to true.
+ this._isFormSubmit = true;
+ this._isFileUpload = true;
+ this._formNode = oForm;
+
+ return;
+
+ }
+
+ var oElement, oName, oValue, oDisabled;
+ var hasSubmit = false;
+
+ // 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];
+ oDisabled = oForm.elements[i].disabled;
+ oName = oForm.elements[i].name;
+ oValue = oForm.elements[i].value;
+
+ // Do not submit fields that are disabled or
+ // do not have a name attribute value.
+ if(!oDisabled && oName)
+ {
+ switch(oElement.type)
+ {
+ case 'select-one':
+ case 'select-multiple':
+ for(var j=0; j<oElement.options.length; j++){
+ if(oElement.options[j].selected){
+ if(window.ActiveXObject){
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
+ }
+ else{
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
+ }
+ }
+ }
+ break;
+ case 'radio':
+ case 'checkbox':
+ if(oElement.checked){
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+ }
+ break;
+ case 'file':
+ // stub case as XMLHttpRequest will only send the file path as a string.
+ case undefined:
+ // stub case for fieldset element which returns undefined.
+ case 'reset':
+ // stub case for input type reset button.
+ case 'button':
+ // stub case for input type button elements.
+ break;
+ case 'submit':
+ if(hasSubmit === false){
+ if(this._hasSubmitListener && this._submitElementValue){
+ this._sFormData += this._submitElementValue + '&';
+ }
+ else{
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+ }
+
+ hasSubmit = true;
+ }
+ break;
+ default:
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+ }
+ }
+ }
+
+ this._isFormSubmit = true;
+ this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+
+
+ this.initHeader('Content-Type', this._default_form_header);
+
+ return this._sFormData;
+ },
+
+ /**
+ * @description Resets HTML form properties when an HTML form or HTML form
+ * with file upload transaction is sent.
+ * @method resetFormState
+ * @private
+ * @static
+ * @return {void}
+ */
+ resetFormState:function(){
+ this._isFormSubmit = false;
+ this._isFileUpload = false;
+ this._formNode = null;
+ this._sFormData = "";
+ },
+
+ /**
+ * @description Creates an iframe to be used for form file uploads. It is remove from the
+ * document upon completion of the upload transaction.
+ * @method createFrame
+ * @private
+ * @static
+ * @param {string} optional qualified path of iframe resource for SSL in IE.
+ * @return {void}
+ */
+ createFrame:function(secureUri){
+
+ // IE does not allow the setting of id and name attributes as object
+ // properties via createElement(). A different iframe creation
+ // pattern is required for IE.
+ var frameId = 'yuiIO' + this._transaction_id;
+ var io;
+ if(window.ActiveXObject){
+ io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
+
+ // IE will throw a security exception in an SSL environment if the
+ // iframe source is undefined.
+ if(typeof secureUri == 'boolean'){
+ io.src = 'javascript:false';
+ }
+ else if(typeof secureURI == 'string'){
+ // Deprecated
+ io.src = secureUri;
+ }
+ }
+ else{
+ io = document.createElement('iframe');
+ io.id = frameId;
+ io.name = frameId;
+ }
+
+ io.style.position = 'absolute';
+ io.style.top = '-1000px';
+ io.style.left = '-1000px';
+
+ document.body.appendChild(io);
+ },
+
+ /**
+ * @description Parses the POST data and creates hidden form elements
+ * for each key-value, and appends them to the HTML form object.
+ * @method appendPostData
+ * @private
+ * @static
+ * @param {string} postData The HTTP POST data
+ * @return {array} formElements Collection of hidden fields.
+ */
+ appendPostData:function(postData)
+ {
+ var formElements = [];
+ var postMessage = postData.split('&');
+ for(var i=0; i < postMessage.length; i++){
+ var delimitPos = postMessage[i].indexOf('=');
+ if(delimitPos != -1){
+ formElements[i] = document.createElement('input');
+ formElements[i].type = 'hidden';
+ formElements[i].name = postMessage[i].substring(0,delimitPos);
+ formElements[i].value = postMessage[i].substring(delimitPos+1);
+ this._formNode.appendChild(formElements[i]);
+ }
+ }
+
+ return formElements;
+ },
+
+ /**
+ * @description Uploads HTML form, inclusive of files/attachments, using the
+ * iframe created in createFrame to facilitate the transaction.
+ * @method uploadFile
+ * @private
+ * @static
+ * @param {int} id The transaction id.
+ * @param {object} callback User-defined callback object.
+ * @param {string} uri Fully qualified path of resource.
+ * @param {string} postData POST data to be submitted in addition to HTML form.
+ * @return {void}
+ */
+ uploadFile:function(o, callback, uri, postData){
+
+ // Each iframe has an id prefix of "yuiIO" followed
+ // by the unique transaction id.
+ var frameId = 'yuiIO' + o.tId;
+ var uploadEncoding = 'multipart/form-data';
+ var io = document.getElementById(frameId);
+ var oConn = this;
+
+ // Track original HTML form attribute values.
+ var rawFormAttributes =
+ {
+ action:this._formNode.getAttribute('action'),
+ method:this._formNode.getAttribute('method'),
+ target:this._formNode.getAttribute('target')
+ };
+
+ // Initialize the HTML form properties in case they are
+ // not defined in the HTML form.
+ this._formNode.setAttribute('action', uri);
+ this._formNode.setAttribute('method', 'POST');
+ this._formNode.setAttribute('target', frameId);
+
+ if(this._formNode.encoding){
+ // IE does not respect property enctype for HTML forms.
+ // Instead it uses the property - "encoding".
+ this._formNode.setAttribute('encoding', uploadEncoding);
+ }
+ else{
+ this._formNode.setAttribute('enctype', uploadEncoding);
+ }
+
+ if(postData){
+ var oElements = this.appendPostData(postData);
+ }
+
+ // Start file upload.
+ this._formNode.submit();
+
+ // Fire global custom event -- startEvent
+ this.startEvent.fire(o);
+
+ if(o.startEvent){
+ // Fire transaction custom event -- startEvent
+ o.startEvent.fire(o);
+ }
+
+ // Start polling if a callback is present and the timeout
+ // property has been defined.
+ if(callback && callback.timeout){
+ this._timeOut[o.tId] = window.setTimeout(function(){ oConn.abort(o, callback, true); }, callback.timeout);
+ }
+
+ // Remove HTML elements created by appendPostData
+ if(oElements && oElements.length > 0){
+ for(var i=0; i < oElements.length; i++){
+ this._formNode.removeChild(oElements[i]);
+ }
+ }
+
+ // Restore HTML form attributes to their original
+ // values prior to file upload.
+ for(var prop in rawFormAttributes){
+ if(YAHOO.lang.hasOwnProperty(rawFormAttributes, prop)){
+ if(rawFormAttributes[prop]){
+ this._formNode.setAttribute(prop, rawFormAttributes[prop]);
+ }
+ else{
+ this._formNode.removeAttribute(prop);
+ }
+ }
+ }
+
+ // Reset HTML form state properties.
+ this.resetFormState();
+
+ // Create the upload callback handler that fires when the iframe
+ // receives the load event. Subsequently, the event handler is detached
+ // and the iframe removed from the document.
+ var uploadCallback = function()
+ {
+ if(callback && callback.timeout){
+ window.clearTimeout(oConn._timeOut[o.tId]);
+ delete oConn._timeOut[o.tId];
+ }
+
+ // Fire global custom event -- completeEvent
+ oConn.completeEvent.fire(o);
+
+ if(o.completeEvent){
+ // Fire transaction custom event -- completeEvent
+ o.completeEvent.fire(o);
+ }
+
+ var obj = {};
+ obj.tId = o.tId;
+ obj.argument = callback.argument;
+
+ try
+ {
+ // responseText and responseXML will be populated with the same data from the iframe.
+ // Since the HTTP headers cannot be read from the iframe
+ obj.responseText = io.contentWindow.document.body?io.contentWindow.document.body.innerHTML:io.contentWindow.document.documentElement.textContent;
+ obj.responseXML = io.contentWindow.document.XMLDocument?io.contentWindow.document.XMLDocument:io.contentWindow.document;
+ }
+ catch(e){}
+
+ if(callback && callback.upload){
+ if(!callback.scope){
+ callback.upload(obj);
+ }
+ else{
+ callback.upload.apply(callback.scope, [obj]);
+ }
+ }
+
+ // Fire global custom event -- uploadEvent
+ oConn.uploadEvent.fire(obj);
+
+ if(o.uploadEvent){
+ // Fire transaction custom event -- uploadEvent
+ o.uploadEvent.fire(obj);
+ }
+
+ YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+
+ setTimeout(
+ function(){
+ document.body.removeChild(io);
+ oConn.releaseObject(o);
+ }, 100);
+ };
+
+ // Bind the onload handler to the iframe to detect the file upload response.
+ YAHOO.util.Event.addListener(io, "load", uploadCallback);
+ },
+
+ /**
+ * @description Method to terminate a transaction, if it has not reached readyState 4.
+ * @method abort
+ * @public
+ * @static
+ * @param {object} o The connection object returned by asyncRequest.
+ * @param {object} callback User-defined callback object.
+ * @param {string} isTimeout boolean to indicate if abort resulted from a callback timeout.
+ * @return {boolean}
+ */
+ abort:function(o, callback, isTimeout)
+ {
+ var abortStatus;
+
+ if(o.conn){
+ if(this.isCallInProgress(o)){
+ // Issue abort request
+ o.conn.abort();
+
+ window.clearInterval(this._poll[o.tId]);
+ delete this._poll[o.tId];
+
+ if(isTimeout){
+ window.clearTimeout(this._timeOut[o.tId]);
+ delete this._timeOut[o.tId];
+ }
+
+ abortStatus = true;
+ }
+ }
+ else if(o.isUpload === true){
+ var frameId = 'yuiIO' + o.tId;
+ var io = document.getElementById(frameId);
+
+ if(io){
+ // Remove the event listener from the iframe.
+ YAHOO.util.Event.removeListener(io, "load", uploadCallback);
+ // Destroy the iframe facilitating the transaction.
+ document.body.removeChild(io);
+
+ if(isTimeout){
+ window.clearTimeout(this._timeOut[o.tId]);
+ delete this._timeOut[o.tId];
+ }
+
+ abortStatus = true;
+ }
+ }
+ else{
+ abortStatus = false;
+ }
+
+ if(abortStatus === true){
+ // Fire global custom event -- abortEvent
+ this.abortEvent.fire(o);
+
+ if(o.abortEvent){
+ // Fire transaction custom event -- abortEvent
+ o.abortEvent.fire(o);
+ }
+
+ this.handleTransactionResponse(o, callback, true);
+ }
+
+ return abortStatus;
+ },
+
+ /**
+ * @description Determines if the transaction is still being processed.
+ * @method isCallInProgress
+ * @public
+ * @static
+ * @param {object} o The connection object returned by asyncRequest
+ * @return {boolean}
+ */
+ isCallInProgress:function(o)
+ {
+ // if the XHR object assigned to the transaction has not been dereferenced,
+ // then check its readyState status. Otherwise, return false.
+ if(o && o.conn){
+ return o.conn.readyState !== 4 && o.conn.readyState !== 0;
+ }
+ else if(o && o.isUpload === true){
+ var frameId = 'yuiIO' + o.tId;
+ return document.getElementById(frameId)?true:false;
+ }
+ else{
+ return false;
+ }
+ },
+
+ /**
+ * @description Dereference the XHR instance and the connection object after the transaction is completed.
+ * @method releaseObject
+ * @private
+ * @static
+ * @param {object} o The connection object
+ * @return {void}
+ */
+ releaseObject:function(o)
+ {
+ //dereference the XHR instance.
+ if(o.conn){
+ o.conn = null;
+ }
+ //dereference the connection object.
+ o = null;
+ }
+};
+
+YAHOO.register("connection", YAHOO.util.Connect, {version: "2.3.1", build: "541"});
\ No newline at end of file
diff --git a/html/js/yui2.3.1/dom/dom.js b/html/js/yui2.3.1/dom/dom.js
new file mode 100644
index 0000000..0c7146e
--- /dev/null
+++ b/html/js/yui2.3.1/dom/dom.js
@@ -0,0 +1,1217 @@
+/*
+Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.3.1
+*/
+/**
+ * The dom module provides helper methods for manipulating Dom elements.
+ * @module dom
+ *
+ */
+
+(function() {
+ var Y = YAHOO.util, // internal shorthand
+ getStyle, // for load time browser branching
+ setStyle, // ditto
+ id_counter = 0, // for use with generateId
+ propertyCache = {}, // for faster hyphen converts
+ reClassNameCache = {}; // cache regexes for className
+
+ // brower detection
+ var isOpera = YAHOO.env.ua.opera,
+ isSafari = YAHOO.env.ua.webkit,
+ isGecko = YAHOO.env.ua.gecko,
+ isIE = YAHOO.env.ua.ie;
+
+ // regex cache
+ var patterns = {
+ HYPHEN: /(-[a-z])/i, // to normalize get/setStyle
+ ROOT_TAG: /^body|html$/i // body for quirks mode, html for standards
+ };
+
+ var toCamel = function(property) {
+ if ( !patterns.HYPHEN.test(property) ) {
+ return property; // no hyphens
+ }
+
+ if (propertyCache[property]) { // already converted
+ return propertyCache[property];
+ }
+
+ var converted = property;
+
+ while( patterns.HYPHEN.exec(converted) ) {
+ converted = converted.replace(RegExp.$1,
+ RegExp.$1.substr(1).toUpperCase());
+ }
+
+ propertyCache[property] = converted;
+ return converted;
+ //return property.replace(/-([a-z])/gi, function(m0, m1) {return m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari bug
+ };
+
+ var getClassRegEx = function(className) {
+ var re = reClassNameCache[className];
+ if (!re) {
+ re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
+ reClassNameCache[className] = re;
+ }
+ return re;
+ };
+
+ // branching at load instead of runtime
+ if (document.defaultView && document.defaultView.getComputedStyle) { // W3C DOM method
+ getStyle = function(el, property) {
+ var value = null;
+
+ if (property == 'float') { // fix reserved word
+ property = 'cssFloat';
+ }
+
+ var computed = document.defaultView.getComputedStyle(el, '');
+ if (computed) { // test computed before touching for safari
+ value = computed[toCamel(property)];
+ }
+
+ return el.style[property] || value;
+ };
+ } else if (document.documentElement.currentStyle && isIE) { // IE method
+ getStyle = function(el, property) {
+ switch( toCamel(property) ) {
+ case 'opacity' :// IE opacity uses filter
+ var val = 100;
+ try { // will error if no DXImageTransform
+ val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
+
+ } catch(e) {
+ try { // make sure its in the document
+ val = el.filters('alpha').opacity;
+ } catch(e) {
+ }
+ }
+ return val / 100;
+ case 'float': // fix reserved word
+ property = 'styleFloat'; // fall through
+ default:
+ // test currentStyle before touching
+ var value = el.currentStyle ? el.currentStyle[property] : null;
+ return ( el.style[property] || value );
+ }
+ };
+ } else { // default to inline only
+ getStyle = function(el, property) { return el.style[property]; };
+ }
+
+ if (isIE) {
+ setStyle = function(el, property, val) {
+ switch (property) {
+ case 'opacity':
+ if ( YAHOO.lang.isString(el.style.filter) ) { // in case not appended
+ el.style.filter = 'alpha(opacity=' + val * 100 + ')';
+
+ if (!el.currentStyle || !el.currentStyle.hasLayout) {
+ el.style.zoom = 1; // when no layout or cant tell
+ }
+ }
+ break;
+ case 'float':
+ property = 'styleFloat';
+ default:
+ el.style[property] = val;
+ }
+ };
+ } else {
+ setStyle = function(el, property, val) {
+ if (property == 'float') {
+ property = 'cssFloat';
+ }
+ el.style[property] = val;
+ };
+ }
+
+ var testElement = function(node, method) {
+ return node && node.nodeType == 1 && ( !method || method(node) );
+ };
+
+ /**
+ * Provides helper methods for DOM elements.
+ * @namespace YAHOO.util
+ * @class Dom
+ */
+ YAHOO.util.Dom = {
+ /**
+ * Returns an HTMLElement reference.
+ * @method get
+ * @param {String | HTMLElement |Array} el Accepts a string to use as an ID for getting a DOM reference, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+ * @return {HTMLElement | Array} A DOM reference to an HTML element or an array of HTMLElements.
+ */
+ get: function(el) {
+ if (el && (el.tagName || el.item)) { // HTMLElement, or HTMLCollection
+ return el;
+ }
+
+ if (YAHOO.lang.isString(el) || !el) { // HTMLElement or null
+ return document.getElementById(el);
+ }
+
+ if (el.length !== undefined) { // array-like
+ var c = [];
+ for (var i = 0, len = el.length; i < len; ++i) {
+ c[c.length] = Y.Dom.get(el[i]);
+ }
+
+ return c;
+ }
+
+ return el; // some other object, just pass it back
+ },
+
+ /**
+ * Normalizes currentStyle and ComputedStyle.
+ * @method getStyle
+ * @param {String | HTMLElement |Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+ * @param {String} property The style property whose value is returned.
+ * @return {String | Array} The current value of the style property for the element(s).
+ */
+ getStyle: function(el, property) {
+ property = toCamel(property);
+
+ var f = function(element) {
+ return getStyle(element, property);
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Wrapper for setting style properties of HTMLElements. Normalizes "opacity" across modern browsers.
+ * @method setStyle
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+ * @param {String} property The style property to be set.
+ * @param {String} val The value to apply to the given property.
+ */
+ setStyle: function(el, property, val) {
+ property = toCamel(property);
+
+ var f = function(element) {
+ setStyle(element, property, val);
+
+ };
+
+ Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * 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).
+ * @method getXY
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+ * @return {Array} The XY position of the element(s)
+ */
+ getXY: function(el) {
+ var f = function(el) {
+
+ // has to be part of document to have pageXY
+ if ( (el.parentNode === null || el.offsetParent === null ||
+ this.getStyle(el, 'display') == 'none') && el != document.body) {
+ return false;
+ }
+
+ var parentNode = null;
+ var pos = [];
+ var box;
+ var doc = el.ownerDocument;
+
+ if (el.getBoundingClientRect) { // IE
+ box = el.getBoundingClientRect();
+ return [box.left + Y.Dom.getDocumentScrollLeft(el.ownerDocument), box.top + Y.Dom.getDocumentScrollTop(el.ownerDocument)];
+ }
+ else { // safari, opera, & gecko
+ pos = [el.offsetLeft, el.offsetTop];
+ parentNode = el.offsetParent;
+
+ // safari: if el is abs or any parent is abs, subtract body offsets
+ var hasAbs = this.getStyle(el, 'position') == 'absolute';
+
+ if (parentNode != el) {
+ while (parentNode) {
+ pos[0] += parentNode.offsetLeft;
+ pos[1] += parentNode.offsetTop;
+ if (isSafari && !hasAbs &&
+ this.getStyle(parentNode,'position') == 'absolute' ) {
+ hasAbs = true; // we need to offset if any parent is absolutely positioned
+ }
+ parentNode = parentNode.offsetParent;
+ }
+ }
+
+ if (isSafari && hasAbs) { //safari doubles in this case
+ pos[0] -= el.ownerDocument.body.offsetLeft;
+ pos[1] -= el.ownerDocument.body.offsetTop;
+ }
+ }
+
+ parentNode = el.parentNode;
+
+ // account for any scrolled ancestors
+ while ( parentNode.tagName && !patterns.ROOT_TAG.test(parentNode.tagName) )
+ {
+ // work around opera inline/table scrollLeft/Top bug
+ if (Y.Dom.getStyle(parentNode, 'display').search(/^inline|table-row.*$/i)) {
+ pos[0] -= parentNode.scrollLeft;
+ pos[1] -= parentNode.scrollTop;
+ }
+
+ parentNode = parentNode.parentNode;
+ }
+
+
+ return pos;
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * 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).
+ * @method getX
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+ * @return {Number | Array} The X position of the element(s)
+ */
+ getX: function(el) {
+ var f = function(el) {
+ return Y.Dom.getXY(el)[0];
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * 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).
+ * @method getY
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+ * @return {Number | Array} The Y position of the element(s)
+ */
+ getY: function(el) {
+ var f = function(el) {
+ return Y.Dom.getXY(el)[1];
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Set the position of an html element in page coordinates, regardless of how the element is positioned.
+ * The element(s) must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+ * @method setXY
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements
+ * @param {Array} pos Contains X & Y values for new position (coordinates are page-based)
+ * @param {Boolean} noRetry By default we try and set the position a second time if the first fails
+ */
+ setXY: function(el, pos, noRetry) {
+ var f = function(el) {
+ var style_pos = this.getStyle(el, 'position');
+ if (style_pos == 'static') { // default to relative
+ this.setStyle(el, 'position', 'relative');
+ style_pos = 'relative';
+ }
+
+ var pageXY = this.getXY(el);
+ if (pageXY === false) { // has to be part of doc to have pageXY
+ return false;
+ }
+
+ var delta = [ // assuming pixels; if not we will have to retry
+ parseInt( this.getStyle(el, 'left'), 10 ),
+ parseInt( this.getStyle(el, 'top'), 10 )
+ ];
+
+ if ( isNaN(delta[0]) ) {// in case of 'auto'
+ delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
+ }
+ if ( isNaN(delta[1]) ) { // in case of 'auto'
+ delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
+ }
+
+ 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'; }
+
+ if (!noRetry) {
+ var newXY = this.getXY(el);
+
+ // if retry is true, try one more time if we miss
+ if ( (pos[0] !== null && newXY[0] != pos[0]) ||
+ (pos[1] !== null && newXY[1] != pos[1]) ) {
+ this.setXY(el, pos, true);
+ }
+ }
+
+ };
+
+ Y.Dom.batch(el, f, Y.Dom, 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).
+ * @method setX
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+ * @param {Int} x The value to use as the X coordinate for the element(s).
+ */
+ setX: function(el, x) {
+ Y.Dom.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).
+ * @method setY
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+ * @param {Int} x To use as the Y coordinate for the element(s).
+ */
+ setY: function(el, y) {
+ Y.Dom.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).
+ * @method getRegion
+ * @param {String | HTMLElement | Array} el Accepts a string to use as an ID, an actual DOM reference, or an Array of IDs and/or HTMLElements.
+ * @return {Region | Array} A Region or array of Region instances containing "top, left, bottom, right" member data.
+ */
+ getRegion: function(el) {
+ var f = function(el) {
+ if ( (el.parentNode === null || el.offsetParent === null ||
+ this.getStyle(el, 'display') == 'none') && el != document.body) {
+ return false;
+ }
+
+ var region = Y.Region.getRegion(el);
+ return region;
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Returns the width of the client (viewport).
+ * @method getClientWidth
+ * @deprecated Now using getViewportWidth. This interface left intact for back compat.
+ * @return {Int} The width of the viewable area of the page.
+ */
+ getClientWidth: function() {
+ return Y.Dom.getViewportWidth();
+ },
+
+ /**
+ * Returns the height of the client (viewport).
+ * @method getClientHeight
+ * @deprecated Now using getViewportHeight. This interface left intact for back compat.
+ * @return {Int} The height of the viewable area of the page.
+ */
+ getClientHeight: function() {
+ return Y.Dom.getViewportHeight();
+ },
+
+ /**
+ * Returns a array of HTMLElements with the given class.
+ * For optimized performance, include a tag and/or root node when possible.
+ * @method getElementsByClassName
+ * @param {String} className The class name to match against
+ * @param {String} tag (optional) The tag name of the elements being collected
+ * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point
+ * @param {Function} apply (optional) A function to apply to each element when found
+ * @return {Array} An array of elements that have the given class name
+ */
+ getElementsByClassName: function(className, tag, root, apply) {
+ tag = tag || '*';
+ root = (root) ? Y.Dom.get(root) : null || document;
+ if (!root) {
+ return [];
+ }
+
+ var nodes = [],
+ elements = root.getElementsByTagName(tag),
+ re = getClassRegEx(className);
+
+ for (var i = 0, len = elements.length; i < len; ++i) {
+ if ( re.test(elements[i].className) ) {
+ nodes[nodes.length] = elements[i];
+ if (apply) {
+ apply.call(elements[i], elements[i]);
+ }
+ }
+ }
+
+ return nodes;
+ },
+
+ /**
+ * Determines whether an HTMLElement has the given className.
+ * @method hasClass
+ * @param {String | HTMLElement | Array} el The element or collection to test
+ * @param {String} className the class name to search for
+ * @return {Boolean | Array} A boolean value or array of boolean values
+ */
+ hasClass: function(el, className) {
+ var re = getClassRegEx(className);
+
+ var f = function(el) {
+ return re.test(el.className);
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Adds a class name to a given element or collection of elements.
+ * @method addClass
+ * @param {String | HTMLElement | Array} el The element or collection to add the class to
+ * @param {String} className the class name to add to the class attribute
+ * @return {Boolean | Array} A pass/fail boolean or array of booleans
+ */
+ addClass: function(el, className) {
+ var f = function(el) {
+ if (this.hasClass(el, className)) {
+ return false; // already present
+ }
+
+
+ el.className = YAHOO.lang.trim([el.className, className].join(' '));
+ return true;
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Removes a class name from a given element or collection of elements.
+ * @method removeClass
+ * @param {String | HTMLElement | Array} el The element or collection to remove the class from
+ * @param {String} className the class name to remove from the class attribute
+ * @return {Boolean | Array} A pass/fail boolean or array of booleans
+ */
+ removeClass: function(el, className) {
+ var re = getClassRegEx(className);
+
+ var f = function(el) {
+ if (!this.hasClass(el, className)) {
+ return false; // not present
+ }
+
+
+ var c = el.className;
+ el.className = c.replace(re, ' ');
+ if ( this.hasClass(el, className) ) { // in case of multiple adjacent
+ this.removeClass(el, className);
+ }
+
+ el.className = YAHOO.lang.trim(el.className); // remove any trailing spaces
+ return true;
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Replace a class with another class for a given element or collection of elements.
+ * If no oldClassName is present, the newClassName is simply added.
+ * @method replaceClass
+ * @param {String | HTMLElement | Array} el The element or collection to remove the class from
+ * @param {String} oldClassName the class name to be replaced
+ * @param {String} newClassName the class name that will be replacing the old class name
+ * @return {Boolean | Array} A pass/fail boolean or array of booleans
+ */
+ replaceClass: function(el, oldClassName, newClassName) {
+ if (!newClassName || oldClassName === newClassName) { // avoid infinite loop
+ return false;
+ }
+
+ var re = getClassRegEx(oldClassName);
+
+ var f = function(el) {
+
+ if ( !this.hasClass(el, oldClassName) ) {
+ this.addClass(el, newClassName); // just add it if nothing to replace
+ return true; // NOTE: return
+ }
+
+ el.className = el.className.replace(re, ' ' + newClassName + ' ');
+
+ if ( this.hasClass(el, oldClassName) ) { // in case of multiple adjacent
+ this.replaceClass(el, oldClassName, newClassName);
+ }
+
+ el.className = YAHOO.lang.trim(el.className); // remove any trailing spaces
+ return true;
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Returns an ID and applies it to the element "el", if provided.
+ * @method generateId
+ * @param {String | HTMLElement | Array} el (optional) An optional element array of elements to add an ID to (no ID is added if one is already present).
+ * @param {String} prefix (optional) an optional prefix to use (defaults to "yui-gen").
+ * @return {String | Array} The generated ID, or array of generated IDs (or original ID if already present on an element)
+ */
+ generateId: function(el, prefix) {
+ prefix = prefix || 'yui-gen';
+
+ var f = function(el) {
+ if (el && el.id) { // do not override existing ID
+ return el.id;
+ }
+
+ var id = prefix + id_counter++;
+
+ if (el) {
+ el.id = id;
+ }
+
+ return id;
+ };
+
+ // batch fails when no element, so just generate and return single ID
+ return Y.Dom.batch(el, f, Y.Dom, true) || f.apply(Y.Dom, arguments);
+ },
+
+ /**
+ * Determines whether an HTMLElement is an ancestor of another HTML element in the DOM hierarchy.
+ * @method isAncestor
+ * @param {String | HTMLElement} haystack The possible ancestor
+ * @param {String | HTMLElement} needle The possible descendent
+ * @return {Boolean} Whether or not the haystack is an ancestor of needle
+ */
+ isAncestor: function(haystack, needle) {
+ haystack = Y.Dom.get(haystack);
+ if (!haystack || !needle) { return false; }
+
+ var f = function(node) {
+ if (haystack.contains && node.nodeType && !isSafari) { // safari contains is broken
+ return haystack.contains(node);
+ }
+ else if ( haystack.compareDocumentPosition && node.nodeType ) {
+ return !!(haystack.compareDocumentPosition(node) & 16);
+ } else if (node.nodeType) {
+ // fallback to crawling up (safari)
+ return !!this.getAncestorBy(node, function(el) {
+ return el == haystack;
+ });
+ }
+ return false;
+ };
+
+ return Y.Dom.batch(needle, f, Y.Dom, true);
+ },
+
+ /**
+ * Determines whether an HTMLElement is present in the current document.
+ * @method inDocument
+ * @param {String | HTMLElement} el The element to search for
+ * @return {Boolean} Whether or not the element is present in the current document
+ */
+ inDocument: function(el) {
+ var f = function(el) { // safari contains fails for body so crawl up
+ if (isSafari) {
+ while (el = el.parentNode) { // note assignment
+ if (el == document.documentElement) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return this.isAncestor(document.documentElement, el);
+ };
+
+ return Y.Dom.batch(el, f, Y.Dom, true);
+ },
+
+ /**
+ * Returns a array of HTMLElements that pass the test applied by supplied boolean method.
+ * For optimized performance, include a tag and/or root node when possible.
+ * @method getElementsBy
+ * @param {Function} method - A boolean method for testing elements which receives the element as its only argument.
+ * @param {String} tag (optional) The tag name of the elements being collected
+ * @param {String | HTMLElement} root (optional) The HTMLElement or an ID to use as the starting point
+ * @param {Function} apply (optional) A function to apply to each element when found
+ * @return {Array} Array of HTMLElements
+ */
+ getElementsBy: function(method, tag, root, apply) {
+ tag = tag || '*';
+ root = (root) ? Y.Dom.get(root) : null || document;
+
+ if (!root) {
+ return [];
+ }
+
+ var nodes = [],
+ elements = root.getElementsByTagName(tag);
+
+ for (var i = 0, len = elements.length; i < len; ++i) {
+ if ( method(elements[i]) ) {
+ nodes[nodes.length] = elements[i];
+ if (apply) {
+ apply(elements[i]);
+ }
+ }
+ }
+
+
+ return nodes;
+ },
+
+ /**
+ * Runs the supplied method against each item in the Collection/Array.
+ * The method is called with the element(s) as the first arg, and the optional param as the second ( method(el, o) ).
+ * @method batch
+ * @param {String | HTMLElement | Array} el (optional) An element or array of elements to apply the method to
+ * @param {Function} method The method to apply to the element(s)
+ * @param {Any} o (optional) An optional arg that is passed to the supplied method
+ * @param {Boolean} override (optional) Whether or not to override the scope of "method" with "o"
+ * @return {Any | Array} The return value(s) from the supplied method
+ */
+ batch: function(el, method, o, override) {
+ el = (el && (el.tagName || el.item)) ? el : Y.Dom.get(el); // skip get() when possible
+
+ if (!el || !method) {
+ return false;
+ }
+ var scope = (override) ? o : window;
+
+ if (el.tagName || el.length === undefined) { // element or not array-like
+ return method.call(scope, el, o);
+ }
+
+ var collection = [];
+
+ for (var i = 0, len = el.length; i < len; ++i) {
+ collection[collection.length] = method.call(scope, el[i], o);
+ }
+
+ return collection;
+ },
+
+ /**
+ * Returns the height of the document.
+ * @method getDocumentHeight
+ * @return {Int} The height of the actual document (which includes the body and its margin).
+ */
+ getDocumentHeight: function() {
+ var scrollHeight = (document.compatMode != 'CSS1Compat') ? document.body.scrollHeight : document.documentElement.scrollHeight;
+
+ var h = Math.max(scrollHeight, Y.Dom.getViewportHeight());
+ return h;
+ },
+
+ /**
+ * Returns the width of the document.
+ * @method getDocumentWidth
+ * @return {Int} The width of the actual document (which includes the body and its margin).
+ */
+ getDocumentWidth: function() {
+ var scrollWidth = (document.compatMode != 'CSS1Compat') ? document.body.scrollWidth : document.documentElement.scrollWidth;
+ var w = Math.max(scrollWidth, Y.Dom.getViewportWidth());
+ return w;
+ },
+
+ /**
+ * Returns the current height of the viewport.
+ * @method getViewportHeight
+ * @return {Int} The height of the viewable area of the page (excludes scrollbars).
+ */
+ getViewportHeight: function() {
+ var height = self.innerHeight; // Safari, Opera
+ var mode = document.compatMode;
+
+ if ( (mode || isIE) && !isOpera ) { // IE, Gecko
+ height = (mode == 'CSS1Compat') ?
+ document.documentElement.clientHeight : // Standards
+ document.body.clientHeight; // Quirks
+ }
+
+ return height;
+ },
+
+ /**
+ * Returns the current width of the viewport.
+ * @method getViewportWidth
+ * @return {Int} The width of the viewable area of the page (excludes scrollbars).
+ */
+
+ getViewportWidth: function() {
+ var width = self.innerWidth; // Safari
+ var mode = document.compatMode;
+
+ if (mode || isIE) { // IE, Gecko, Opera
+ width = (mode == 'CSS1Compat') ?
+ document.documentElement.clientWidth : // Standards
+ document.body.clientWidth; // Quirks
+ }
+ return width;
+ },
+
+ /**
+ * Returns the nearest ancestor that passes the test applied by supplied boolean method.
+ * For performance reasons, IDs are not accepted and argument validation omitted.
+ * @method getAncestorBy
+ * @param {HTMLElement} node The HTMLElement to use as the starting point
+ * @param {Function} method - A boolean method for testing elements which receives the element as its only argument.
+ * @return {Object} HTMLElement or null if not found
+ */
+ getAncestorBy: function(node, method) {
+ while (node = node.parentNode) { // NOTE: assignment
+ if ( testElement(node, method) ) {
+ return node;
+ }
+ }
+
+ return null;
+ },
+
+ /**
+ * Returns the nearest ancestor with the given className.
+ * @method getAncestorByClassName
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @param {String} className
+ * @return {Object} HTMLElement
+ */
+ getAncestorByClassName: function(node, className) {
+ node = Y.Dom.get(node);
+ if (!node) {
+ return null;
+ }
+ var method = function(el) { return Y.Dom.hasClass(el, className); };
+ return Y.Dom.getAncestorBy(node, method);
+ },
+
+ /**
+ * Returns the nearest ancestor with the given tagName.
+ * @method getAncestorByTagName
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @param {String} tagName
+ * @return {Object} HTMLElement
+ */
+ getAncestorByTagName: function(node, tagName) {
+ node = Y.Dom.get(node);
+ if (!node) {
+ return null;
+ }
+ var method = function(el) {
+ return el.tagName && el.tagName.toUpperCase() == tagName.toUpperCase();
+ };
+
+ return Y.Dom.getAncestorBy(node, method);
+ },
+
+ /**
+ * Returns the previous sibling that is an HTMLElement.
+ * For performance reasons, IDs are not accepted and argument validation omitted.
+ * Returns the nearest HTMLElement sibling if no method provided.
+ * @method getPreviousSiblingBy
+ * @param {HTMLElement} node The HTMLElement to use as the starting point
+ * @param {Function} method A boolean function used to test siblings
+ * that receives the sibling node being tested as its only argument
+ * @return {Object} HTMLElement or null if not found
+ */
+ getPreviousSiblingBy: function(node, method) {
+ while (node) {
+ node = node.previousSibling;
+ if ( testElement(node, method) ) {
+ return node;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Returns the previous sibling that is an HTMLElement
+ * @method getPreviousSibling
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @return {Object} HTMLElement or null if not found
+ */
+ getPreviousSibling: function(node) {
+ node = Y.Dom.get(node);
+ if (!node) {
+ return null;
+ }
+
+ return Y.Dom.getPreviousSiblingBy(node);
+ },
+
+ /**
+ * Returns the next HTMLElement sibling that passes the boolean method.
+ * For performance reasons, IDs are not accepted and argument validation omitted.
+ * Returns the nearest HTMLElement sibling if no method provided.
+ * @method getNextSiblingBy
+ * @param {HTMLElement} node The HTMLElement to use as the starting point
+ * @param {Function} method A boolean function used to test siblings
+ * that receives the sibling node being tested as its only argument
+ * @return {Object} HTMLElement or null if not found
+ */
+ getNextSiblingBy: function(node, method) {
+ while (node) {
+ node = node.nextSibling;
+ if ( testElement(node, method) ) {
+ return node;
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Returns the next sibling that is an HTMLElement
+ * @method getNextSibling
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @return {Object} HTMLElement or null if not found
+ */
+ getNextSibling: function(node) {
+ node = Y.Dom.get(node);
+ if (!node) {
+ return null;
+ }
+
+ return Y.Dom.getNextSiblingBy(node);
+ },
+
+ /**
+ * Returns the first HTMLElement child that passes the test method.
+ * @method getFirstChildBy
+ * @param {HTMLElement} node The HTMLElement to use as the starting point
+ * @param {Function} method A boolean function used to test children
+ * that receives the node being tested as its only argument
+ * @return {Object} HTMLElement or null if not found
+ */
+ getFirstChildBy: function(node, method) {
+ var child = ( testElement(node.firstChild, method) ) ? node.firstChild : null;
+ return child || Y.Dom.getNextSiblingBy(node.firstChild, method);
+ },
+
+ /**
+ * Returns the first HTMLElement child.
+ * @method getFirstChild
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @return {Object} HTMLElement or null if not found
+ */
+ getFirstChild: function(node, method) {
+ node = Y.Dom.get(node);
+ if (!node) {
+ return null;
+ }
+ return Y.Dom.getFirstChildBy(node);
+ },
+
+ /**
+ * Returns the last HTMLElement child that passes the test method.
+ * @method getLastChildBy
+ * @param {HTMLElement} node The HTMLElement to use as the starting point
+ * @param {Function} method A boolean function used to test children
+ * that receives the node being tested as its only argument
+ * @return {Object} HTMLElement or null if not found
+ */
+ getLastChildBy: function(node, method) {
+ if (!node) {
+ return null;
+ }
+ var child = ( testElement(node.lastChild, method) ) ? node.lastChild : null;
+ return child || Y.Dom.getPreviousSiblingBy(node.lastChild, method);
+ },
+
+ /**
+ * Returns the last HTMLElement child.
+ * @method getLastChild
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @return {Object} HTMLElement or null if not found
+ */
+ getLastChild: function(node) {
+ node = Y.Dom.get(node);
+ return Y.Dom.getLastChildBy(node);
+ },
+
+ /**
+ * Returns an array of HTMLElement childNodes that pass the test method.
+ * @method getChildrenBy
+ * @param {HTMLElement} node The HTMLElement to start from
+ * @param {Function} method A boolean function used to test children
+ * that receives the node being tested as its only argument
+ * @return {Array} A static array of HTMLElements
+ */
+ getChildrenBy: function(node, method) {
+ var child = Y.Dom.getFirstChildBy(node, method);
+ var children = child ? [child] : [];
+
+ Y.Dom.getNextSiblingBy(child, function(node) {
+ if ( !method || method(node) ) {
+ children[children.length] = node;
+ }
+ return false; // fail test to collect all children
+ });
+
+ return children;
+ },
+
+ /**
+ * Returns an array of HTMLElement childNodes.
+ * @method getChildren
+ * @param {String | HTMLElement} node The HTMLElement or an ID to use as the starting point
+ * @return {Array} A static array of HTMLElements
+ */
+ getChildren: function(node) {
+ node = Y.Dom.get(node);
+ if (!node) {
+ }
+
+ return Y.Dom.getChildrenBy(node);
+ },
+
+ /**
+ * Returns the left scroll value of the document
+ * @method getDocumentScrollLeft
+ * @param {HTMLDocument} document (optional) The document to get the scroll value of
+ * @return {Int} The amount that the document is scrolled to the left
+ */
+ getDocumentScrollLeft: function(doc) {
+ doc = doc || document;
+ return Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
+ },
+
+ /**
+ * Returns the top scroll value of the document
+ * @method getDocumentScrollTop
+ * @param {HTMLDocument} document (optional) The document to get the scroll value of
+ * @return {Int} The amount that the document is scrolled to the top
+ */
+ getDocumentScrollTop: function(doc) {
+ doc = doc || document;
+ return Math.max(doc.documentElement.scrollTop, doc.body.scrollTop);
+ },
+
+ /**
+ * Inserts the new node as the previous sibling of the reference node
+ * @method insertBefore
+ * @param {String | HTMLElement} newNode The node to be inserted
+ * @param {String | HTMLElement} referenceNode The node to insert the new node before
+ * @return {HTMLElement} The node that was inserted (or null if insert fails)
+ */
+ insertBefore: function(newNode, referenceNode) {
+ newNode = Y.Dom.get(newNode);
+ referenceNode = Y.Dom.get(referenceNode);
+
+ if (!newNode || !referenceNode || !referenceNode.parentNode) {
+ return null;
+ }
+
+ return referenceNode.parentNode.insertBefore(newNode, referenceNode);
+ },
+
+ /**
+ * Inserts the new node as the next sibling of the reference node
+ * @method insertAfter
+ * @param {String | HTMLElement} newNode The node to be inserted
+ * @param {String | HTMLElement} referenceNode The node to insert the new node after
+ * @return {HTMLElement} The node that was inserted (or null if insert fails)
+ */
+ insertAfter: function(newNode, referenceNode) {
+ newNode = Y.Dom.get(newNode);
+ referenceNode = Y.Dom.get(referenceNode);
+
+ if (!newNode || !referenceNode || !referenceNode.parentNode) {
+ return null;
+ }
+
+ if (referenceNode.nextSibling) {
+ return referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
+ } else {
+ return referenceNode.parentNode.appendChild(newNode);
+ }
+ }
+ };
+})();
+/**
+ * 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.
+ * @namespace YAHOO.util
+ * @class Region
+ * @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
+ * @property top
+ * @type Int
+ */
+ this.top = t;
+
+ /**
+ * The region's top extent as index, for symmetry with set/getXY
+ * @property 1
+ * @type Int
+ */
+ this[1] = t;
+
+ /**
+ * The region's right extent
+ * @property right
+ * @type int
+ */
+ this.right = r;
+
+ /**
+ * The region's bottom extent
+ * @property bottom
+ * @type Int
+ */
+ this.bottom = b;
+
+ /**
+ * The region's left extent
+ * @property left
+ * @type Int
+ */
+ this.left = l;
+
+ /**
+ * The region's left extent as index, for symmetry with set/getXY
+ * @property 0
+ * @type Int
+ */
+ this[0] = l;
+};
+
+/**
+ * Returns true if this region contains the region passed in
+ * @method contains
+ * @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
+ * @method getArea
+ * @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
+ * @method intersect
+ * @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.
+ * @method union
+ * @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
+ * @method toString
+ * @return string the region properties
+ */
+YAHOO.util.Region.prototype.toString = function() {
+ return ( "Region {" +
+ "top: " + this.top +
+ ", right: " + this.right +
+ ", bottom: " + this.bottom +
+ ", left: " + this.left +
+ "}" );
+};
+
+/**
+ * Returns a region that is occupied by the DOM element
+ * @method getRegion
+ * @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);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * A point is a region that is special in that it represents a single point on
+ * the grid.
+ * @namespace YAHOO.util
+ * @class Point
+ * @param {Int} x The X position of the point
+ * @param {Int} y The Y position of the point
+ * @constructor
+ * @extends YAHOO.util.Region
+ */
+YAHOO.util.Point = function(x, y) {
+ if (YAHOO.lang.isArray(x)) { // accept input from Dom.getXY, Event.getXY, etc.
+ y = x[1]; // dont blow away x yet
+ x = x[0];
+ }
+
+ /**
+ * The X position of the point, which is also the right, left and index zero (for Dom.getXY symmetry)
+ * @property x
+ * @type Int
+ */
+
+ this.x = this.right = this.left = this[0] = x;
+
+ /**
+ * The Y position of the point, which is also the top, bottom and index one (for Dom.getXY symmetry)
+ * @property y
+ * @type Int
+ */
+ this.y = this.top = this.bottom = this[1] = y;
+};
+
+YAHOO.util.Point.prototype = new YAHOO.util.Region();
+
+YAHOO.register("dom", YAHOO.util.Dom, {version: "2.3.1", build: "541"});
diff --git a/html/js/yui2.3.1/event/event.js b/html/js/yui2.3.1/event/event.js
new file mode 100644
index 0000000..9b8089e
--- /dev/null
+++ b/html/js/yui2.3.1/event/event.js
@@ -0,0 +1,2374 @@
+/*
+Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.3.1
+*/
+
+/**
+ * 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.
+ * @param {boolean} silent pass true to prevent the event from writing to
+ * the debugsystem
+ * @param {int} signature the signature that the custom event subscriber
+ * will receive. YAHOO.util.CustomEvent.LIST or
+ * YAHOO.util.CustomEvent.FLAT. The default is
+ * YAHOO.util.CustomEvent.LIST.
+ * @namespace YAHOO.util
+ * @class CustomEvent
+ * @constructor
+ */
+YAHOO.util.CustomEvent = function(type, oScope, silent, signature) {
+
+ /**
+ * The type of event, returned to subscribers when the event fires
+ * @property type
+ * @type string
+ */
+ this.type = type;
+
+ /**
+ * The scope the the event will fire from by default. Defaults to the window
+ * obj
+ * @property scope
+ * @type object
+ */
+ this.scope = oScope || window;
+
+ /**
+ * By default all custom events are logged in the debug build, set silent
+ * to true to disable debug outpu for this event.
+ * @property silent
+ * @type boolean
+ */
+ this.silent = silent;
+
+ /**
+ * Custom events support two styles of arguments provided to the event
+ * subscribers.
+ * <ul>
+ * <li>YAHOO.util.CustomEvent.LIST:
+ * <ul>
+ * <li>param1: event name</li>
+ * <li>param2: array of arguments sent to fire</li>
+ * <li>param3: <optional> a custom object supplied by the subscriber</li>
+ * </ul>
+ * </li>
+ * <li>YAHOO.util.CustomEvent.FLAT
+ * <ul>
+ * <li>param1: the first argument passed to fire. If you need to
+ * pass multiple parameters, use and array or object literal</li>
+ * <li>param2: <optional> a custom object supplied by the subscriber</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * @property signature
+ * @type int
+ */
+ this.signature = signature || YAHOO.util.CustomEvent.LIST;
+
+ /**
+ * The subscribers to this event
+ * @property subscribers
+ * @type Subscriber[]
+ */
+ this.subscribers = [];
+
+ if (!this.silent) {
+ }
+
+ var onsubscribeType = "_YUICEOnSubscribe";
+
+ // Only add subscribe events for events that are not generated by
+ // CustomEvent
+ if (type !== onsubscribeType) {
+
+ /**
+ * Custom events provide a custom event that fires whenever there is
+ * a new subscriber to the event. This provides an opportunity to
+ * handle the case where there is a non-repeating event that has
+ * already fired has a new subscriber.
+ *
+ * @event subscribeEvent
+ * @type YAHOO.util.CustomEvent
+ * @param {Function} fn The function to execute
+ * @param {Object} obj An object to be passed along when the event
+ * fires
+ * @param {boolean|Object} override If true, the obj passed in becomes
+ * the execution scope of the listener.
+ * if an object, that object becomes the
+ * the execution scope.
+ */
+ this.subscribeEvent =
+ new YAHOO.util.CustomEvent(onsubscribeType, this, true);
+
+ }
+
+
+ /**
+ * In order to make it possible to execute the rest of the subscriber
+ * stack when one thows an exception, the subscribers exceptions are
+ * caught. The most recent exception is stored in this property
+ * @property lastError
+ * @type Error
+ */
+ this.lastError = null;
+};
+
+/**
+ * Subscriber listener sigature constant. The LIST type returns three
+ * parameters: the event type, the array of args passed to fire, and
+ * the optional custom object
+ * @property YAHOO.util.CustomEvent.LIST
+ * @static
+ * @type int
+ */
+YAHOO.util.CustomEvent.LIST = 0;
+
+/**
+ * Subscriber listener sigature constant. The FLAT type returns two
+ * parameters: the first argument passed to fire and the optional
+ * custom object
+ * @property YAHOO.util.CustomEvent.FLAT
+ * @static
+ * @type int
+ */
+YAHOO.util.CustomEvent.FLAT = 1;
+
+YAHOO.util.CustomEvent.prototype = {
+
+ /**
+ * Subscribes the caller to this event
+ * @method subscribe
+ * @param {Function} fn The function to execute
+ * @param {Object} obj An object to be passed along when the event
+ * fires
+ * @param {boolean|Object} override If true, the obj passed in becomes
+ * the execution scope of the listener.
+ * if an object, that object becomes the
+ * the execution scope.
+ */
+ subscribe: function(fn, obj, override) {
+
+ if (!fn) {
+throw new Error("Invalid callback for subscriber to '" + this.type + "'");
+ }
+
+ if (this.subscribeEvent) {
+ this.subscribeEvent.fire(fn, obj, override);
+ }
+
+ this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, override) );
+ },
+
+ /**
+ * Unsubscribes subscribers.
+ * @method unsubscribe
+ * @param {Function} fn The subscribed function to remove, if not supplied
+ * all will be removed
+ * @param {Object} obj The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {boolean} True if the subscriber was found and detached.
+ */
+ unsubscribe: function(fn, obj) {
+
+ if (!fn) {
+ return this.unsubscribeAll();
+ }
+
+ var found = false;
+ for (var i=0, len=this.subscribers.length; i<len; ++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:
+ * <ul>
+ * <li>The type of event</li>
+ * <li>All of the arguments fire() was executed with as an array</li>
+ * <li>The custom object (if any) that was passed into the subscribe()
+ * method</li>
+ * </ul>
+ * @method fire
+ * @param {Object*} arguments an arbitrary set of parameters to pass to
+ * the handler.
+ * @return {boolean} false if one of the subscribers returned false,
+ * true otherwise
+ */
+ fire: function() {
+ var len=this.subscribers.length;
+ if (!len && this.silent) {
+ return true;
+ }
+
+ var args=[], ret=true, i, rebuild=false;
+
+ for (i=0; i<arguments.length; ++i) {
+ args.push(arguments[i]);
+ }
+
+ var argslength = args.length;
+
+ if (!this.silent) {
+ }
+
+ for (i=0; i<len; ++i) {
+ var s = this.subscribers[i];
+ if (!s) {
+ rebuild=true;
+ } else {
+ if (!this.silent) {
+ }
+
+ var scope = s.getScope(this.scope);
+
+ if (this.signature == YAHOO.util.CustomEvent.FLAT) {
+ var param = null;
+ if (args.length > 0) {
+ param = args[0];
+ }
+
+ try {
+ ret = s.fn.call(scope, param, s.obj);
+ } catch(e) {
+ this.lastError = e;
+ }
+ } else {
+ try {
+ ret = s.fn.call(scope, this.type, args, s.obj);
+ } catch(e) {
+ this.lastError = e;
+ }
+ }
+ if (false === ret) {
+ if (!this.silent) {
+ }
+
+ //break;
+ return false;
+ }
+ }
+ }
+
+ if (rebuild) {
+ var newlist=[],subs=this.subscribers;
+ for (i=0,len=subs.length; i<len; i=i+1) {
+ newlist.push(subs[i]);
+ }
+
+ this.subscribers=newlist;
+ }
+
+ return true;
+ },
+
+ /**
+ * Removes all listeners
+ * @method unsubscribeAll
+ * @return {int} The number of listeners unsubscribed
+ */
+ unsubscribeAll: function() {
+ for (var i=0, len=this.subscribers.length; i<len; ++i) {
+ this._delete(len - 1 - i);
+ }
+
+ this.subscribers=[];
+
+ return i;
+ },
+
+ /**
+ * @method _delete
+ * @private
+ */
+ _delete: function(index) {
+ var s = this.subscribers[index];
+ if (s) {
+ delete s.fn;
+ delete s.obj;
+ }
+
+ this.subscribers[index]=null;
+ },
+
+ /**
+ * @method toString
+ */
+ toString: function() {
+ return "CustomEvent: " + "'" + this.type + "', " +
+ "scope: " + this.scope;
+
+ }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * Stores the subscriber information to be used when the event fires.
+ * @param {Function} fn The function to execute
+ * @param {Object} obj An object to be passed along when the event fires
+ * @param {boolean} override If true, the obj passed in becomes the execution
+ * scope of the listener
+ * @class Subscriber
+ * @constructor
+ */
+YAHOO.util.Subscriber = function(fn, obj, override) {
+
+ /**
+ * The callback that will be execute when the event fires
+ * @property fn
+ * @type function
+ */
+ this.fn = fn;
+
+ /**
+ * An optional custom object that will passed to the callback when
+ * the event fires
+ * @property obj
+ * @type object
+ */
+ this.obj = YAHOO.lang.isUndefined(obj) ? null : obj;
+
+ /**
+ * 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. If override is an object, that
+ * object becomes the scope.
+ * @property override
+ * @type boolean|object
+ */
+ this.override = override;
+
+};
+
+/**
+ * Returns the execution scope for this listener. If override was set to true
+ * the custom obj will be the scope. If override is an object, that is the
+ * scope, otherwise the default scope will be used.
+ * @method getScope
+ * @param {Object} defaultScope the scope to use if this listener does not
+ * override it.
+ */
+YAHOO.util.Subscriber.prototype.getScope = function(defaultScope) {
+ if (this.override) {
+ if (this.override === true) {
+ return this.obj;
+ } else {
+ return this.override;
+ }
+ }
+ return defaultScope;
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @method contains
+ * @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) {
+ if (obj) {
+ return (this.fn == fn && this.obj == obj);
+ } else {
+ return (this.fn == fn);
+ }
+};
+
+/**
+ * @method toString
+ */
+YAHOO.util.Subscriber.prototype.toString = function() {
+ return "Subscriber { obj: " + this.obj +
+ ", override: " + (this.override || "no") + " }";
+};
+
+/**
+ * The Event Utility provides utilities for managing DOM Events and tools
+ * for building event systems
+ *
+ * @module event
+ * @title Event Utility
+ * @namespace YAHOO.util
+ * @requires yahoo
+ */
+
+// The first instance of Event will win if it is loaded more than once.
+// @TODO this needs to be changed so that only the state data that needs to
+// be preserved is kept, while methods are overwritten/added as needed.
+// This means that the module pattern can't be used.
+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 Event
+ * @static
+ */
+ YAHOO.util.Event = function() {
+
+ /**
+ * True after the onload event has fired
+ * @property loadComplete
+ * @type boolean
+ * @static
+ * @private
+ */
+ var loadComplete = false;
+
+ /**
+ * True when the document is initially usable
+ * @property DOMReady
+ * @type boolean
+ * @static
+ * @private
+ */
+ var DOMReady = false;
+
+ /**
+ * Cache of wrapped listeners
+ * @property listeners
+ * @type array
+ * @static
+ * @private
+ */
+ var listeners = [];
+
+ /**
+ * User-defined unload function that will be fired before all events
+ * are detached
+ * @property unloadListeners
+ * @type array
+ * @static
+ * @private
+ */
+ var unloadListeners = [];
+
+ /**
+ * Cache of DOM0 event handlers to work around issues with DOM2 events
+ * in Safari
+ * @property legacyEvents
+ * @static
+ * @private
+ */
+ var legacyEvents = [];
+
+ /**
+ * Listener stack for DOM0 events
+ * @property legacyHandlers
+ * @static
+ * @private
+ */
+ var legacyHandlers = [];
+
+ /**
+ * The number of times to poll after window.onload. This number is
+ * increased if additional late-bound handlers are requested after
+ * the page load.
+ * @property retryCount
+ * @static
+ * @private
+ */
+ var retryCount = 0;
+
+ /**
+ * onAvailable listeners
+ * @property onAvailStack
+ * @static
+ * @private
+ */
+ var onAvailStack = [];
+
+ /**
+ * Lookup table for legacy events
+ * @property legacyMap
+ * @static
+ * @private
+ */
+ var legacyMap = [];
+
+ /**
+ * Counter for auto id generation
+ * @property counter
+ * @static
+ * @private
+ */
+ var counter = 0;
+
+ /**
+ * Normalized keycodes for webkit/safari
+ * @property webkitKeymap
+ * @type {int: int}
+ * @private
+ * @static
+ * @final
+ */
+ var webkitKeymap = {
+ 63232: 38, // up
+ 63233: 40, // down
+ 63234: 37, // left
+ 63235: 39 // right
+ };
+
+ return {
+
+ /**
+ * The number of times we should look for elements that are not
+ * in the DOM at the time the event is requested after the document
+ * has been loaded. The default is 4000@amp;10 ms, so it will poll
+ * for 40 seconds or until all outstanding handlers are bound
+ * (whichever comes first).
+ * @property POLL_RETRYS
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_RETRYS: 4000,
+
+ /**
+ * The poll interval in milliseconds
+ * @property POLL_INTERVAL
+ * @type int
+ * @static
+ * @final
+ */
+ POLL_INTERVAL: 10,
+
+ /**
+ * Element to bind, int constant
+ * @property EL
+ * @type int
+ * @static
+ * @final
+ */
+ EL: 0,
+
+ /**
+ * Type of event, int constant
+ * @property TYPE
+ * @type int
+ * @static
+ * @final
+ */
+ TYPE: 1,
+
+ /**
+ * Function to execute, int constant
+ * @property FN
+ * @type int
+ * @static
+ * @final
+ */
+ FN: 2,
+
+ /**
+ * Function wrapped for scope correction and cleanup, int constant
+ * @property WFN
+ * @type int
+ * @static
+ * @final
+ */
+ WFN: 3,
+
+ /**
+ * Object passed in by the user that will be returned as a
+ * parameter to the callback, int constant. Specific to
+ * unload listeners
+ * @property OBJ
+ * @type int
+ * @static
+ * @final
+ */
+ UNLOAD_OBJ: 3,
+
+ /**
+ * Adjusted scope, either the element we are registering the event
+ * on or the custom object passed in by the listener, int constant
+ * @property ADJ_SCOPE
+ * @type int
+ * @static
+ * @final
+ */
+ ADJ_SCOPE: 4,
+
+ /**
+ * The original obj passed into addListener
+ * @property OBJ
+ * @type int
+ * @static
+ * @final
+ */
+ OBJ: 5,
+
+ /**
+ * The original scope parameter passed into addListener
+ * @property OVERRIDE
+ * @type int
+ * @static
+ * @final
+ */
+ OVERRIDE: 6,
+
+ /**
+ * addListener/removeListener can throw errors in unexpected scenarios.
+ * These errors are suppressed, the method returns false, and this property
+ * is set
+ * @property lastError
+ * @static
+ * @type Error
+ */
+ lastError: null,
+
+ /**
+ * Safari detection
+ * @property isSafari
+ * @private
+ * @static
+ * @deprecated use YAHOO.env.ua.webkit
+ */
+ isSafari: YAHOO.env.ua.webkit,
+
+ /**
+ * webkit version
+ * @property webkit
+ * @type string
+ * @private
+ * @static
+ * @deprecated use YAHOO.env.ua.webkit
+ */
+ webkit: YAHOO.env.ua.webkit,
+
+ /**
+ * IE detection
+ * @property isIE
+ * @private
+ * @static
+ * @deprecated use YAHOO.env.ua.ie
+ */
+ isIE: YAHOO.env.ua.ie,
+
+ /**
+ * poll handle
+ * @property _interval
+ * @static
+ * @private
+ */
+ _interval: null,
+
+ /**
+ * @method startInterval
+ * @static
+ * @private
+ */
+ startInterval: function() {
+ if (!this._interval) {
+ var self = this;
+ var callback = function() { self._tryPreloadAttach(); };
+ this._interval = setInterval(callback, this.POLL_INTERVAL);
+ }
+ },
+
+ /**
+ * Executes the supplied callback when the item with the supplied
+ * id is found. This is meant to be used to execute behavior as
+ * soon as possible as the page loads. If you use this after the
+ * initial page load it will poll for a fixed time for the element.
+ * The number of times it will poll and the frequency are
+ * configurable. By default it will poll for 10 seconds.
+ *
+ * <p>The callback is executed with a single parameter:
+ * the custom object parameter, if provided.</p>
+ *
+ * @method onAvailable
+ *
+ * @param {string} p_id the id of the element to look for.
+ * @param {function} p_fn what to execute when the element is found.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to p_fn.
+ * @param {boolean|object} p_override If set to true, p_fn will execute
+ * in the scope of p_obj, if set to an object it
+ * will execute in the scope of that object
+ *
+ * @static
+ */
+ onAvailable: function(p_id, p_fn, p_obj, p_override) {
+ onAvailStack.push( { id: p_id,
+ fn: p_fn,
+ obj: p_obj,
+ override: p_override,
+ checkReady: false } );
+ retryCount = this.POLL_RETRYS;
+ this.startInterval();
+ },
+
+ /**
+ * Executes the supplied callback when the DOM is first usable. This
+ * will execute immediately if called after the DOMReady event has
+ * fired. @todo the DOMContentReady event does not fire when the
+ * script is dynamically injected into the page. This means the
+ * DOMReady custom event will never fire in FireFox or Opera when the
+ * library is injected. It _will_ fire in Safari, and the IE
+ * implementation would allow for us to fire it if the defered script
+ * is not available. We want this to behave the same in all browsers.
+ * Is there a way to identify when the script has been injected
+ * instead of included inline? Is there a way to know whether the
+ * window onload event has fired without having had a listener attached
+ * to it when it did so?
+ *
+ * <p>The callback is a CustomEvent, so the signature is:</p>
+ * <p>type <string>, args <array>, customobject <object></p>
+ * <p>For DOMReady events, there are no fire argments, so the
+ * signature is:</p>
+ * <p>"DOMReady", [], obj</p>
+ *
+ *
+ * @method onDOMReady
+ *
+ * @param {function} p_fn what to execute when the element is found.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to p_fn.
+ * @param {boolean|object} p_scope If set to true, p_fn will execute
+ * in the scope of p_obj, if set to an object it
+ * will execute in the scope of that object
+ *
+ * @static
+ */
+ onDOMReady: function(p_fn, p_obj, p_override) {
+ if (DOMReady) {
+ setTimeout(function() {
+ var s = window;
+ if (p_override) {
+ if (p_override === true) {
+ s = p_obj;
+ } else {
+ s = p_override;
+ }
+ }
+ p_fn.call(s, "DOMReady", [], p_obj);
+ }, 0);
+ } else {
+ this.DOMReadyEvent.subscribe(p_fn, p_obj, p_override);
+ }
+ },
+
+ /**
+ * Works the same way as onAvailable, but additionally checks the
+ * state of sibling elements to determine if the content of the
+ * available element is safe to modify.
+ *
+ * <p>The callback is executed with a single parameter:
+ * the custom object parameter, if provided.</p>
+ *
+ * @method onContentReady
+ *
+ * @param {string} p_id the id of the element to look for.
+ * @param {function} p_fn what to execute when the element is ready.
+ * @param {object} p_obj an optional object to be passed back as
+ * a parameter to p_fn.
+ * @param {boolean|object} p_override If set to true, p_fn will execute
+ * in the scope of p_obj. If an object, p_fn will
+ * exectute in the scope of that object
+ *
+ * @static
+ */
+ onContentReady: function(p_id, p_fn, p_obj, p_override) {
+ onAvailStack.push( { id: p_id,
+ fn: p_fn,
+ obj: p_obj,
+ override: p_override,
+ checkReady: true } );
+
+ retryCount = this.POLL_RETRYS;
+ this.startInterval();
+ },
+
+ /**
+ * Appends an event handler
+ *
+ * @method addListener
+ *
+ * @param {String|HTMLElement|Array|NodeList} el An id, an element
+ * reference, or a collection of ids and/or elements to assign the
+ * listener to.
+ * @param {String} sType The type of event to append
+ * @param {Function} fn The method the event invokes
+ * @param {Object} obj An arbitrary object that will be
+ * passed as a parameter to the handler
+ * @param {Boolean|object} override If true, the obj passed in becomes
+ * the execution scope of the listener. If an
+ * object, this object becomes the execution
+ * scope.
+ * @return {Boolean} True if the action was successful or defered,
+ * false if one or more of the elements
+ * could not have the listener attached,
+ * or if the operation throws an exception.
+ * @static
+ */
+ addListener: function(el, sType, fn, obj, override) {
+
+ if (!fn || !fn.call) {
+// throw new TypeError(sType + " addListener call failed, callback undefined");
+ return false;
+ }
+
+ // The el argument can be an array of elements or element ids.
+ if ( this._isValidCollection(el)) {
+ var ok = true;
+ for (var i=0,len=el.length; i<len; ++i) {
+ ok = this.on(el[i],
+ sType,
+ fn,
+ obj,
+ override) && ok;
+ }
+ return ok;
+
+ } else if (YAHOO.lang.isString(el)) {
+ var oEl = this.getEl(el);
+ // 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 (oEl) {
+ el = oEl;
+ } else {
+ // defer adding the event until the element is available
+ this.onAvailable(el, function() {
+ YAHOO.util.Event.on(el, sType, fn, obj, override);
+ });
+
+ 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 && obj !== this) {
+ unloadListeners[unloadListeners.length] =
+ [el, sType, fn, obj, override];
+ 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 = el;
+ if (override) {
+ if (override === true) {
+ scope = obj;
+ } else {
+ scope = override;
+ }
+ }
+
+ // wrap the function so we can return the obj object when
+ // the event fires;
+ var wrappedFn = function(e) {
+ return fn.call(scope, YAHOO.util.Event.getEvent(e, el),
+ obj);
+ };
+
+ var li = [el, sType, fn, wrappedFn, scope, obj, override];
+ 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);
+
+ // Add a new dom0 wrapper if one is not detected for this
+ // element
+ if ( legacyIndex == -1 ||
+ el != legacyEvents[legacyIndex][0] ) {
+
+ legacyIndex = legacyEvents.length;
+ legacyMap[el.id + sType] = legacyIndex;
+
+ // 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);
+ legacyHandlers[legacyIndex].push(li);
+
+ } else {
+ try {
+ this._simpleAdd(el, sType, wrappedFn, false);
+ } catch(ex) {
+ // handle an error trying to attach an event. If it fails
+ // we need to clean up the cache
+ this.lastError = ex;
+ this.removeListener(el, sType, fn);
+ return false;
+ }
+ }
+
+ return true;
+
+ },
+
+ /**
+ * When using legacy events, the handler is routed to this object
+ * so we can fire our custom listener stack.
+ * @method fireLegacyEvent
+ * @static
+ * @private
+ */
+ fireLegacyEvent: function(e, legacyIndex) {
+ var ok=true,le,lh,li,scope,ret;
+
+ lh = legacyHandlers[legacyIndex];
+ for (var i=0,len=lh.length; i<len; ++i) {
+ li = lh[i];
+ if ( li && li[this.WFN] ) {
+ scope = li[this.ADJ_SCOPE];
+ ret = li[this.WFN].call(scope, e);
+ ok = (ok && ret);
+ }
+ }
+
+ // Fire the original handler if we replaced one. We fire this
+ // after the other events to keep stopPropagation/preventDefault
+ // that happened in the DOM0 handler from touching our DOM2
+ // substitute
+ le = legacyEvents[legacyIndex];
+ if (le && le[2]) {
+ le[2](e);
+ }
+
+ return ok;
+ },
+
+ /**
+ * Returns the legacy event index that matches the supplied
+ * signature
+ * @method getLegacyIndex
+ * @static
+ * @private
+ */
+ getLegacyIndex: function(el, sType) {
+ var key = this.generateId(el) + sType;
+ if (typeof legacyMap[key] == "undefined") {
+ return -1;
+ } else {
+ return legacyMap[key];
+ }
+ },
+
+ /**
+ * Logic that determines when we should automatically use legacy
+ * events instead of DOM2 events. Currently this is limited to old
+ * Safari browsers with a broken preventDefault
+ * @method useLegacyEvent
+ * @static
+ * @private
+ */
+ useLegacyEvent: function(el, sType) {
+ if (this.webkit && ("click"==sType || "dblclick"==sType)) {
+ var v = parseInt(this.webkit, 10);
+ if (!isNaN(v) && v<418) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * Removes an event listener
+ *
+ * @method removeListener
+ *
+ * @param {String|HTMLElement|Array|NodeList} el An id, an element
+ * reference, or a collection of ids and/or elements to remove
+ * the listener from.
+ * @param {String} sType the type of event to remove.
+ * @param {Function} fn the method the event invokes. If fn is
+ * undefined, then all event handlers for the type of event are
+ * removed.
+ * @return {boolean} true if the unbind was successful, false
+ * otherwise.
+ * @static
+ */
+ removeListener: function(el, sType, fn) {
+ var i, len, li;
+
+ // 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 (i=0,len=el.length; i<len; ++i) {
+ ok = ( this.removeListener(el[i], sType, fn) && ok );
+ }
+ return ok;
+ }
+
+ if (!fn || !fn.call) {
+ //return false;
+ return this.purgeElement(el, false, sType);
+ }
+
+ if ("unload" == sType) {
+
+ for (i=0, len=unloadListeners.length; i<len; i++) {
+ li = unloadListeners[i];
+ if (li &&
+ li[0] == el &&
+ li[1] == sType &&
+ li[2] == fn) {
+ //unloadListeners.splice(i, 1);
+ unloadListeners[i]=null;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ var cacheItem = null;
+
+ // The index is a hidden parameter; needed to remove it from
+ // the method signature because it was tempting users to
+ // try and take advantage of it, which is not possible.
+ var index = arguments[3];
+
+ if ("undefined" === typeof index) {
+ index = this._getCacheIndex(el, sType, fn);
+ }
+
+ if (index >= 0) {
+ cacheItem = listeners[index];
+ }
+
+ if (!el || !cacheItem) {
+ return false;
+ }
+
+
+ if (this.useLegacyEvent(el, sType)) {
+ var legacyIndex = this.getLegacyIndex(el, sType);
+ var llist = legacyHandlers[legacyIndex];
+ if (llist) {
+ for (i=0, len=llist.length; i<len; ++i) {
+ li = llist[i];
+ if (li &&
+ li[this.EL] == el &&
+ li[this.TYPE] == sType &&
+ li[this.FN] == fn) {
+ //llist.splice(i, 1);
+ llist[i]=null;
+ break;
+ }
+ }
+ }
+
+ } else {
+ try {
+ this._simpleRemove(el, sType, cacheItem[this.WFN], false);
+ } catch(ex) {
+ this.lastError = ex;
+ return false;
+ }
+ }
+
+ // removed the wrapped handler
+ delete listeners[index][this.WFN];
+ delete listeners[index][this.FN];
+ //listeners.splice(index, 1);
+ listeners[index]=null;
+
+ return true;
+
+ },
+
+ /**
+ * Returns the event's target element. Safari sometimes provides
+ * a text node, and this is automatically resolved to the text
+ * node's parent so that it behaves like other browsers.
+ * @method getTarget
+ * @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. @deprecated, the text node is
+ * now resolved automatically
+ * @return {HTMLElement} the event's target
+ * @static
+ */
+ getTarget: function(ev, resolveTextNode) {
+ var t = ev.target || ev.srcElement;
+ return this.resolveTextNode(t);
+ },
+
+ /**
+ * In some cases, some browsers will return a text node inside
+ * the actual element that was targeted. This normalizes the
+ * return value for getTarget and getRelatedTarget.
+ * @method resolveTextNode
+ * @param {HTMLElement} node node to resolve
+ * @return {HTMLElement} the normized node
+ * @static
+ */
+ resolveTextNode: function(node) {
+ if (node && 3 == node.nodeType) {
+ return node.parentNode;
+ } else {
+ return node;
+ }
+ },
+
+ /**
+ * Returns the event's pageX
+ * @method getPageX
+ * @param {Event} ev the event
+ * @return {int} the event's pageX
+ * @static
+ */
+ 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
+ * @method getPageY
+ * @param {Event} ev the event
+ * @return {int} the event's pageY
+ * @static
+ */
+ 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 pageX and pageY properties as an indexed array.
+ * @method getXY
+ * @param {Event} ev the event
+ * @return {[x, y]} the pageX and pageY properties of the event
+ * @static
+ */
+ getXY: function(ev) {
+ return [this.getPageX(ev), this.getPageY(ev)];
+ },
+
+ /**
+ * Returns the event's related target
+ * @method getRelatedTarget
+ * @param {Event} ev the event
+ * @return {HTMLElement} the event's relatedTarget
+ * @static
+ */
+ 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 this.resolveTextNode(t);
+ },
+
+ /**
+ * Returns the time of the event. If the time is not included, the
+ * event is modified using the current time.
+ * @method getTime
+ * @param {Event} ev the event
+ * @return {Date} the time of the event
+ * @static
+ */
+ getTime: function(ev) {
+ if (!ev.time) {
+ var t = new Date().getTime();
+ try {
+ ev.time = t;
+ } catch(ex) {
+ this.lastError = ex;
+ return t;
+ }
+ }
+
+ return ev.time;
+ },
+
+ /**
+ * Convenience method for stopPropagation + preventDefault
+ * @method stopEvent
+ * @param {Event} ev the event
+ * @static
+ */
+ stopEvent: function(ev) {
+ this.stopPropagation(ev);
+ this.preventDefault(ev);
+ },
+
+ /**
+ * Stops event propagation
+ * @method stopPropagation
+ * @param {Event} ev the event
+ * @static
+ */
+ stopPropagation: function(ev) {
+ if (ev.stopPropagation) {
+ ev.stopPropagation();
+ } else {
+ ev.cancelBubble = true;
+ }
+ },
+
+ /**
+ * Prevents the default behavior of the event
+ * @method preventDefault
+ * @param {Event} ev the event
+ * @static
+ */
+ preventDefault: function(ev) {
+ if (ev.preventDefault) {
+ ev.preventDefault();
+ } else {
+ ev.returnValue = false;
+ }
+ },
+
+ /**
+ * Finds the event in the window object, the caller's arguments, or
+ * in the arguments of another method in the callstack. This is
+ * executed automatically for events registered through the event
+ * manager, so the implementer should not normally need to execute
+ * this function at all.
+ * @method getEvent
+ * @param {Event} e the event parameter from the handler
+ * @param {HTMLElement} boundEl the element the listener is attached to
+ * @return {Event} the event
+ * @static
+ */
+ getEvent: function(e, boundEl) {
+ 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;
+ }
+ }
+
+ // IE events that target non-browser objects (e.g., VML
+ // canvas) will sometimes throw errors when you try to
+ // inspect the properties of the event target. We try to
+ // detect this condition, and provide a dummy target (the bound
+ // element) to eliminate spurious errors.
+ if (ev && this.isIE) {
+
+ try {
+
+ var el = ev.srcElement;
+ if (el) {
+ var type = el.type;
+ }
+
+ } catch(ex) {
+
+
+ ev.target = boundEl;
+ }
+
+ }
+
+ return ev;
+ },
+
+ /**
+ * Returns the charcode for an event
+ * @method getCharCode
+ * @param {Event} ev the event
+ * @return {int} the event's charCode
+ * @static
+ */
+ getCharCode: function(ev) {
+ var code = ev.keyCode || ev.charCode || 0;
+
+ // webkit normalization
+ if (YAHOO.env.ua.webkit && (code in webkitKeymap)) {
+ code = webkitKeymap[code];
+ }
+ return code;
+ },
+
+ /**
+ * Locating the saved event handler data by function ref
+ *
+ * @method _getCacheIndex
+ * @static
+ * @private
+ */
+ _getCacheIndex: function(el, sType, fn) {
+ for (var i=0,len=listeners.length; i<len; ++i) {
+ var li = listeners[i];
+ if ( li &&
+ li[this.FN] == fn &&
+ li[this.EL] == el &&
+ li[this.TYPE] == sType ) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ /**
+ * Generates an unique ID for the element if it does not already
+ * have one.
+ * @method generateId
+ * @param el the element to create the id for
+ * @return {string} the resulting id of the element
+ * @static
+ */
+ generateId: function(el) {
+ var id = el.id;
+
+ if (!id) {
+ id = "yuievtautoid-" + counter;
+ ++counter;
+ el.id = id;
+ }
+
+ return id;
+ },
+
+
+ /**
+ * 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.
+ * @method _isValidCollection
+ * @param o the object to test
+ * @return {boolean} true if the object is array-like and populated
+ * @static
+ * @private
+ */
+ _isValidCollection: function(o) {
+ try {
+ return ( typeof o !== "string" && // o is not a string
+ o.length && // o is indexed
+ !o.tagName && // o is not an HTML element
+ !o.alert && // o is not a window
+ typeof o[0] !== "undefined" );
+ } catch(e) {
+ return false;
+ }
+
+ },
+
+ /**
+ * @private
+ * @property elCache
+ * DOM element cache
+ * @static
+ * @deprecated Elements are not cached due to issues that arise when
+ * elements are removed and re-added
+ */
+ elCache: {},
+
+ /**
+ * We cache elements bound by id because when the unload event
+ * fires, we can no longer use document.getElementById
+ * @method getEl
+ * @static
+ * @private
+ * @deprecated Elements are not cached any longer
+ */
+ getEl: function(id) {
+ return (typeof id === "string") ? document.getElementById(id) : id;
+ },
+
+ /**
+ * Clears the element cache
+ * @deprecated Elements are not cached any longer
+ * @method clearCache
+ * @static
+ * @private
+ */
+ clearCache: function() { },
+
+ /**
+ * Custom event the fires when the dom is initially usable
+ * @event DOMReadyEvent
+ */
+ DOMReadyEvent: new YAHOO.util.CustomEvent("DOMReady", this),
+
+ /**
+ * hook up any deferred listeners
+ * @method _load
+ * @static
+ * @private
+ */
+ _load: function(e) {
+
+ if (!loadComplete) {
+ loadComplete = true;
+ var EU = YAHOO.util.Event;
+
+ // Just in case DOMReady did not go off for some reason
+ EU._ready();
+
+ // Available elements may not have been detected before the
+ // window load event fires. Try to find them now so that the
+ // the user is more likely to get the onAvailable notifications
+ // before the window load notification
+ EU._tryPreloadAttach();
+
+ // Remove the listener to assist with the IE memory issue, but not
+ // for other browsers because FF 1.0x does not like it.
+ //if (this.isIE) {
+ //EU._simpleRemove(window, "load", EU._load);
+ //}
+ }
+ },
+
+ /**
+ * Fires the DOMReady event listeners the first time the document is
+ * usable.
+ * @method _ready
+ * @static
+ * @private
+ */
+ _ready: function(e) {
+ if (!DOMReady) {
+ DOMReady=true;
+ var EU = YAHOO.util.Event;
+
+ // Fire the content ready custom event
+ EU.DOMReadyEvent.fire();
+
+ // Remove the DOMContentLoaded (FF/Opera)
+ EU._simpleRemove(document, "DOMContentLoaded", EU._ready);
+ }
+ },
+
+ /**
+ * Polling function that runs before the onload event fires,
+ * attempting to attach to DOM Nodes as soon as they are
+ * available
+ * @method _tryPreloadAttach
+ * @static
+ * @private
+ */
+ _tryPreloadAttach: function() {
+
+ if (this.locked) {
+ return false;
+ }
+
+ if (this.isIE) {
+ // Hold off if DOMReady has not fired and check current
+ // readyState to protect against the IE operation aborted
+ // issue.
+ //if (!DOMReady || "complete" !== document.readyState) {
+ if (!DOMReady) {
+ this.startInterval();
+ return false;
+ }
+ }
+
+ this.locked = true;
+
+
+ // 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;
+ if (!tryAgain) {
+ tryAgain = (retryCount > 0);
+ }
+
+ // onAvailable
+ var notAvail = [];
+
+ var executeItem = function (el, item) {
+ var scope = el;
+ if (item.override) {
+ if (item.override === true) {
+ scope = item.obj;
+ } else {
+ scope = item.override;
+ }
+ }
+ item.fn.call(scope, item.obj);
+ };
+
+ var i,len,item,el;
+
+ // onAvailable
+ for (i=0,len=onAvailStack.length; i<len; ++i) {
+ item = onAvailStack[i];
+ if (item && !item.checkReady) {
+ el = this.getEl(item.id);
+ if (el) {
+ executeItem(el, item);
+ onAvailStack[i] = null;
+ } else {
+ notAvail.push(item);
+ }
+ }
+ }
+
+ // onContentReady
+ for (i=0,len=onAvailStack.length; i<len; ++i) {
+ item = onAvailStack[i];
+ if (item && item.checkReady) {
+ el = this.getEl(item.id);
+
+ if (el) {
+ // The element is available, but not necessarily ready
+ // @todo should we test parentNode.nextSibling?
+ if (loadComplete || el.nextSibling) {
+ executeItem(el, item);
+ onAvailStack[i] = null;
+ }
+ } else {
+ notAvail.push(item);
+ }
+ }
+ }
+
+ retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
+
+ if (tryAgain) {
+ // we may need to strip the nulled out items here
+ this.startInterval();
+ } else {
+ clearInterval(this._interval);
+ this._interval = null;
+ }
+
+ this.locked = false;
+
+ return true;
+
+ },
+
+ /**
+ * Removes all listeners attached to the given element via addListener.
+ * Optionally, the node's children can also be purged.
+ * Optionally, you can specify a specific type of event to remove.
+ * @method purgeElement
+ * @param {HTMLElement} el the element to purge
+ * @param {boolean} recurse recursively purge this element's children
+ * as well. Use with caution.
+ * @param {string} sType optional type of listener to purge. If
+ * left out, all listeners will be removed
+ * @static
+ */
+ purgeElement: function(el, recurse, sType) {
+ var elListeners = this.getListeners(el, sType), i, len;
+ if (elListeners) {
+ for (i=0,len=elListeners.length; i<len ; ++i) {
+ var l = elListeners[i];
+ // can't use the index on the changing collection
+ this.removeListener(el, l.type, l.fn, l.index);
+ //this.removeListener(el, l.type, l.fn);
+ }
+ }
+
+ if (recurse && el && el.childNodes) {
+ for (i=0,len=el.childNodes.length; i<len ; ++i) {
+ this.purgeElement(el.childNodes[i], recurse, sType);
+ }
+ }
+ },
+
+ /**
+ * Returns all listeners attached to the given element via addListener.
+ * Optionally, you can specify a specific type of event to return.
+ * @method getListeners
+ * @param el {HTMLElement} the element to inspect
+ * @param sType {string} optional type of listener to return. If
+ * left out, all listeners will be returned
+ * @return {Object} the listener. Contains the following fields:
+ * type: (string) the type of event
+ * fn: (function) the callback supplied to addListener
+ * obj: (object) the custom object supplied to addListener
+ * adjust: (boolean|object) whether or not to adjust the default scope
+ * scope: (boolean) the derived scope based on the adjust parameter
+ * index: (int) its position in the Event util listener cache
+ * @static
+ */
+ getListeners: function(el, sType) {
+ var results=[], searchLists;
+ if (!sType) {
+ searchLists = [listeners, unloadListeners];
+ } else if (sType == "unload") {
+ searchLists = [unloadListeners];
+ } else {
+ searchLists = [listeners];
+ }
+
+ for (var j=0;j<searchLists.length; j=j+1) {
+ var searchList = searchLists[j];
+ if (searchList && searchList.length > 0) {
+ for (var i=0,len=searchList.length; i<len ; ++i) {
+ var l = searchList[i];
+ if ( l && l[this.EL] === el &&
+ (!sType || sType === l[this.TYPE]) ) {
+ results.push({
+ type: l[this.TYPE],
+ fn: l[this.FN],
+ obj: l[this.OBJ],
+ adjust: l[this.OVERRIDE],
+ scope: l[this.ADJ_SCOPE],
+ index: i
+ });
+ }
+ }
+ }
+ }
+
+ return (results.length) ? results : null;
+ },
+
+ /**
+ * Removes all listeners registered by pe.event. Called
+ * automatically during the unload event.
+ * @method _unload
+ * @static
+ * @private
+ */
+ _unload: function(e) {
+
+ var EU = YAHOO.util.Event, i, j, l, len, index;
+
+ for (i=0,len=unloadListeners.length; i<len; ++i) {
+ l = unloadListeners[i];
+ if (l) {
+ var scope = window;
+ if (l[EU.ADJ_SCOPE]) {
+ if (l[EU.ADJ_SCOPE] === true) {
+ scope = l[EU.UNLOAD_OBJ];
+ } else {
+ scope = l[EU.ADJ_SCOPE];
+ }
+ }
+ l[EU.FN].call(scope, EU.getEvent(e, l[EU.EL]), l[EU.UNLOAD_OBJ] );
+ unloadListeners[i] = null;
+ l=null;
+ scope=null;
+ }
+ }
+
+ unloadListeners = null;
+
+ if (listeners && listeners.length > 0) {
+ j = listeners.length;
+ while (j) {
+ index = j-1;
+ l = listeners[index];
+ if (l) {
+ EU.removeListener(l[EU.EL], l[EU.TYPE], l[EU.FN], index);
+ }
+ j = j - 1;
+ }
+ l=null;
+
+ EU.clearCache();
+ }
+
+ for (i=0,len=legacyEvents.length; i<len; ++i) {
+ // dereference the element
+ //delete legacyEvents[i][0];
+ legacyEvents[i][0] = null;
+
+ // delete the array item
+ //delete legacyEvents[i];
+ legacyEvents[i] = null;
+ }
+
+ legacyEvents = null;
+
+ EU._simpleRemove(window, "unload", EU._unload);
+
+ },
+
+ /**
+ * Returns scrollLeft
+ * @method _getScrollLeft
+ * @static
+ * @private
+ */
+ _getScrollLeft: function() {
+ return this._getScroll()[1];
+ },
+
+ /**
+ * Returns scrollTop
+ * @method _getScrollTop
+ * @static
+ * @private
+ */
+ _getScrollTop: function() {
+ return this._getScroll()[0];
+ },
+
+ /**
+ * Returns the scrollTop and scrollLeft. Used to calculate the
+ * pageX and pageY in Internet Explorer
+ * @method _getScroll
+ * @static
+ * @private
+ */
+ _getScroll: function() {
+ var dd = document.documentElement, db = document.body;
+ if (dd && (dd.scrollTop || dd.scrollLeft)) {
+ return [dd.scrollTop, dd.scrollLeft];
+ } else if (db) {
+ return [db.scrollTop, db.scrollLeft];
+ } else {
+ return [0, 0];
+ }
+ },
+
+ /**
+ * Used by old versions of CustomEvent, restored for backwards
+ * compatibility
+ * @method regCE
+ * @private
+ * @static
+ * @deprecated still here for backwards compatibility
+ */
+ regCE: function() {
+ // does nothing
+ },
+
+ /**
+ * Adds a DOM event directly without the caching, cleanup, scope adj, etc
+ *
+ * @method _simpleAdd
+ * @param {HTMLElement} el the element to bind the handler to
+ * @param {string} sType the type of event handler
+ * @param {function} fn the callback to invoke
+ * @param {boolen} capture capture or bubble phase
+ * @static
+ * @private
+ */
+ _simpleAdd: function () {
+ if (window.addEventListener) {
+ return function(el, sType, fn, capture) {
+ el.addEventListener(sType, fn, (capture));
+ };
+ } else if (window.attachEvent) {
+ return function(el, sType, fn, capture) {
+ el.attachEvent("on" + sType, fn);
+ };
+ } else {
+ return function(){};
+ }
+ }(),
+
+ /**
+ * Basic remove listener
+ *
+ * @method _simpleRemove
+ * @param {HTMLElement} el the element to bind the handler to
+ * @param {string} sType the type of event handler
+ * @param {function} fn the callback to invoke
+ * @param {boolen} capture capture or bubble phase
+ * @static
+ * @private
+ */
+ _simpleRemove: function() {
+ if (window.removeEventListener) {
+ return function (el, sType, fn, capture) {
+ el.removeEventListener(sType, fn, (capture));
+ };
+ } else if (window.detachEvent) {
+ return function (el, sType, fn) {
+ el.detachEvent("on" + sType, fn);
+ };
+ } else {
+ return function(){};
+ }
+ }()
+ };
+
+ }();
+
+ (function() {
+ var EU = YAHOO.util.Event;
+
+ /**
+ * YAHOO.util.Event.on is an alias for addListener
+ * @method on
+ * @see addListener
+ * @static
+ */
+ EU.on = EU.addListener;
+
+ /////////////////////////////////////////////////////////////
+ // DOMReady
+ // based on work by: Dean Edwards/John Resig/Matthias Miller
+
+ // Internet Explorer: use the readyState of a defered script.
+ // This isolates what appears to be a safe moment to manipulate
+ // the DOM prior to when the document's readyState suggests
+ // it is safe to do so.
+ if (EU.isIE) {
+
+ // Process onAvailable/onContentReady items when when the
+ // DOM is ready.
+ YAHOO.util.Event.onDOMReady(
+ YAHOO.util.Event._tryPreloadAttach,
+ YAHOO.util.Event, true);
+
+
+ var el, d=document, b=d.body;
+
+ // If the library is being injected after window.onload, it
+ // is not safe to document.write the script tag. Detecting
+ // this state doesn't appear possible, so we expect a flag
+ // in YAHOO_config to be set if the library is being injected.
+ if (("undefined" !== typeof YAHOO_config) && YAHOO_config.injecting) {
+
+ el = document.createElement("script");
+ var p=d.getElementsByTagName("head")[0] || b;
+ p.insertBefore(el, p.firstChild);
+
+ } else {
+ d.write('<scr'+'ipt id="_yui_eu_dr" defer="true" src="//:"><'+'/script>');
+ el=document.getElementById("_yui_eu_dr");
+ }
+
+
+ if (el) {
+ el.onreadystatechange = function() {
+ if ("complete" === this.readyState) {
+ this.parentNode.removeChild(this);
+ YAHOO.util.Event._ready();
+ }
+ };
+ } else {
+ // The library was likely injected into the page
+ // rendering onDOMReady unreliable
+ // YAHOO.util.Event._ready();
+ }
+
+ el=null;
+
+
+ // Safari: The document's readyState in Safari currently will
+ // change to loaded/complete before images are loaded.
+ //} else if (EU.webkit) {
+ } else if (EU.webkit) {
+
+ EU._drwatch = setInterval(function(){
+ var rs=document.readyState;
+ if ("loaded" == rs || "complete" == rs) {
+ clearInterval(EU._drwatch);
+ EU._drwatch = null;
+ EU._ready();
+ }
+ }, EU.POLL_INTERVAL);
+
+ // FireFox and Opera: These browsers provide a event for this
+ // moment.
+ } else {
+
+ // @todo will this fire when the library is injected?
+
+ EU._simpleAdd(document, "DOMContentLoaded", EU._ready);
+
+ }
+ /////////////////////////////////////////////////////////////
+
+
+ EU._simpleAdd(window, "load", EU._load);
+ EU._simpleAdd(window, "unload", EU._unload);
+ EU._tryPreloadAttach();
+ })();
+
+}
+/**
+ * EventProvider is designed to be used with YAHOO.augment to wrap
+ * CustomEvents in an interface that allows events to be subscribed to
+ * and fired by name. This makes it possible for implementing code to
+ * subscribe to an event that either has not been created yet, or will
+ * not be created at all.
+ *
+ * @Class EventProvider
+ */
+YAHOO.util.EventProvider = function() { };
+
+YAHOO.util.EventProvider.prototype = {
+
+ /**
+ * Private storage of custom events
+ * @property __yui_events
+ * @type Object[]
+ * @private
+ */
+ __yui_events: null,
+
+ /**
+ * Private storage of custom event subscribers
+ * @property __yui_subscribers
+ * @type Object[]
+ * @private
+ */
+ __yui_subscribers: null,
+
+ /**
+ * Subscribe to a CustomEvent by event type
+ *
+ * @method subscribe
+ * @param p_type {string} the type, or name of the event
+ * @param p_fn {function} the function to exectute when the event fires
+ * @param p_obj {Object} An object to be passed along when the event
+ * fires
+ * @param p_override {boolean} If true, the obj passed in becomes the
+ * execution scope of the listener
+ */
+ subscribe: function(p_type, p_fn, p_obj, p_override) {
+
+ this.__yui_events = this.__yui_events || {};
+ var ce = this.__yui_events[p_type];
+
+ if (ce) {
+ ce.subscribe(p_fn, p_obj, p_override);
+ } else {
+ this.__yui_subscribers = this.__yui_subscribers || {};
+ var subs = this.__yui_subscribers;
+ if (!subs[p_type]) {
+ subs[p_type] = [];
+ }
+ subs[p_type].push(
+ { fn: p_fn, obj: p_obj, override: p_override } );
+ }
+ },
+
+ /**
+ * Unsubscribes one or more listeners the from the specified event
+ * @method unsubscribe
+ * @param p_type {string} The type, or name of the event. If the type
+ * is not specified, it will attempt to remove
+ * the listener from all hosted events.
+ * @param p_fn {Function} The subscribed function to unsubscribe, if not
+ * supplied, all subscribers will be removed.
+ * @param p_obj {Object} The custom object passed to subscribe. This is
+ * optional, but if supplied will be used to
+ * disambiguate multiple listeners that are the same
+ * (e.g., you subscribe many object using a function
+ * that lives on the prototype)
+ * @return {boolean} true if the subscriber was found and detached.
+ */
+ unsubscribe: function(p_type, p_fn, p_obj) {
+ this.__yui_events = this.__yui_events || {};
+ var evts = this.__yui_events;
+ if (p_type) {
+ var ce = evts[p_type];
+ if (ce) {
+ return ce.unsubscribe(p_fn, p_obj);
+ }
+ } else {
+ var ret = true;
+ for (var i in evts) {
+ if (YAHOO.lang.hasOwnProperty(evts, i)) {
+ ret = ret && evts[i].unsubscribe(p_fn, p_obj);
+ }
+ }
+ return ret;
+ }
+
+ return false;
+ },
+
+ /**
+ * Removes all listeners from the specified event. If the event type
+ * is not specified, all listeners from all hosted custom events will
+ * be removed.
+ * @method unsubscribeAll
+ * @param p_type {string} The type, or name of the event
+ */
+ unsubscribeAll: function(p_type) {
+ return this.unsubscribe(p_type);
+ },
+
+ /**
+ * Creates a new custom event of the specified type. If a custom event
+ * by that name already exists, it will not be re-created. In either
+ * case the custom event is returned.
+ *
+ * @method createEvent
+ *
+ * @param p_type {string} the type, or name of the event
+ * @param p_config {object} optional config params. Valid properties are:
+ *
+ * <ul>
+ * <li>
+ * scope: defines the default execution scope. If not defined
+ * the default scope will be this instance.
+ * </li>
+ * <li>
+ * silent: if true, the custom event will not generate log messages.
+ * This is false by default.
+ * </li>
+ * <li>
+ * onSubscribeCallback: specifies a callback to execute when the
+ * event has a new subscriber. This will fire immediately for
+ * each queued subscriber if any exist prior to the creation of
+ * the event.
+ * </li>
+ * </ul>
+ *
+ * @return {CustomEvent} the custom event
+ *
+ */
+ createEvent: function(p_type, p_config) {
+
+ this.__yui_events = this.__yui_events || {};
+ var opts = p_config || {};
+ var events = this.__yui_events;
+
+ if (events[p_type]) {
+ } else {
+
+ var scope = opts.scope || this;
+ var silent = (opts.silent);
+
+ var ce = new YAHOO.util.CustomEvent(p_type, scope, silent,
+ YAHOO.util.CustomEvent.FLAT);
+ events[p_type] = ce;
+
+ if (opts.onSubscribeCallback) {
+ ce.subscribeEvent.subscribe(opts.onSubscribeCallback);
+ }
+
+ this.__yui_subscribers = this.__yui_subscribers || {};
+ var qs = this.__yui_subscribers[p_type];
+
+ if (qs) {
+ for (var i=0; i<qs.length; ++i) {
+ ce.subscribe(qs[i].fn, qs[i].obj, qs[i].override);
+ }
+ }
+ }
+
+ return events[p_type];
+ },
+
+
+ /**
+ * Fire a custom event by name. The callback functions will be executed
+ * from the scope specified when the event was created, and with the
+ * following parameters:
+ * <ul>
+ * <li>The first argument fire() was executed with</li>
+ * <li>The custom object (if any) that was passed into the subscribe()
+ * method</li>
+ * </ul>
+ * If the custom event has not been explicitly created, it will be
+ * created now with the default config, scoped to the host object
+ * @method fireEvent
+ * @param p_type {string} the type, or name of the event
+ * @param arguments {Object*} an arbitrary set of parameters to pass to
+ * the handler.
+ * @return {boolean} the return value from CustomEvent.fire
+ *
+ */
+ fireEvent: function(p_type, arg1, arg2, etc) {
+
+ this.__yui_events = this.__yui_events || {};
+ var ce = this.__yui_events[p_type];
+
+ if (!ce) {
+ return null;
+ }
+
+ var args = [];
+ for (var i=1; i<arguments.length; ++i) {
+ args.push(arguments[i]);
+ }
+ return ce.fire.apply(ce, args);
+ },
+
+ /**
+ * Returns true if the custom event of the provided type has been created
+ * with createEvent.
+ * @method hasEvent
+ * @param type {string} the type, or name of the event
+ */
+ hasEvent: function(type) {
+ if (this.__yui_events) {
+ if (this.__yui_events[type]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+};
+
+/**
+* KeyListener is a utility that provides an easy interface for listening for
+* keydown/keyup events fired against DOM elements.
+* @namespace YAHOO.util
+* @class KeyListener
+* @constructor
+* @param {HTMLElement} attachTo The element or element ID to which the key
+* event should be attached
+* @param {String} attachTo The element or element ID to which the key
+* event should be attached
+* @param {Object} keyData The object literal representing the key(s)
+* to detect. Possible attributes are
+* shift(boolean), alt(boolean), ctrl(boolean)
+* and keys(either an int or an array of ints
+* representing keycodes).
+* @param {Function} handler The CustomEvent handler to fire when the
+* key event is detected
+* @param {Object} handler An object literal representing the handler.
+* @param {String} event Optional. The event (keydown or keyup) to
+* listen for. Defaults automatically to keydown.
+*
+* @knownissue the "keypress" event is completely broken in Safari 2.x and below.
+* the workaround is use "keydown" for key listening. However, if
+* it is desired to prevent the default behavior of the keystroke,
+* that can only be done on the keypress event. This makes key
+* handling quite ugly.
+* @knownissue keydown is also broken in Safari 2.x and below for the ESC key.
+* There currently is no workaround other than choosing another
+* key to listen for.
+*/
+YAHOO.util.KeyListener = function(attachTo, keyData, handler, event) {
+ if (!attachTo) {
+ } else if (!keyData) {
+ } else if (!handler) {
+ }
+
+ if (!event) {
+ event = YAHOO.util.KeyListener.KEYDOWN;
+ }
+
+ /**
+ * The CustomEvent fired internally when a key is pressed
+ * @event keyEvent
+ * @private
+ * @param {Object} keyData The object literal representing the key(s) to
+ * detect. Possible attributes are shift(boolean),
+ * alt(boolean), ctrl(boolean) and keys(either an
+ * int or an array of ints representing keycodes).
+ */
+ var keyEvent = new YAHOO.util.CustomEvent("keyPressed");
+
+ /**
+ * The CustomEvent fired when the KeyListener is enabled via the enable()
+ * function
+ * @event enabledEvent
+ * @param {Object} keyData The object literal representing the key(s) to
+ * detect. Possible attributes are shift(boolean),
+ * alt(boolean), ctrl(boolean) and keys(either an
+ * int or an array of ints representing keycodes).
+ */
+ this.enabledEvent = new YAHOO.util.CustomEvent("enabled");
+
+ /**
+ * The CustomEvent fired when the KeyListener is disabled via the
+ * disable() function
+ * @event disabledEvent
+ * @param {Object} keyData The object literal representing the key(s) to
+ * detect. Possible attributes are shift(boolean),
+ * alt(boolean), ctrl(boolean) and keys(either an
+ * int or an array of ints representing keycodes).
+ */
+ this.disabledEvent = new YAHOO.util.CustomEvent("disabled");
+
+ if (typeof attachTo == 'string') {
+ attachTo = document.getElementById(attachTo);
+ }
+
+ if (typeof handler == 'function') {
+ keyEvent.subscribe(handler);
+ } else {
+ keyEvent.subscribe(handler.fn, handler.scope, handler.correctScope);
+ }
+
+ /**
+ * Handles the key event when a key is pressed.
+ * @method handleKeyPress
+ * @param {DOMEvent} e The keypress DOM event
+ * @param {Object} obj The DOM event scope object
+ * @private
+ */
+ function handleKeyPress(e, obj) {
+ if (! keyData.shift) {
+ keyData.shift = false;
+ }
+ if (! keyData.alt) {
+ keyData.alt = false;
+ }
+ if (! keyData.ctrl) {
+ keyData.ctrl = false;
+ }
+
+ // check held down modifying keys first
+ if (e.shiftKey == keyData.shift &&
+ e.altKey == keyData.alt &&
+ e.ctrlKey == keyData.ctrl) { // if we pass this, all modifiers match
+
+ var dataItem;
+ var keyPressed;
+
+ if (keyData.keys instanceof Array) {
+ for (var i=0;i<keyData.keys.length;i++) {
+ dataItem = keyData.keys[i];
+
+ if (dataItem == e.charCode ) {
+ keyEvent.fire(e.charCode, e);
+ break;
+ } else if (dataItem == e.keyCode) {
+ keyEvent.fire(e.keyCode, e);
+ break;
+ }
+ }
+ } else {
+ dataItem = keyData.keys;
+ if (dataItem == e.charCode ) {
+ keyEvent.fire(e.charCode, e);
+ } else if (dataItem == e.keyCode) {
+ keyEvent.fire(e.keyCode, e);
+ }
+ }
+ }
+ }
+
+ /**
+ * Enables the KeyListener by attaching the DOM event listeners to the
+ * target DOM element
+ * @method enable
+ */
+ this.enable = function() {
+ if (! this.enabled) {
+ YAHOO.util.Event.addListener(attachTo, event, handleKeyPress);
+ this.enabledEvent.fire(keyData);
+ }
+ /**
+ * Boolean indicating the enabled/disabled state of the Tooltip
+ * @property enabled
+ * @type Boolean
+ */
+ this.enabled = true;
+ };
+
+ /**
+ * Disables the KeyListener by removing the DOM event listeners from the
+ * target DOM element
+ * @method disable
+ */
+ this.disable = function() {
+ if (this.enabled) {
+ YAHOO.util.Event.removeListener(attachTo, event, handleKeyPress);
+ this.disabledEvent.fire(keyData);
+ }
+ this.enabled = false;
+ };
+
+ /**
+ * Returns a String representation of the object.
+ * @method toString
+ * @return {String} The string representation of the KeyListener
+ */
+ this.toString = function() {
+ return "KeyListener [" + keyData.keys + "] " + attachTo.tagName +
+ (attachTo.id ? "[" + attachTo.id + "]" : "");
+ };
+
+};
+
+/**
+* Constant representing the DOM "keydown" event.
+* @property YAHOO.util.KeyListener.KEYDOWN
+* @static
+* @final
+* @type String
+*/
+YAHOO.util.KeyListener.KEYDOWN = "keydown";
+
+/**
+* Constant representing the DOM "keyup" event.
+* @property YAHOO.util.KeyListener.KEYUP
+* @static
+* @final
+* @type String
+*/
+YAHOO.util.KeyListener.KEYUP = "keyup";
+YAHOO.register("event", YAHOO.util.Event, {version: "2.3.1", build: "541"});
diff --git a/html/js/yui2.3.1/logger/logger.js b/html/js/yui2.3.1/logger/logger.js
new file mode 100644
index 0000000..e498963
--- /dev/null
+++ b/html/js/yui2.3.1/logger/logger.js
@@ -0,0 +1,1945 @@
+/*
+Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.3.1
+*/
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ * The LogMsg class defines a single log message.
+ *
+ * @class LogMsg
+ * @constructor
+ * @param oConfigs {Object} Object literal of configuration params.
+ */
+ YAHOO.widget.LogMsg = function(oConfigs) {
+ // Parse configs
+ if (oConfigs && (oConfigs.constructor == Object)) {
+ for(var param in oConfigs) {
+ this[param] = oConfigs[param];
+ }
+ }
+ };
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Public member variables
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Log message.
+ *
+ * @property msg
+ * @type String
+ */
+YAHOO.widget.LogMsg.prototype.msg = null;
+
+/**
+ * Log timestamp.
+ *
+ * @property time
+ * @type Date
+ */
+YAHOO.widget.LogMsg.prototype.time = null;
+
+/**
+ * Log category.
+ *
+ * @property category
+ * @type String
+ */
+YAHOO.widget.LogMsg.prototype.category = null;
+
+/**
+ * Log source. The first word passed in as the source argument.
+ *
+ * @property source
+ * @type String
+ */
+YAHOO.widget.LogMsg.prototype.source = null;
+
+/**
+ * Log source detail. The remainder of the string passed in as the source argument, not
+ * including the first word (if any).
+ *
+ * @property sourceDetail
+ * @type String
+ */
+YAHOO.widget.LogMsg.prototype.sourceDetail = null;
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ * The LogWriter class provides a mechanism to log messages through
+ * YAHOO.widget.Logger from a named source.
+ *
+ * @class LogWriter
+ * @constructor
+ * @param sSource {String} Source of LogWriter instance.
+ */
+YAHOO.widget.LogWriter = function(sSource) {
+ if(!sSource) {
+ YAHOO.log("Could not instantiate LogWriter due to invalid source.",
+ "error", "LogWriter");
+ return;
+ }
+ this._source = sSource;
+ };
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Public methods
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Public accessor to the unique name of the LogWriter instance.
+ *
+ * @method toString
+ * @return {String} Unique name of the LogWriter instance.
+ */
+YAHOO.widget.LogWriter.prototype.toString = function() {
+ return "LogWriter " + this._sSource;
+};
+
+/**
+ * Logs a message attached to the source of the LogWriter.
+ *
+ * @method log
+ * @param sMsg {String} The log message.
+ * @param sCategory {String} Category name.
+ */
+YAHOO.widget.LogWriter.prototype.log = function(sMsg, sCategory) {
+ YAHOO.widget.Logger.log(sMsg, sCategory, this._source);
+};
+
+/**
+ * Public accessor to get the source name.
+ *
+ * @method getSource
+ * @return {String} The LogWriter source.
+ */
+YAHOO.widget.LogWriter.prototype.getSource = function() {
+ return this._sSource;
+};
+
+/**
+ * Public accessor to set the source name.
+ *
+ * @method setSource
+ * @param sSource {String} Source of LogWriter instance.
+ */
+YAHOO.widget.LogWriter.prototype.setSource = function(sSource) {
+ if(!sSource) {
+ YAHOO.log("Could not set source due to invalid source.", "error", this.toString());
+ return;
+ }
+ else {
+ this._sSource = sSource;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Private member variables
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Source of the LogWriter instance.
+ *
+ * @property _source
+ * @type String
+ * @private
+ */
+YAHOO.widget.LogWriter.prototype._source = null;
+
+
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+/**
+ * The LogReader class provides UI to read messages logged to YAHOO.widget.Logger.
+ *
+ * @class LogReader
+ * @constructor
+ * @param elContainer {HTMLElement} (optional) DOM element reference of an existing DIV.
+ * @param elContainer {String} (optional) String ID of an existing DIV.
+ * @param oConfigs {Object} (optional) Object literal of configuration params.
+ */
+YAHOO.widget.LogReader = function(elContainer, oConfigs) {
+ this._sName = YAHOO.widget.LogReader._index;
+ YAHOO.widget.LogReader._index++;
+
+ // Internal vars
+ this._buffer = []; // output buffer
+ this._filterCheckboxes = {}; // pointers to checkboxes
+ this._lastTime = YAHOO.widget.Logger.getStartTime(); // timestamp of last log message to console
+
+ // Parse config vars here
+ if (oConfigs && (oConfigs.constructor == Object)) {
+ for(var param in oConfigs) {
+ this[param] = oConfigs[param];
+ }
+ }
+
+ this._initContainerEl(elContainer);
+ if(!this._elContainer) {
+ YAHOO.log("Could not instantiate LogReader due to an invalid container element " +
+ elContainer, "error", this.toString());
+ return;
+ }
+
+ this._initHeaderEl();
+ this._initConsoleEl();
+ this._initFooterEl();
+
+ this._initDragDrop();
+
+ this._initCategories();
+ this._initSources();
+
+ // Subscribe to Logger custom events
+ YAHOO.widget.Logger.newLogEvent.subscribe(this._onNewLog, this);
+ YAHOO.widget.Logger.logResetEvent.subscribe(this._onReset, this);
+
+ YAHOO.widget.Logger.categoryCreateEvent.subscribe(this._onCategoryCreate, this);
+ YAHOO.widget.Logger.sourceCreateEvent.subscribe(this._onSourceCreate, this);
+
+ this._filterLogs();
+ YAHOO.log("LogReader initialized", null, this.toString());
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Public member variables
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Whether or not LogReader is enabled to output log messages.
+ *
+ * @property logReaderEnabled
+ * @type Boolean
+ * @default true
+ */
+YAHOO.widget.LogReader.prototype.logReaderEnabled = true;
+
+/**
+ * Public member to access CSS width of the LogReader container.
+ *
+ * @property width
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.width = null;
+
+/**
+ * Public member to access CSS height of the LogReader container.
+ *
+ * @property height
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.height = null;
+
+/**
+ * Public member to access CSS top position of the LogReader container.
+ *
+ * @property top
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.top = null;
+
+/**
+ * Public member to access CSS left position of the LogReader container.
+ *
+ * @property left
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.left = null;
+
+/**
+ * Public member to access CSS right position of the LogReader container.
+ *
+ * @property right
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.right = null;
+
+/**
+ * Public member to access CSS bottom position of the LogReader container.
+ *
+ * @property bottom
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.bottom = null;
+
+/**
+ * Public member to access CSS font size of the LogReader container.
+ *
+ * @property fontSize
+ * @type String
+ */
+YAHOO.widget.LogReader.prototype.fontSize = null;
+
+/**
+ * Whether or not the footer UI is enabled for the LogReader.
+ *
+ * @property footerEnabled
+ * @type Boolean
+ * @default true
+ */
+YAHOO.widget.LogReader.prototype.footerEnabled = true;
+
+/**
+ * Whether or not output is verbose (more readable). Setting to true will make
+ * output more compact (less readable).
+ *
+ * @property verboseOutput
+ * @type Boolean
+ * @default true
+ */
+YAHOO.widget.LogReader.prototype.verboseOutput = true;
+
+/**
+ * Whether or not newest message is printed on top.
+ *
+ * @property newestOnTop
+ * @type Boolean
+ */
+YAHOO.widget.LogReader.prototype.newestOnTop = true;
+
+/**
+ * Output timeout buffer in milliseconds.
+ *
+ * @property outputBuffer
+ * @type Number
+ * @default 100
+ */
+YAHOO.widget.LogReader.prototype.outputBuffer = 100;
+
+/**
+ * Maximum number of messages a LogReader console will display.
+ *
+ * @property thresholdMax
+ * @type Number
+ * @default 500
+ */
+YAHOO.widget.LogReader.prototype.thresholdMax = 500;
+
+/**
+ * When a LogReader console reaches its thresholdMax, it will clear out messages
+ * and print out the latest thresholdMin number of messages.
+ *
+ * @property thresholdMin
+ * @type Number
+ * @default 100
+ */
+YAHOO.widget.LogReader.prototype.thresholdMin = 100;
+
+/**
+ * True when LogReader is in a collapsed state, false otherwise.
+ *
+ * @property isCollapsed
+ * @type Boolean
+ * @default false
+ */
+YAHOO.widget.LogReader.prototype.isCollapsed = false;
+
+/**
+ * True when LogReader is in a paused state, false otherwise.
+ *
+ * @property isPaused
+ * @type Boolean
+ * @default false
+ */
+YAHOO.widget.LogReader.prototype.isPaused = false;
+
+/**
+ * Enables draggable LogReader if DragDrop Utility is present.
+ *
+ * @property draggable
+ * @type Boolean
+ * @default true
+ */
+YAHOO.widget.LogReader.prototype.draggable = true;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Public methods
+//
+/////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Public accessor to the unique name of the LogReader instance.
+ *
+ * @method toString
+ * @return {String} Unique name of the LogReader instance.
+ */
+YAHOO.widget.LogReader.prototype.toString = function() {
+ return "LogReader instance" + this._sName;
+};
+/**
+ * Pauses output of log messages. While paused, log messages are not lost, but
+ * get saved to a buffer and then output upon resume of LogReader.
+ *
+ * @method pause
+ */
+YAHOO.widget.LogReader.prototype.pause = function() {
+ this.isPaused = true;
+ this._btnPause.value = "Resume";
+ this._timeout = null;
+ this.logReaderEnabled = false;
+};
+
+/**
+ * Resumes output of log messages, including outputting any log messages that
+ * have been saved to buffer while paused.
+ *
+ * @method resume
+ */
+YAHOO.widget.LogReader.prototype.resume = function() {
+ this.isPaused = false;
+ this._btnPause.value = "Pause";
+ this.logReaderEnabled = true;
+ this._printBuffer();
+};
+
+/**
+ * Hides UI of LogReader. Logging functionality is not disrupted.
+ *
+ * @method hide
+ */
+YAHOO.widget.LogReader.prototype.hide = function() {
+ this._elContainer.style.display = "none";
+};
+
+/**
+ * Shows UI of LogReader. Logging functionality is not disrupted.
+ *
+ * @method show
+ */
+YAHOO.widget.LogReader.prototype.show = function() {
+ this._elContainer.style.display = "block";
+};
+
+/**
+ * Collapses UI of LogReader. Logging functionality is not disrupted.
+ *
+ * @method collapse
+ */
+YAHOO.widget.LogReader.prototype.collapse = function() {
+ this._elConsole.style.display = "none";
+ if(this._elFt) {
+ this._elFt.style.display = "none";
+ }
+ this._btnCollapse.value = "Expand";
+ this.isCollapsed = true;
+};
+
+/**
+ * Expands UI of LogReader. Logging functionality is not disrupted.
+ *
+ * @method expand
+ */
+YAHOO.widget.LogReader.prototype.expand = function() {
+ this._elConsole.style.display = "block";
+ if(this._elFt) {
+ this._elFt.style.display = "block";
+ }
+ this._btnCollapse.value = "Collapse";
+ this.isCollapsed = false;
+};
+
+/**
+ * Returns related checkbox element for given filter (i.e., category or source).
+ *
+ * @method getCheckbox
+ * @param {String} Category or source name.
+ * @return {Array} Array of all filter checkboxes.
+ */
+YAHOO.widget.LogReader.prototype.getCheckbox = function(filter) {
+ return this._filterCheckboxes[filter];
+};
+
+/**
+ * Returns array of enabled categories.
+ *
+ * @method getCategories
+ * @return {String[]} Array of enabled categories.
+ */
+YAHOO.widget.LogReader.prototype.getCategories = function() {
+ return this._categoryFilters;
+};
+
+/**
+ * Shows log messages associated with given category.
+ *
+ * @method showCategory
+ * @param {String} Category name.
+ */
+YAHOO.widget.LogReader.prototype.showCategory = function(sCategory) {
+ var filtersArray = this._categoryFilters;
+ // Don't do anything if category is already enabled
+ // Use Array.indexOf if available...
+ if(filtersArray.indexOf) {
+ if(filtersArray.indexOf(sCategory) > -1) {
+ return;
+ }
+ }
+ // ...or do it the old-fashioned way
+ else {
+ for(var i=0; i<filtersArray.length; i++) {
+ if(filtersArray[i] === sCategory){
+ return;
+ }
+ }
+ }
+
+ this._categoryFilters.push(sCategory);
+ this._filterLogs();
+ var elCheckbox = this.getCheckbox(sCategory);
+ if(elCheckbox) {
+ elCheckbox.checked = true;
+ }
+};
+
+/**
+ * Hides log messages associated with given category.
+ *
+ * @method hideCategory
+ * @param {String} Category name.
+ */
+YAHOO.widget.LogReader.prototype.hideCategory = function(sCategory) {
+ var filtersArray = this._categoryFilters;
+ for(var i=0; i<filtersArray.length; i++) {
+ if(sCategory == filtersArray[i]) {
+ filtersArray.splice(i, 1);
+ break;
+ }
+ }
+ this._filterLogs();
+ var elCheckbox = this.getCheckbox(sCategory);
+ if(elCheckbox) {
+ elCheckbox.checked = false;
+ }
+};
+
+/**
+ * Returns array of enabled sources.
+ *
+ * @method getSources
+ * @return {Array} Array of enabled sources.
+ */
+YAHOO.widget.LogReader.prototype.getSources = function() {
+ return this._sourceFilters;
+};
+
+/**
+ * Shows log messages associated with given source.
+ *
+ * @method showSource
+ * @param {String} Source name.
+ */
+YAHOO.widget.LogReader.prototype.showSource = function(sSource) {
+ var filtersArray = this._sourceFilters;
+ // Don't do anything if category is already enabled
+ // Use Array.indexOf if available...
+ if(filtersArray.indexOf) {
+ if(filtersArray.indexOf(sSource) > -1) {
+ return;
+ }
+ }
+ // ...or do it the old-fashioned way
+ else {
+ for(var i=0; i<filtersArray.length; i++) {
+ if(sSource == filtersArray[i]){
+ return;
+ }
+ }
+ }
+ filtersArray.push(sSource);
+ this._filterLogs();
+ var elCheckbox = this.getCheckbox(sSource);
+ if(elCheckbox) {
+ elCheckbox.checked = true;
+ }
+};
+
+/**
+ * Hides log messages associated with given source.
+ *
+ * @method hideSource
+ * @param {String} Source name.
+ */
+YAHOO.widget.LogReader.prototype.hideSource = function(sSource) {
+ var filtersArray = this._sourceFilters;
+ for(var i=0; i<filtersArray.length; i++) {
+ if(sSource == filtersArray[i]) {
+ filtersArray.splice(i, 1);
+ break;
+ }
+ }
+ this._filterLogs();
+ var elCheckbox = this.getCheckbox(sSource);
+ if(elCheckbox) {
+ elCheckbox.checked = false;
+ }
+};
+
+/**
+ * Does not delete any log messages, but clears all printed log messages from
+ * the console. Log messages will be printed out again if user re-filters. The
+ * static method YAHOO.widget.Logger.reset() should be called in order to
+ * actually delete log messages.
+ *
+ * @method clearConsole
+ */
+YAHOO.widget.LogReader.prototype.clearConsole = function() {
+ // Clear the buffer of any pending messages
+ this._timeout = null;
+ this._buffer = [];
+ this._consoleMsgCount = 0;
+
+ var elConsole = this._elConsole;
+ while(elConsole.hasChildNodes()) {
+ elConsole.removeChild(elConsole.firstChild);
+ }
+};
+
+/**
+ * Updates title to given string.
+ *
+ * @method setTitle
+ * @param sTitle {String} New title.
+ */
+YAHOO.widget.LogReader.prototype.setTitle = function(sTitle) {
+ this._title.innerHTML = this.html2Text(sTitle);
+};
+
+/**
+ * Gets timestamp of the last log.
+ *
+ * @method getLastTime
+ * @return {Date} Timestamp of the last log.
+ */
+YAHOO.widget.LogReader.prototype.getLastTime = function() {
+ return this._lastTime;
+};
+
+/**
+ * Formats message string to HTML for output to console.
+ *
+ * @method formatMsg
+ * @param oLogMsg {Object} Log message object.
+ * @return {String} HTML-formatted message for output to console.
+ */
+YAHOO.widget.LogReader.prototype.formatMsg = function(oLogMsg) {
+ var category = oLogMsg.category;
+
+ // Label for color-coded display
+ var label = category.substring(0,4).toUpperCase();
+
+ // Calculate the elapsed time to be from the last item that passed through the filter,
+ // not the absolute previous item in the stack
+
+ var time = oLogMsg.time;
+ if (time.toLocaleTimeString) {
+ var localTime = time.toLocaleTimeString();
+ }
+ else {
+ localTime = time.toString();
+ }
+
+ var msecs = time.getTime();
+ var startTime = YAHOO.widget.Logger.getStartTime();
+ var totalTime = msecs - startTime;
+ var elapsedTime = msecs - this.getLastTime();
+
+ var source = oLogMsg.source;
+ var sourceDetail = oLogMsg.sourceDetail;
+ var sourceAndDetail = (sourceDetail) ?
+ source + " " + sourceDetail : source;
+
+
+ // Escape HTML entities in the log message itself for output to console
+ //var msg = this.html2Text(oLogMsg.msg); //TODO: delete
+ var msg = this.html2Text(YAHOO.lang.dump(oLogMsg.msg));
+
+ // Verbose output includes extra line breaks
+ var output = (this.verboseOutput) ?
+ ["<pre class=\"yui-log-verbose\"><p><span class='", category, "'>", label, "</span> ",
+ totalTime, "ms (+", elapsedTime, ") ",
+ localTime, ": ",
+ "</p><p>",
+ sourceAndDetail,
+ ": </p><p>",
+ msg,
+ "</p></pre>"] :
+
+ ["<pre><p><span class='", category, "'>", label, "</span> ",
+ totalTime, "ms (+", elapsedTime, ") ",
+ localTime, ": ",
+ sourceAndDetail, ": ",
+ msg, "</p></pre>"];
+
+ return output.join("");
+};
+
+/**
+ * Converts input chars "<", ">", and "&" to HTML entities.
+ *
+ * @method html2Text
+ * @param sHtml {String} String to convert.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype.html2Text = function(sHtml) {
+ if(sHtml) {
+ sHtml += "";
+ return sHtml.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
+ }
+ return "";
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Private member variables
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Internal class member to index multiple LogReader instances.
+ *
+ * @property _memberName
+ * @static
+ * @type Number
+ * @default 0
+ * @private
+ */
+YAHOO.widget.LogReader._index = 0;
+
+/**
+ * Name of LogReader instance.
+ *
+ * @property _sName
+ * @type String
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._sName = null;
+
+//TODO: remove
+/**
+ * A class member shared by all LogReaders if a container needs to be
+ * created during instantiation. Will be null if a container element never needs to
+ * be created on the fly, such as when the implementer passes in their own element.
+ *
+ * @property _elDefaultContainer
+ * @type HTMLElement
+ * @private
+ */
+//YAHOO.widget.LogReader._elDefaultContainer = null;
+
+/**
+ * Buffer of log message objects for batch output.
+ *
+ * @property _buffer
+ * @type Object[]
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._buffer = null;
+
+/**
+ * Number of log messages output to console.
+ *
+ * @property _consoleMsgCount
+ * @type Number
+ * @default 0
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._consoleMsgCount = 0;
+
+/**
+ * Date of last output log message.
+ *
+ * @property _lastTime
+ * @type Date
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._lastTime = null;
+
+/**
+ * Batched output timeout ID.
+ *
+ * @property _timeout
+ * @type Number
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._timeout = null;
+
+/**
+ * Hash of filters and their related checkbox elements.
+ *
+ * @property _filterCheckboxes
+ * @type Object
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._filterCheckboxes = null;
+
+/**
+ * Array of filters for log message categories.
+ *
+ * @property _categoryFilters
+ * @type String[]
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._categoryFilters = null;
+
+/**
+ * Array of filters for log message sources.
+ *
+ * @property _sourceFilters
+ * @type String[]
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._sourceFilters = null;
+
+/**
+ * LogReader container element.
+ *
+ * @property _elContainer
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elContainer = null;
+
+/**
+ * LogReader header element.
+ *
+ * @property _elHd
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elHd = null;
+
+/**
+ * LogReader collapse element.
+ *
+ * @property _elCollapse
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elCollapse = null;
+
+/**
+ * LogReader collapse button element.
+ *
+ * @property _btnCollapse
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._btnCollapse = null;
+
+/**
+ * LogReader title header element.
+ *
+ * @property _title
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._title = null;
+
+/**
+ * LogReader console element.
+ *
+ * @property _elConsole
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elConsole = null;
+
+/**
+ * LogReader footer element.
+ *
+ * @property _elFt
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elFt = null;
+
+/**
+ * LogReader buttons container element.
+ *
+ * @property _elBtns
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elBtns = null;
+
+/**
+ * Container element for LogReader category filter checkboxes.
+ *
+ * @property _elCategoryFilters
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elCategoryFilters = null;
+
+/**
+ * Container element for LogReader source filter checkboxes.
+ *
+ * @property _elSourceFilters
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._elSourceFilters = null;
+
+/**
+ * LogReader pause button element.
+ *
+ * @property _btnPause
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._btnPause = null;
+
+/**
+ * Clear button element.
+ *
+ * @property _btnClear
+ * @type HTMLElement
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._btnClear = null;
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Private methods
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Initializes the primary container element.
+ *
+ * @method _initContainerEl
+ * @param elContainer {HTMLElement} Container element by reference or string ID.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initContainerEl = function(elContainer) {
+ // Validate container
+ elContainer = YAHOO.util.Dom.get(elContainer);
+ // Attach to existing container...
+ if(elContainer && elContainer.tagName && (elContainer.tagName.toLowerCase() == "div")) {
+ this._elContainer = elContainer;
+ YAHOO.util.Dom.addClass(this._elContainer,"yui-log");
+ }
+ // ...or create container from scratch
+ else {
+ this._elContainer = document.body.appendChild(document.createElement("div"));
+ //this._elContainer.id = "yui-log" + this._sName;
+ YAHOO.util.Dom.addClass(this._elContainer,"yui-log");
+ YAHOO.util.Dom.addClass(this._elContainer,"yui-log-container");
+
+ //YAHOO.widget.LogReader._elDefaultContainer = this._elContainer;
+
+ // If implementer has provided container values, trust and set those
+ var containerStyle = this._elContainer.style;
+ if(this.width) {
+ containerStyle.width = this.width;
+ }
+ if(this.right) {
+ containerStyle.right = this.right;
+ }
+ if(this.top) {
+ containerStyle.top = this.top;
+ }
+ if(this.left) {
+ containerStyle.left = this.left;
+ containerStyle.right = "auto";
+ }
+ if(this.bottom) {
+ containerStyle.bottom = this.bottom;
+ containerStyle.top = "auto";
+ }
+ if(this.fontSize) {
+ containerStyle.fontSize = this.fontSize;
+ }
+ // For Opera
+ if(navigator.userAgent.toLowerCase().indexOf("opera") != -1) {
+ document.body.style += '';
+ }
+ }
+};
+
+/**
+ * Initializes the header element.
+ *
+ * @method _initHeaderEl
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initHeaderEl = function() {
+ var oSelf = this;
+
+ // Destroy header
+ if(this._elHd) {
+ // Unhook DOM events
+ YAHOO.util.Event.purgeElement(this._elHd, true);
+
+ // Remove DOM elements
+ this._elHd.innerHTML = "";
+ }
+
+ // Create header
+ this._elHd = this._elContainer.appendChild(document.createElement("div"));
+ this._elHd.id = "yui-log-hd" + this._sName;
+ this._elHd.className = "yui-log-hd";
+
+ this._elCollapse = this._elHd.appendChild(document.createElement("div"));
+ this._elCollapse.className = "yui-log-btns";
+
+ this._btnCollapse = document.createElement("input");
+ this._btnCollapse.type = "button";
+ //this._btnCollapse.style.fontSize =
+ // YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
+ this._btnCollapse.className = "yui-log-button";
+ this._btnCollapse.value = "Collapse";
+ this._btnCollapse = this._elCollapse.appendChild(this._btnCollapse);
+ YAHOO.util.Event.addListener(
+ oSelf._btnCollapse,'click',oSelf._onClickCollapseBtn,oSelf);
+
+ this._title = this._elHd.appendChild(document.createElement("h4"));
+ this._title.innerHTML = "Logger Console";
+};
+
+/**
+ * Initializes the console element.
+ *
+ * @method _initConsoleEl
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initConsoleEl = function() {
+ // Destroy console
+ if(this._elConsole) {
+ // Unhook DOM events
+ YAHOO.util.Event.purgeElement(this._elConsole, true);
+
+ // Remove DOM elements
+ this._elConsole.innerHTML = "";
+ }
+
+ // Ceate console
+ this._elConsole = this._elContainer.appendChild(document.createElement("div"));
+ this._elConsole.className = "yui-log-bd";
+
+ // If implementer has provided console, trust and set those
+ if(this.height) {
+ this._elConsole.style.height = this.height;
+ }
+};
+
+/**
+ * Initializes the footer element.
+ *
+ * @method _initFooterEl
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initFooterEl = function() {
+ var oSelf = this;
+
+ // Don't create footer elements if footer is disabled
+ if(this.footerEnabled) {
+ // Destroy console
+ if(this._elFt) {
+ // Unhook DOM events
+ YAHOO.util.Event.purgeElement(this._elFt, true);
+
+ // Remove DOM elements
+ this._elFt.innerHTML = "";
+ }
+
+ this._elFt = this._elContainer.appendChild(document.createElement("div"));
+ this._elFt.className = "yui-log-ft";
+
+ this._elBtns = this._elFt.appendChild(document.createElement("div"));
+ this._elBtns.className = "yui-log-btns";
+
+ this._btnPause = document.createElement("input");
+ this._btnPause.type = "button";
+ //this._btnPause.style.fontSize =
+ // YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
+ this._btnPause.className = "yui-log-button";
+ this._btnPause.value = "Pause";
+ this._btnPause = this._elBtns.appendChild(this._btnPause);
+ YAHOO.util.Event.addListener(
+ oSelf._btnPause,'click',oSelf._onClickPauseBtn,oSelf);
+
+ this._btnClear = document.createElement("input");
+ this._btnClear.type = "button";
+ //this._btnClear.style.fontSize =
+ // YAHOO.util.Dom.getStyle(this._elContainer,"fontSize");
+ this._btnClear.className = "yui-log-button";
+ this._btnClear.value = "Clear";
+ this._btnClear = this._elBtns.appendChild(this._btnClear);
+ YAHOO.util.Event.addListener(
+ oSelf._btnClear,'click',oSelf._onClickClearBtn,oSelf);
+
+ this._elCategoryFilters = this._elFt.appendChild(document.createElement("div"));
+ this._elCategoryFilters.className = "yui-log-categoryfilters";
+ this._elSourceFilters = this._elFt.appendChild(document.createElement("div"));
+ this._elSourceFilters.className = "yui-log-sourcefilters";
+ }
+};
+
+/**
+ * Initializes Drag and Drop on the header element.
+ *
+ * @method _initDragDrop
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initDragDrop = function() {
+ // If Drag and Drop utility is available...
+ // ...and draggable is true...
+ // ...then make the header draggable
+ if(YAHOO.util.DD && this.draggable && this._elHd) {
+ var ylog_dd = new YAHOO.util.DD(this._elContainer);
+ ylog_dd.setHandleElId(this._elHd.id);
+ //TODO: use class name
+ this._elHd.style.cursor = "move";
+ }
+};
+
+/**
+ * Initializes category filters.
+ *
+ * @method _initCategories
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initCategories = function() {
+ // Initialize category filters
+ this._categoryFilters = [];
+ var aInitialCategories = YAHOO.widget.Logger.categories;
+
+ for(var j=0; j < aInitialCategories.length; j++) {
+ var sCategory = aInitialCategories[j];
+
+ // Add category to the internal array of filters
+ this._categoryFilters.push(sCategory);
+
+ // Add checkbox element if UI is enabled
+ if(this._elCategoryFilters) {
+ this._createCategoryCheckbox(sCategory);
+ }
+ }
+};
+
+/**
+ * Initializes source filters.
+ *
+ * @method _initSources
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._initSources = function() {
+ // Initialize source filters
+ this._sourceFilters = [];
+ var aInitialSources = YAHOO.widget.Logger.sources;
+
+ for(var j=0; j < aInitialSources.length; j++) {
+ var sSource = aInitialSources[j];
+
+ // Add source to the internal array of filters
+ this._sourceFilters.push(sSource);
+
+ // Add checkbox element if UI is enabled
+ if(this._elSourceFilters) {
+ this._createSourceCheckbox(sSource);
+ }
+ }}
+;
+
+/**
+ * Creates the UI for a category filter in the LogReader footer element.
+ *
+ * @method _createCategoryCheckbox
+ * @param sCategory {String} Category name.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._createCategoryCheckbox = function(sCategory) {
+ var oSelf = this;
+
+ if(this._elFt) {
+ var elParent = this._elCategoryFilters;
+ var elFilter = elParent.appendChild(document.createElement("span"));
+ elFilter.className = "yui-log-filtergrp";
+
+ // Append el at the end so IE 5.5 can set "type" attribute
+ // and THEN set checked property
+ var chkCategory = document.createElement("input");
+ chkCategory.id = "yui-log-filter-" + sCategory + this._sName;
+ chkCategory.className = "yui-log-filter-" + sCategory;
+ chkCategory.type = "checkbox";
+ chkCategory.category = sCategory;
+ chkCategory = elFilter.appendChild(chkCategory);
+ chkCategory.checked = true;
+
+ // Subscribe to the click event
+ YAHOO.util.Event.addListener(chkCategory,'click',oSelf._onCheckCategory,oSelf);
+
+ // Create and class the text label
+ var lblCategory = elFilter.appendChild(document.createElement("label"));
+ lblCategory.htmlFor = chkCategory.id;
+ lblCategory.className = sCategory;
+ lblCategory.innerHTML = sCategory;
+
+ this._filterCheckboxes[sCategory] = chkCategory;
+ }
+};
+
+/**
+ * Creates a checkbox in the LogReader footer element to filter by source.
+ *
+ * @method _createSourceCheckbox
+ * @param sSource {String} Source name.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._createSourceCheckbox = function(sSource) {
+ var oSelf = this;
+
+ if(this._elFt) {
+ var elParent = this._elSourceFilters;
+ var elFilter = elParent.appendChild(document.createElement("span"));
+ elFilter.className = "yui-log-filtergrp";
+
+ // Append el at the end so IE 5.5 can set "type" attribute
+ // and THEN set checked property
+ var chkSource = document.createElement("input");
+ chkSource.id = "yui-log-filter" + sSource + this._sName;
+ chkSource.className = "yui-log-filter" + sSource;
+ chkSource.type = "checkbox";
+ chkSource.source = sSource;
+ chkSource = elFilter.appendChild(chkSource);
+ chkSource.checked = true;
+
+ // Subscribe to the click event
+ YAHOO.util.Event.addListener(chkSource,'click',oSelf._onCheckSource,oSelf);
+
+ // Create and class the text label
+ var lblSource = elFilter.appendChild(document.createElement("label"));
+ lblSource.htmlFor = chkSource.id;
+ lblSource.className = sSource;
+ lblSource.innerHTML = sSource;
+
+ this._filterCheckboxes[sSource] = chkSource;
+ }
+};
+
+/**
+ * Reprints all log messages in the stack through filters.
+ *
+ * @method _filterLogs
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._filterLogs = function() {
+ // Reprint stack with new filters
+ if (this._elConsole !== null) {
+ this.clearConsole();
+ this._printToConsole(YAHOO.widget.Logger.getStack());
+ }
+};
+
+/**
+ * Sends buffer of log messages to output and clears buffer.
+ *
+ * @method _printBuffer
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._printBuffer = function() {
+ this._timeout = null;
+
+ if(this._elConsole !== null) {
+ var thresholdMax = this.thresholdMax;
+ thresholdMax = (thresholdMax && !isNaN(thresholdMax)) ? thresholdMax : 500;
+ if(this._consoleMsgCount < thresholdMax) {
+ var entries = [];
+ for (var i=0; i<this._buffer.length; i++) {
+ entries[i] = this._buffer[i];
+ }
+ this._buffer = [];
+ this._printToConsole(entries);
+ }
+ else {
+ this._filterLogs();
+ }
+
+ if(!this.newestOnTop) {
+ this._elConsole.scrollTop = this._elConsole.scrollHeight;
+ }
+ }
+};
+
+/**
+ * Cycles through an array of log messages, and outputs each one to the console
+ * if its category has not been filtered out.
+ *
+ * @method _printToConsole
+ * @param aEntries {Object[]} Array of LogMsg objects to output to console.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._printToConsole = function(aEntries) {
+ // Manage the number of messages displayed in the console
+ var entriesLen = aEntries.length;
+ var thresholdMin = this.thresholdMin;
+ if(isNaN(thresholdMin) || (thresholdMin > this.thresholdMax)) {
+ thresholdMin = 0;
+ }
+ var entriesStartIndex = (entriesLen > thresholdMin) ? (entriesLen - thresholdMin) : 0;
+
+ // Iterate through all log entries
+ var sourceFiltersLen = this._sourceFilters.length;
+ var categoryFiltersLen = this._categoryFilters.length;
+ for(var i=entriesStartIndex; i<entriesLen; i++) {
+ // Print only the ones that filter through
+ var okToPrint = false;
+ var okToFilterCats = false;
+
+ // Get log message details
+ var entry = aEntries[i];
+ var source = entry.source;
+ var category = entry.category;
+
+ for(var j=0; j<sourceFiltersLen; j++) {
+ if(source == this._sourceFilters[j]) {
+ okToFilterCats = true;
+ break;
+ }
+ }
+ if(okToFilterCats) {
+ for(var k=0; k<categoryFiltersLen; k++) {
+ if(category == this._categoryFilters[k]) {
+ okToPrint = true;
+ break;
+ }
+ }
+ }
+ if(okToPrint) {
+ var output = this.formatMsg(entry);
+ if(this.newestOnTop) {
+ this._elConsole.innerHTML = output + this._elConsole.innerHTML;
+ }
+ else {
+ this._elConsole.innerHTML += output;
+ }
+ this._consoleMsgCount++;
+ this._lastTime = entry.time.getTime();
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Private event handlers
+//
+/////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Handles Logger's categoryCreateEvent.
+ *
+ * @method _onCategoryCreate
+ * @param sType {String} The event.
+ * @param aArgs {Object[]} Data passed from event firer.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCategoryCreate = function(sType, aArgs, oSelf) {
+ var category = aArgs[0];
+
+ // Add category to the internal array of filters
+ oSelf._categoryFilters.push(category);
+
+ if(oSelf._elFt) {
+ oSelf._createCategoryCheckbox(category);
+ }
+};
+
+/**
+ * Handles Logger's sourceCreateEvent.
+ *
+ * @method _onSourceCreate
+ * @param sType {String} The event.
+ * @param aArgs {Object[]} Data passed from event firer.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onSourceCreate = function(sType, aArgs, oSelf) {
+ var source = aArgs[0];
+
+ // Add source to the internal array of filters
+ oSelf._sourceFilters.push(source);
+
+ if(oSelf._elFt) {
+ oSelf._createSourceCheckbox(source);
+ }
+};
+
+/**
+ * Handles check events on the category filter checkboxes.
+ *
+ * @method _onCheckCategory
+ * @param v {HTMLEvent} The click event.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCheckCategory = function(v, oSelf) {
+ var category = this.category;
+ if(!this.checked) {
+ oSelf.hideCategory(category);
+ }
+ else {
+ oSelf.showCategory(category);
+ }
+};
+
+/**
+ * Handles check events on the category filter checkboxes.
+ *
+ * @method _onCheckSource
+ * @param v {HTMLEvent} The click event.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onCheckSource = function(v, oSelf) {
+ var source = this.source;
+ if(!this.checked) {
+ oSelf.hideSource(source);
+ }
+ else {
+ oSelf.showSource(source);
+ }
+};
+
+/**
+ * Handles click events on the collapse button.
+ *
+ * @method _onClickCollapseBtn
+ * @param v {HTMLEvent} The click event.
+ * @param oSelf {Object} The LogReader instance
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickCollapseBtn = function(v, oSelf) {
+ if(!oSelf.isCollapsed) {
+ oSelf.collapse();
+ }
+ else {
+ oSelf.expand();
+ }
+};
+
+/**
+ * Handles click events on the pause button.
+ *
+ * @method _onClickPauseBtn
+ * @param v {HTMLEvent} The click event.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickPauseBtn = function(v, oSelf) {
+ if(!oSelf.isPaused) {
+ oSelf.pause();
+ }
+ else {
+ oSelf.resume();
+ }
+};
+
+/**
+ * Handles click events on the clear button.
+ *
+ * @method _onClickClearBtn
+ * @param v {HTMLEvent} The click event.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onClickClearBtn = function(v, oSelf) {
+ oSelf.clearConsole();
+};
+
+/**
+ * Handles Logger's newLogEvent.
+ *
+ * @method _onNewLog
+ * @param sType {String} The event.
+ * @param aArgs {Object[]} Data passed from event firer.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onNewLog = function(sType, aArgs, oSelf) {
+ var logEntry = aArgs[0];
+ oSelf._buffer.push(logEntry);
+
+ if (oSelf.logReaderEnabled === true && oSelf._timeout === null) {
+ oSelf._timeout = setTimeout(function(){oSelf._printBuffer();}, oSelf.outputBuffer);
+ }
+};
+
+/**
+ * Handles Logger's resetEvent.
+ *
+ * @method _onReset
+ * @param sType {String} The event.
+ * @param aArgs {Object[]} Data passed from event firer.
+ * @param oSelf {Object} The LogReader instance.
+ * @private
+ */
+YAHOO.widget.LogReader.prototype._onReset = function(sType, aArgs, oSelf) {
+ oSelf._filterLogs();
+};
+
+ /**
+ * The Logger widget provides a simple way to read or write log messages in
+ * JavaScript code. Integration with the YUI Library's debug builds allow
+ * implementers to access under-the-hood events, errors, and debugging messages.
+ * Output may be read through a LogReader console and/or output to a browser
+ * console.
+ *
+ * @module logger
+ * @requires yahoo, event, dom
+ * @optional dragdrop
+ * @namespace YAHOO.widget
+ * @title Logger Widget
+ */
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+// Define once
+if(!YAHOO.widget.Logger) {
+ /**
+ * The singleton Logger class provides core log management functionality. Saves
+ * logs written through the global YAHOO.log function or written by a LogWriter
+ * instance. Provides access to logs for reading by a LogReader instance or
+ * native browser console such as the Firebug extension to Firefox or Safari's
+ * JavaScript console through integration with the console.log() method.
+ *
+ * @class Logger
+ * @static
+ */
+ YAHOO.widget.Logger = {
+ // Initialize properties
+ loggerEnabled: true,
+ _browserConsoleEnabled: false,
+ categories: ["info","warn","error","time","window"],
+ sources: ["global"],
+ _stack: [], // holds all log msgs
+ maxStackEntries: 2500,
+ _startTime: new Date().getTime(), // static start timestamp
+ _lastTime: null // timestamp of last logged message
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Public properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * True if Logger is enabled, false otherwise.
+ *
+ * @property loggerEnabled
+ * @type Boolean
+ * @static
+ * @default true
+ */
+
+ /**
+ * Array of categories.
+ *
+ * @property categories
+ * @type String[]
+ * @static
+ * @default ["info","warn","error","time","window"]
+ */
+
+ /**
+ * Array of sources.
+ *
+ * @property sources
+ * @type String[]
+ * @static
+ * @default ["global"]
+ */
+
+ /**
+ * Upper limit on size of internal stack.
+ *
+ * @property maxStackEntries
+ * @type Number
+ * @static
+ * @default 2500
+ */
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Private properties
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Internal property to track whether output to browser console is enabled.
+ *
+ * @property _browserConsoleEnabled
+ * @type Boolean
+ * @static
+ * @default false
+ * @private
+ */
+
+ /**
+ * Array to hold all log messages.
+ *
+ * @property _stack
+ * @type Array
+ * @static
+ * @private
+ */
+ /**
+ * Static timestamp of Logger initialization.
+ *
+ * @property _startTime
+ * @type Date
+ * @static
+ * @private
+ */
+ /**
+ * Timestamp of last logged message.
+ *
+ * @property _lastTime
+ * @type Date
+ * @static
+ * @private
+ */
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Public methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+ /**
+ * Saves a log message to the stack and fires newLogEvent. If the log message is
+ * assigned to an unknown category, creates a new category. If the log message is
+ * from an unknown source, creates a new source. If browser console is enabled,
+ * outputs the log message to browser console.
+ *
+ * @method log
+ * @param sMsg {String} The log message.
+ * @param sCategory {String} Category of log message, or null.
+ * @param sSource {String} Source of LogWriter, or null if global.
+ */
+ YAHOO.widget.Logger.log = function(sMsg, sCategory, sSource) {
+ if(this.loggerEnabled) {
+ if(!sCategory) {
+ sCategory = "info"; // default category
+ }
+ else {
+ sCategory = sCategory.toLocaleLowerCase();
+ if(this._isNewCategory(sCategory)) {
+ this._createNewCategory(sCategory);
+ }
+ }
+ var sClass = "global"; // default source
+ var sDetail = null;
+ if(sSource) {
+ var spaceIndex = sSource.indexOf(" ");
+ if(spaceIndex > 0) {
+ // Substring until first space
+ sClass = sSource.substring(0,spaceIndex);
+ // The rest of the source
+ sDetail = sSource.substring(spaceIndex,sSource.length);
+ }
+ else {
+ sClass = sSource;
+ }
+ if(this._isNewSource(sClass)) {
+ this._createNewSource(sClass);
+ }
+ }
+
+ var timestamp = new Date();
+ var logEntry = new YAHOO.widget.LogMsg({
+ msg: sMsg,
+ time: timestamp,
+ category: sCategory,
+ source: sClass,
+ sourceDetail: sDetail
+ });
+
+ var stack = this._stack;
+ var maxStackEntries = this.maxStackEntries;
+ if(maxStackEntries && !isNaN(maxStackEntries) &&
+ (stack.length >= maxStackEntries)) {
+ stack.shift();
+ }
+ stack.push(logEntry);
+ this.newLogEvent.fire(logEntry);
+
+ if(this._browserConsoleEnabled) {
+ this._printToBrowserConsole(logEntry);
+ }
+ return true;
+ }
+ else {
+ return false;
+ }
+ };
+
+ /**
+ * Resets internal stack and startTime, enables Logger, and fires logResetEvent.
+ *
+ * @method reset
+ */
+ YAHOO.widget.Logger.reset = function() {
+ this._stack = [];
+ this._startTime = new Date().getTime();
+ this.loggerEnabled = true;
+ this.log("Logger reset");
+ this.logResetEvent.fire();
+ };
+
+ /**
+ * Public accessor to internal stack of log message objects.
+ *
+ * @method getStack
+ * @return {Object[]} Array of log message objects.
+ */
+ YAHOO.widget.Logger.getStack = function() {
+ return this._stack;
+ };
+
+ /**
+ * Public accessor to internal start time.
+ *
+ * @method getStartTime
+ * @return {Date} Internal date of when Logger singleton was initialized.
+ */
+ YAHOO.widget.Logger.getStartTime = function() {
+ return this._startTime;
+ };
+
+ /**
+ * Disables output to the browser's global console.log() function, which is used
+ * by the Firebug extension to Firefox as well as Safari.
+ *
+ * @method disableBrowserConsole
+ */
+ YAHOO.widget.Logger.disableBrowserConsole = function() {
+ YAHOO.log("Logger output to the function console.log() has been disabled.");
+ this._browserConsoleEnabled = false;
+ };
+
+ /**
+ * Enables output to the browser's global console.log() function, which is used
+ * by the Firebug extension to Firefox as well as Safari.
+ *
+ * @method enableBrowserConsole
+ */
+ YAHOO.widget.Logger.enableBrowserConsole = function() {
+ this._browserConsoleEnabled = true;
+ YAHOO.log("Logger output to the function console.log() has been enabled.");
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Public events
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Fired when a new category has been created.
+ *
+ * @event categoryCreateEvent
+ * @param sCategory {String} Category name.
+ */
+ YAHOO.widget.Logger.categoryCreateEvent =
+ new YAHOO.util.CustomEvent("categoryCreate", this, true);
+
+ /**
+ * Fired when a new source has been named.
+ *
+ * @event sourceCreateEvent
+ * @param sSource {String} Source name.
+ */
+ YAHOO.widget.Logger.sourceCreateEvent =
+ new YAHOO.util.CustomEvent("sourceCreate", this, true);
+
+ /**
+ * Fired when a new log message has been created.
+ *
+ * @event newLogEvent
+ * @param sMsg {String} Log message.
+ */
+ YAHOO.widget.Logger.newLogEvent = new YAHOO.util.CustomEvent("newLog", this, true);
+
+ /**
+ * Fired when the Logger has been reset has been created.
+ *
+ * @event logResetEvent
+ */
+ YAHOO.widget.Logger.logResetEvent = new YAHOO.util.CustomEvent("logReset", this, true);
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Private methods
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Creates a new category of log messages and fires categoryCreateEvent.
+ *
+ * @method _createNewCategory
+ * @param sCategory {String} Category name.
+ * @private
+ */
+ YAHOO.widget.Logger._createNewCategory = function(sCategory) {
+ this.categories.push(sCategory);
+ this.categoryCreateEvent.fire(sCategory);
+ };
+
+ /**
+ * Checks to see if a category has already been created.
+ *
+ * @method _isNewCategory
+ * @param sCategory {String} Category name.
+ * @return {Boolean} Returns true if category is unknown, else returns false.
+ * @private
+ */
+ YAHOO.widget.Logger._isNewCategory = function(sCategory) {
+ for(var i=0; i < this.categories.length; i++) {
+ if(sCategory == this.categories[i]) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /**
+ * Creates a new source of log messages and fires sourceCreateEvent.
+ *
+ * @method _createNewSource
+ * @param sSource {String} Source name.
+ * @private
+ */
+ YAHOO.widget.Logger._createNewSource = function(sSource) {
+ this.sources.push(sSource);
+ this.sourceCreateEvent.fire(sSource);
+ };
+
+ /**
+ * Checks to see if a source already exists.
+ *
+ * @method _isNewSource
+ * @param sSource {String} Source name.
+ * @return {Boolean} Returns true if source is unknown, else returns false.
+ * @private
+ */
+ YAHOO.widget.Logger._isNewSource = function(sSource) {
+ if(sSource) {
+ for(var i=0; i < this.sources.length; i++) {
+ if(sSource == this.sources[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ /**
+ * Outputs a log message to global console.log() function.
+ *
+ * @method _printToBrowserConsole
+ * @param oEntry {Object} Log entry object.
+ * @private
+ */
+ YAHOO.widget.Logger._printToBrowserConsole = function(oEntry) {
+ if(window.console && console.log) {
+ var category = oEntry.category;
+ var label = oEntry.category.substring(0,4).toUpperCase();
+
+ var time = oEntry.time;
+ if (time.toLocaleTimeString) {
+ var localTime = time.toLocaleTimeString();
+ }
+ else {
+ localTime = time.toString();
+ }
+
+ var msecs = time.getTime();
+ var elapsedTime = (YAHOO.widget.Logger._lastTime) ?
+ (msecs - YAHOO.widget.Logger._lastTime) : 0;
+ YAHOO.widget.Logger._lastTime = msecs;
+
+ var output =
+ localTime + " (" +
+ elapsedTime + "ms): " +
+ oEntry.source + ": " +
+ oEntry.msg;
+
+ console.log(output);
+ }
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Private event handlers
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handles logging of messages due to window error events.
+ *
+ * @method _onWindowError
+ * @param sMsg {String} The error message.
+ * @param sUrl {String} URL of the error.
+ * @param sLine {String} Line number of the error.
+ * @private
+ */
+ YAHOO.widget.Logger._onWindowError = function(sMsg,sUrl,sLine) {
+ // Logger is not in scope of this event handler
+ try {
+ YAHOO.widget.Logger.log(sMsg+' ('+sUrl+', line '+sLine+')', "window");
+ if(YAHOO.widget.Logger._origOnWindowError) {
+ YAHOO.widget.Logger._origOnWindowError();
+ }
+ }
+ catch(e) {
+ return false;
+ }
+ };
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // Enable handling of native JavaScript errors
+ // NB: Not all browsers support the window.onerror event
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ if(window.onerror) {
+ // Save any previously defined handler to call
+ YAHOO.widget.Logger._origOnWindowError = window.onerror;
+ }
+ window.onerror = YAHOO.widget.Logger._onWindowError;
+
+ /////////////////////////////////////////////////////////////////////////////
+ //
+ // First log
+ //
+ /////////////////////////////////////////////////////////////////////////////
+
+ YAHOO.widget.Logger.log("Logger initialized");
+}
+
+
+YAHOO.register("logger", YAHOO.widget.Logger, {version: "2.3.1", build: "541"});
diff --git a/html/js/yui2.3.1/yahoo/yahoo.js b/html/js/yui2.3.1/yahoo/yahoo.js
new file mode 100644
index 0000000..0fa1263
--- /dev/null
+++ b/html/js/yui2.3.1/yahoo/yahoo.js
@@ -0,0 +1,869 @@
+/*
+Copyright (c) 2007, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.3.1
+*/
+/**
+ * The YAHOO object is the single global object used by YUI Library. It
+ * contains utility function for setting up namespaces, inheritance, and
+ * logging. YAHOO.util, YAHOO.widget, and YAHOO.example are namespaces
+ * created automatically for and used by the library.
+ * @module yahoo
+ * @title YAHOO Global
+ */
+
+/**
+ * YAHOO_config is not included as part of the library. Instead it is an
+ * object that can be defined by the implementer immediately before
+ * including the YUI library. The properties included in this object
+ * will be used to configure global properties needed as soon as the
+ * library begins to load.
+ * @class YAHOO_config
+ * @static
+ */
+
+/**
+ * A reference to a function that will be executed every time a YAHOO module
+ * is loaded. As parameter, this function will receive the version
+ * information for the module. See <a href="YAHOO.env.html#getVersion">
+ * YAHOO.env.getVersion</a> for the description of the version data structure.
+ * @property listener
+ * @type Function
+ * @static
+ * @default undefined
+ */
+
+/**
+ * Set to true if the library will be dynamically loaded after window.onload.
+ * Defaults to false
+ * @property injecting
+ * @type boolean
+ * @static
+ * @default undefined
+ */
+
+/**
+ * Instructs the yuiloader component to dynamically load yui components and
+ * their dependencies. See the yuiloader documentation for more information
+ * about dynamic loading
+ * @property load
+ * @static
+ * @default undefined
+ * @see yuiloader
+ */
+
+if (typeof YAHOO == "undefined") {
+ /**
+ * The YAHOO global namespace object. If YAHOO is already defined, the
+ * existing YAHOO object will not be overwritten so that defined
+ * namespaces are preserved.
+ * @class YAHOO
+ * @static
+ */
+ var YAHOO = {};
+}
+
+/**
+ * Returns the namespace specified and creates it if it doesn't exist
+ * <pre>
+ * YAHOO.namespace("property.package");
+ * YAHOO.namespace("YAHOO.property.package");
+ * </pre>
+ * Either of the above would create YAHOO.property, then
+ * YAHOO.property.package
+ *
+ * Be careful when naming packages. Reserved words may work in some browsers
+ * and not others. For instance, the following will fail in Safari:
+ * <pre>
+ * YAHOO.namespace("really.long.nested.namespace");
+ * </pre>
+ * This fails because "long" is a future reserved word in ECMAScript
+ *
+ * @method namespace
+ * @static
+ * @param {String*} arguments 1-n namespaces to create
+ * @return {Object} A reference to the last namespace object created
+ */
+YAHOO.namespace = function() {
+ var a=arguments, o=null, i, j, d;
+ for (i=0; i<a.length; i=i+1) {
+ d=a[i].split(".");
+ o=YAHOO;
+
+ // YAHOO is implied, so it is ignored if it is included
+ for (j=(d[0] == "YAHOO") ? 1 : 0; j<d.length; j=j+1) {
+ o[d[j]]=o[d[j]] || {};
+ o=o[d[j]];
+ }
+ }
+
+ return o;
+};
+
+/**
+ * Uses YAHOO.widget.Logger to output a log message, if the widget is
+ * available.
+ *
+ * @method log
+ * @static
+ * @param {String} msg The message to log.
+ * @param {String} cat The log category for the message. Default
+ * categories are "info", "warn", "error", time".
+ * Custom categories can be used as well. (opt)
+ * @param {String} src The source of the the message (opt)
+ * @return {Boolean} True if the log operation was successful.
+ */
+YAHOO.log = function(msg, cat, src) {
+ var l=YAHOO.widget.Logger;
+ if(l && l.log) {
+ return l.log(msg, cat, src);
+ } else {
+ return false;
+ }
+};
+
+/**
+ * Registers a module with the YAHOO object
+ * @method register
+ * @static
+ * @param {String} name the name of the module (event, slider, etc)
+ * @param {Function} mainClass a reference to class in the module. This
+ * class will be tagged with the version info
+ * so that it will be possible to identify the
+ * version that is in use when multiple versions
+ * have loaded
+ * @param {Object} data metadata object for the module. Currently it
+ * is expected to contain a "version" property
+ * and a "build" property at minimum.
+ */
+YAHOO.register = function(name, mainClass, data) {
+ var mods = YAHOO.env.modules;
+ if (!mods[name]) {
+ mods[name] = { versions:[], builds:[] };
+ }
+ var m=mods[name],v=data.version,b=data.build,ls=YAHOO.env.listeners;
+ m.name = name;
+ m.version = v;
+ m.build = b;
+ m.versions.push(v);
+ m.builds.push(b);
+ m.mainClass = mainClass;
+ // fire the module load listeners
+ for (var i=0;i<ls.length;i=i+1) {
+ ls[i](m);
+ }
+ // label the main class
+ if (mainClass) {
+ mainClass.VERSION = v;
+ mainClass.BUILD = b;
+ } else {
+ YAHOO.log("mainClass is undefined for module " + name, "warn");
+ }
+};
+
+/**
+ * YAHOO.env is used to keep track of what is known about the YUI library and
+ * the browsing environment
+ * @class YAHOO.env
+ * @static
+ */
+YAHOO.env = YAHOO.env || {
+
+ /**
+ * Keeps the version info for all YUI modules that have reported themselves
+ * @property modules
+ * @type Object[]
+ */
+ modules: [],
+
+ /**
+ * List of functions that should be executed every time a YUI module
+ * reports itself.
+ * @property listeners
+ * @type Function[]
+ */
+ listeners: []
+};
+
+/**
+ * Returns the version data for the specified module:
+ * <dl>
+ * <dt>name:</dt> <dd>The name of the module</dd>
+ * <dt>version:</dt> <dd>The version in use</dd>
+ * <dt>build:</dt> <dd>The build number in use</dd>
+ * <dt>versions:</dt> <dd>All versions that were registered</dd>
+ * <dt>builds:</dt> <dd>All builds that were registered.</dd>
+ * <dt>mainClass:</dt> <dd>An object that was was stamped with the
+ * current version and build. If
+ * mainClass.VERSION != version or mainClass.BUILD != build,
+ * multiple versions of pieces of the library have been
+ * loaded, potentially causing issues.</dd>
+ * </dl>
+ *
+ * @method getVersion
+ * @static
+ * @param {String} name the name of the module (event, slider, etc)
+ * @return {Object} The version info
+ */
+YAHOO.env.getVersion = function(name) {
+ return YAHOO.env.modules[name] || null;
+};
+
+/**
+ * Do not fork for a browser if it can be avoided. Use feature detection when
+ * you can. Use the user agent as a last resort. YAHOO.env.ua stores a version
+ * number for the browser engine, 0 otherwise. This value may or may not map
+ * to the version number of the browser using the engine. The value is
+ * presented as a float so that it can easily be used for boolean evaluation
+ * as well as for looking for a particular range of versions. Because of this,
+ * some of the granularity of the version info may be lost (e.g., Gecko 1.8.0.9
+ * reports 1.8).
+ * @class YAHOO.env.ua
+ * @static
+ */
+YAHOO.env.ua = function() {
+ var o={
+
+ /**
+ * Internet Explorer version number or 0. Example: 6
+ * @property ie
+ * @type float
+ */
+ ie:0,
+
+ /**
+ * Opera version number or 0. Example: 9.2
+ * @property opera
+ * @type float
+ */
+ opera:0,
+
+ /**
+ * Gecko engine revision number. Will evaluate to 1 if Gecko
+ * is detected but the revision could not be found. Other browsers
+ * will be 0. Example: 1.8
+ * <pre>
+ * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7
+ * Firefox 1.5.0.9: 1.8.0.9 <-- Reports 1.8
+ * Firefox 2.0.0.3: 1.8.1.3 <-- Reports 1.8
+ * Firefox 3 alpha: 1.9a4 <-- Reports 1.9
+ * </pre>
+ * @property gecko
+ * @type float
+ */
+ gecko:0,
+
+ /**
+ * AppleWebKit version. KHTML browsers that are not WebKit browsers
+ * will evaluate to 1, other browsers 0. Example: 418.9.1
+ * <pre>
+ * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
+ * latest available for Mac OSX 10.3.
+ * Safari 2.0.2: 416 <-- hasOwnProperty introduced
+ * Safari 2.0.4: 418 <-- preventDefault fixed
+ * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
+ * different versions of webkit
+ * Safari 2.0.4 (419.3): 419 <-- Current Safari release
+ * Webkit 212 nightly: 522+ <-- Safari 3.0 (with native SVG) should
+ * be higher than this
+ *
+ * </pre>
+ * http://developer.apple.com/internet/safari/uamatrix.html
+ * @property webkit
+ * @type float
+ */
+ webkit:0
+ };
+
+ var ua=navigator.userAgent, m;
+
+ // Modern KHTML browsers should qualify as Safari X-Grade
+ if ((/KHTML/).test(ua)) {
+ o.webkit=1;
+ }
+ // Modern WebKit browsers are at least X-Grade
+ m=ua.match(/AppleWebKit\/([^\s]*)/);
+ if (m&&m[1]) {
+ o.webkit=parseFloat(m[1]);
+ }
+
+ if (!o.webkit) { // not webkit
+ // @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
+ m=ua.match(/Opera[\s\/]([^\s]*)/);
+ if (m&&m[1]) {
+ o.opera=parseFloat(m[1]);
+ } else { // not opera or webkit
+ m=ua.match(/MSIE\s([^;]*)/);
+ if (m&&m[1]) {
+ o.ie=parseFloat(m[1]);
+ } else { // not opera, webkit, or ie
+ m=ua.match(/Gecko\/([^\s]*)/);
+ if (m) {
+ o.gecko=1; // Gecko detected, look for revision
+ m=ua.match(/rv:([^\s\)]*)/);
+ if (m&&m[1]) {
+ o.gecko=parseFloat(m[1]);
+ }
+ }
+ }
+ }
+ }
+
+ return o;
+}();
+
+/*
+ * Initializes the global by creating the default namespaces and applying
+ * any new configuration information that is detected. This is the setup
+ * for env.
+ * @method init
+ * @static
+ * @private
+ */
+(function() {
+ YAHOO.namespace("util", "widget", "example");
+ if ("undefined" !== typeof YAHOO_config) {
+ var l=YAHOO_config.listener,ls=YAHOO.env.listeners,unique=true,i;
+ if (l) {
+ // if YAHOO is loaded multiple times we need to check to see if
+ // this is a new config object. If it is, add the new component
+ // load listener to the stack
+ for (i=0;i<ls.length;i=i+1) {
+ if (ls[i]==l) {
+ unique=false;
+ break;
+ }
+ }
+ if (unique) {
+ ls.push(l);
+ }
+ }
+ }
+})();
+/**
+ * Provides the language utilites and extensions used by the library
+ * @class YAHOO.lang
+ */
+YAHOO.lang = {
+ /**
+ * Determines whether or not the provided object is an array.
+ * Testing typeof/instanceof/constructor of arrays across frame
+ * boundaries isn't possible in Safari unless you have a reference
+ * to the other frame to test against its Array prototype. To
+ * handle this case, we test well-known array properties instead.
+ * properties.
+ * @method isArray
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isArray: function(o) {
+
+ if (o) {
+ var l = YAHOO.lang;
+ return l.isNumber(o.length) && l.isFunction(o.splice) &&
+ !l.hasOwnProperty(o.length);
+ }
+ return false;
+ },
+
+ /**
+ * Determines whether or not the provided object is a boolean
+ * @method isBoolean
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isBoolean: function(o) {
+ return typeof o === 'boolean';
+ },
+
+ /**
+ * Determines whether or not the provided object is a function
+ * @method isFunction
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isFunction: function(o) {
+ return typeof o === 'function';
+ },
+
+ /**
+ * Determines whether or not the provided object is null
+ * @method isNull
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isNull: function(o) {
+ return o === null;
+ },
+
+ /**
+ * Determines whether or not the provided object is a legal number
+ * @method isNumber
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isNumber: function(o) {
+ return typeof o === 'number' && isFinite(o);
+ },
+
+ /**
+ * Determines whether or not the provided object is of type object
+ * or function
+ * @method isObject
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isObject: function(o) {
+return (o && (typeof o === 'object' || YAHOO.lang.isFunction(o))) || false;
+ },
+
+ /**
+ * Determines whether or not the provided object is a string
+ * @method isString
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isString: function(o) {
+ return typeof o === 'string';
+ },
+
+ /**
+ * Determines whether or not the provided object is undefined
+ * @method isUndefined
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ isUndefined: function(o) {
+ return typeof o === 'undefined';
+ },
+
+ /**
+ * Determines whether or not the property was added
+ * to the object instance. Returns false if the property is not present
+ * in the object, or was inherited from the prototype.
+ * This abstraction is provided to enable hasOwnProperty for Safari 1.3.x.
+ * There is a discrepancy between YAHOO.lang.hasOwnProperty and
+ * Object.prototype.hasOwnProperty when the property is a primitive added to
+ * both the instance AND prototype with the same value:
+ * <pre>
+ * var A = function() {};
+ * A.prototype.foo = 'foo';
+ * var a = new A();
+ * a.foo = 'foo';
+ * alert(a.hasOwnProperty('foo')); // true
+ * alert(YAHOO.lang.hasOwnProperty(a, 'foo')); // false when using fallback
+ * </pre>
+ * @method hasOwnProperty
+ * @param {any} o The object being testing
+ * @return Boolean
+ */
+ hasOwnProperty: function(o, prop) {
+ if (Object.prototype.hasOwnProperty) {
+ return o.hasOwnProperty(prop);
+ }
+
+ return !YAHOO.lang.isUndefined(o[prop]) &&
+ o.constructor.prototype[prop] !== o[prop];
+ },
+
+ /**
+ * IE will not enumerate native functions in a derived object even if the
+ * function was overridden. This is a workaround for specific functions
+ * we care about on the Object prototype.
+ * @property _IEEnumFix
+ * @param {Function} r the object to receive the augmentation
+ * @param {Function} s the object that supplies the properties to augment
+ * @static
+ * @private
+ */
+ _IEEnumFix: function(r, s) {
+ if (YAHOO.env.ua.ie) {
+ var add=["toString", "valueOf"], i;
+ for (i=0;i<add.length;i=i+1) {
+ var fname=add[i],f=s[fname];
+ if (YAHOO.lang.isFunction(f) && f!=Object.prototype[fname]) {
+ r[fname]=f;
+ }
+ }
+ }
+ },
+
+ /**
+ * Utility to set up the prototype, constructor and superclass properties to
+ * support an inheritance strategy that can chain constructors and methods.
+ * Static members will not be inherited.
+ *
+ * @method extend
+ * @static
+ * @param {Function} subc the object to modify
+ * @param {Function} superc the object to inherit
+ * @param {Object} overrides additional properties/methods to add to the
+ * subclass prototype. These will override the
+ * matching items obtained from the superclass
+ * if present.
+ */
+ extend: function(subc, superc, overrides) {
+ if (!superc||!subc) {
+ throw new Error("YAHOO.lang.extend failed, please check that " +
+ "all dependencies are included.");
+ }
+ var F = function() {};
+ F.prototype=superc.prototype;
+ subc.prototype=new F();
+ subc.prototype.constructor=subc;
+ subc.superclass=superc.prototype;
+ if (superc.prototype.constructor == Object.prototype.constructor) {
+ superc.prototype.constructor=superc;
+ }
+
+ if (overrides) {
+ for (var i in overrides) {
+ subc.prototype[i]=overrides[i];
+ }
+
+ YAHOO.lang._IEEnumFix(subc.prototype, overrides);
+ }
+ },
+
+ /**
+ * Applies all properties in the supplier to the receiver if the
+ * receiver does not have these properties yet. Optionally, one or
+ * more methods/properties can be specified (as additional
+ * parameters). This option will overwrite the property if receiver
+ * has it already. If true is passed as the third parameter, all
+ * properties will be applied and _will_ overwrite properties in
+ * the receiver.
+ *
+ * @method augmentObject
+ * @static
+ * @since 2.3.0
+ * @param {Function} r the object to receive the augmentation
+ * @param {Function} s the object that supplies the properties to augment
+ * @param {String*|boolean} arguments zero or more properties methods
+ * to augment the receiver with. If none specified, everything
+ * in the supplier will be used unless it would
+ * overwrite an existing property in the receiver. If true
+ * is specified as the third parameter, all properties will
+ * be applied and will overwrite an existing property in
+ * the receiver
+ */
+ augmentObject: function(r, s) {
+ if (!s||!r) {
+ throw new Error("Absorb failed, verify dependencies.");
+ }
+ var a=arguments, i, p, override=a[2];
+ if (override && override!==true) { // only absorb the specified properties
+ for (i=2; i<a.length; i=i+1) {
+ r[a[i]] = s[a[i]];
+ }
+ } else { // take everything, overwriting only if the third parameter is true
+ for (p in s) {
+ if (override || !r[p]) {
+ r[p] = s[p];
+ }
+ }
+
+ YAHOO.lang._IEEnumFix(r, s);
+ }
+ },
+
+ /**
+ * Same as YAHOO.lang.augmentObject, except it only applies prototype properties
+ * @see YAHOO.lang.augmentObject
+ * @method augmentProto
+ * @static
+ * @param {Function} r the object to receive the augmentation
+ * @param {Function} s the object that supplies the properties to augment
+ * @param {String*|boolean} arguments zero or more properties methods
+ * to augment the receiver with. If none specified, everything
+ * in the supplier will be used unless it would overwrite an existing
+ * property in the receiver. if true is specified as the third
+ * parameter, all properties will be applied and will overwrite an
+ * existing property in the receiver
+ */
+ augmentProto: function(r, s) {
+ if (!s||!r) {
+ throw new Error("Augment failed, verify dependencies.");
+ }
+ //var a=[].concat(arguments);
+ var a=[r.prototype,s.prototype];
+ for (var i=2;i<arguments.length;i=i+1) {
+ a.push(arguments[i]);
+ }
+ YAHOO.lang.augmentObject.apply(this, a);
+ },
+
+
+ /**
+ * Returns a simple string representation of the object or array.
+ * Other types of objects will be returned unprocessed. Arrays
+ * are expected to be indexed. Use object notation for
+ * associative arrays.
+ * @method dump
+ * @since 2.3.0
+ * @param o {Object} The object to dump
+ * @param d {int} How deep to recurse child objects, default 3
+ * @return {String} the dump result
+ */
+ dump: function(o, d) {
+ var l=YAHOO.lang,i,len,s=[],OBJ="{...}",FUN="f(){...}",
+ COMMA=', ', ARROW=' => ';
+
+ // Cast non-objects to string
+ // Skip dates because the std toString is what we want
+ // Skip HTMLElement-like objects because trying to dump
+ // an element will cause an unhandled exception in FF 2.x
+ if (!l.isObject(o)) {
+ return o + "";
+ } else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) {
+ return o;
+ } else if (l.isFunction(o)) {
+ return FUN;
+ }
+
+ // dig into child objects the depth specifed. Default 3
+ d = (l.isNumber(d)) ? d : 3;
+
+ // arrays [1, 2, 3]
+ if (l.isArray(o)) {
+ s.push("[");
+ for (i=0,len=o.length;i<len;i=i+1) {
+ if (l.isObject(o[i])) {
+ s.push((d > 0) ? l.dump(o[i], d-1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push("]");
+ // objects {k1 => v1, k2 => v2}
+ } else {
+ s.push("{");
+ for (i in o) {
+ if (l.hasOwnProperty(o, i)) {
+ s.push(i + ARROW);
+ if (l.isObject(o[i])) {
+ s.push((d > 0) ? l.dump(o[i], d-1) : OBJ);
+ } else {
+ s.push(o[i]);
+ }
+ s.push(COMMA);
+ }
+ }
+ if (s.length > 1) {
+ s.pop();
+ }
+ s.push("}");
+ }
+
+ return s.join("");
+ },
+
+ /**
+ * Does variable substitution on a string. It scans through the string
+ * looking for expressions enclosed in { } braces. If an expression
+ * is found, it is used a key on the object. If there is a space in
+ * the key, the first word is used for the key and the rest is provided
+ * to an optional function to be used to programatically determine the
+ * value (the extra information might be used for this decision). If
+ * the value for the key in the object, or what is returned from the
+ * function has a string value, number value, or object value, it is
+ * substituted for the bracket expression and it repeats. If this
+ * value is an object, it uses the Object's toString() if this has
+ * been overridden, otherwise it does a shallow dump of the key/value
+ * pairs.
+ * @method substitute
+ * @since 2.3.0
+ * @param s {String} The string that will be modified.
+ * @param o {Object} An object containing the replacement values
+ * @param f {Function} An optional function that can be used to
+ * process each match. It receives the key,
+ * value, and any extra metadata included with
+ * the key inside of the braces.
+ * @return {String} the substituted string
+ */
+ substitute: function (s, o, f) {
+ var i, j, k, key, v, meta, l=YAHOO.lang, saved=[], token,
+ DUMP='dump', SPACE=' ', LBRACE='{', RBRACE='}';
+
+
+ for (;;) {
+ i = s.lastIndexOf(LBRACE);
+ if (i < 0) {
+ break;
+ }
+ j = s.indexOf(RBRACE, i);
+ if (i + 1 >= j) {
+ break;
+ }
+
+ //Extract key and meta info
+ token = s.substring(i + 1, j);
+ key = token;
+ meta = null;
+ k = key.indexOf(SPACE);
+ if (k > -1) {
+ meta = key.substring(k + 1);
+ key = key.substring(0, k);
+ }
+
+ // lookup the value
+ v = o[key];
+
+ // if a substitution function was provided, execute it
+ if (f) {
+ v = f(key, v, meta);
+ }
+
+ if (l.isObject(v)) {
+ if (l.isArray(v)) {
+ v = l.dump(v, parseInt(meta, 10));
+ } else {
+ meta = meta || "";
+
+ // look for the keyword 'dump', if found force obj dump
+ var dump = meta.indexOf(DUMP);
+ if (dump > -1) {
+ meta = meta.substring(4);
+ }
+
+ // use the toString if it is not the Object toString
+ // and the 'dump' meta info was not found
+ if (v.toString===Object.prototype.toString||dump>-1) {
+ v = l.dump(v, parseInt(meta, 10));
+ } else {
+ v = v.toString();
+ }
+ }
+ } else if (!l.isString(v) && !l.isNumber(v)) {
+ // This {block} has no replace string. Save it for later.
+ v = "~-" + saved.length + "-~";
+ saved[saved.length] = token;
+
+ // break;
+ }
+
+ s = s.substring(0, i) + v + s.substring(j + 1);
+
+
+ }
+
+ // restore saved {block}s
+ for (i=saved.length-1; i>=0; i=i-1) {
+ s = s.replace(new RegExp("~-" + i + "-~"), "{" + saved[i] + "}", "g");
+ }
+
+ return s;
+ },
+
+
+ /**
+ * Returns a string without any leading or trailing whitespace. If
+ * the input is not a string, the input will be returned untouched.
+ * @method trim
+ * @since 2.3.0
+ * @param s {string} the string to trim
+ * @return {string} the trimmed string
+ */
+ trim: function(s){
+ try {
+ return s.replace(/^\s+|\s+$/g, "");
+ } catch(e) {
+ return s;
+ }
+ },
+
+ /**
+ * Returns a new object containing all of the properties of
+ * all the supplied objects. The properties from later objects
+ * will overwrite those in earlier objects.
+ * @method merge
+ * @since 2.3.0
+ * @param arguments {Object*} the objects to merge
+ * @return the new merged object
+ */
+ merge: function() {
+ var o={}, a=arguments, i;
+ for (i=0; i<a.length; i=i+1) {
+ YAHOO.lang.augmentObject(o, a[i], true);
+ /*
+ for (var j in a[i]) {
+ o[j] = a[i][j];
+ }
+ */
+ }
+ return o;
+ },
+
+ /**
+ * A convenience method for detecting a legitimate non-null value.
+ * Returns false for null/undefined/NaN, true for other values,
+ * including 0/false/''
+ * @method isValue
+ * @since 2.3.0
+ * @param o {any} the item to test
+ * @return {boolean} true if it is not null/undefined/NaN || false
+ */
+ isValue: function(o) {
+ // return (o || o === false || o === 0 || o === ''); // Infinity fails
+ var l = YAHOO.lang;
+return (l.isObject(o) || l.isString(o) || l.isNumber(o) || l.isBoolean(o));
+ }
+
+};
+
+/*
+ * An alias for <a href="YAHOO.lang.html">YAHOO.lang</a>
+ * @class YAHOO.util.Lang
+ */
+YAHOO.util.Lang = YAHOO.lang;
+
+/**
+ * Same as YAHOO.lang.augmentObject, except it only applies prototype
+ * properties. This is an alias for augmentProto.
+ * @see YAHOO.lang.augmentObject
+ * @method augment
+ * @static
+ * @param {Function} r the object to receive the augmentation
+ * @param {Function} s the object that supplies the properties to augment
+ * @param {String*|boolean} arguments zero or more properties methods to
+ * augment the receiver with. If none specified, everything
+ * in the supplier will be used unless it would
+ * overwrite an existing property in the receiver. if true
+ * is specified as the third parameter, all properties will
+ * be applied and will overwrite an existing property in
+ * the receiver
+ */
+YAHOO.lang.augment = YAHOO.lang.augmentProto;
+
+/**
+ * An alias for <a href="YAHOO.lang.html#augment">YAHOO.lang.augment</a>
+ * @for YAHOO
+ * @method augment
+ * @static
+ * @param {Function} r the object to receive the augmentation
+ * @param {Function} s the object that supplies the properties to augment
+ * @param {String*} arguments zero or more properties methods to
+ * augment the receiver with. If none specified, everything
+ * in the supplier will be used unless it would
+ * overwrite an existing property in the receiver
+ */
+YAHOO.augment = YAHOO.lang.augmentProto;
+
+/**
+ * An alias for <a href="YAHOO.lang.html#extend">YAHOO.lang.extend</a>
+ * @method extend
+ * @static
+ * @param {Function} subc the object to modify
+ * @param {Function} superc the object to inherit
+ * @param {Object} overrides additional properties/methods to add to the
+ * subclass prototype. These will override the
+ * matching items obtained from the superclass if present.
+ */
+YAHOO.extend = YAHOO.lang.extend;
+
+YAHOO.register("yahoo", YAHOO, {version: "2.3.1", build: "541"});