+++ /dev/null
-! Copyright (C) 2006 Chris Double. All Rights Reserved.
-! See http://factorcode.org/license.txt for BSD license.
-!
-IN: fjsc-responder
-USING: kernel lazy-lists parser-combinators fjsc cont-responder html io namespaces file-responder httpd hashtables ;
-
-USE: prettyprint
-
-: fjsc-eval-page ( -- )
- [ "response" get . ] string-out log-message
- "code" "response" get hash dup log-message
- serving-text
- 'expression' parse car
- parse-result-parsed compile write flush ;
-
-: fjsc-page ( -- )
- [
- <html>
- <head>
- <script "text/javascript" =type "/responder/fjsc-resources/yahoo/yahoo.js" =src script> </script>
- <script "text/javascript" =type "/responder/fjsc-resources/yahoo/event.js" =src script> </script>
- <script "text/javascript" =type "/responder/fjsc-resources/yahoo/connection.js" =src script> </script>
- <script "text/javascript" =type "/responder/fjsc-resources/bootstrap.js" =src script> </script>
- </head>
- <body>
- <form "toeval" =id "fjsc_eval(document.getElementById(\"toeval\"));return false;" =onsubmit "post" =method form>
- <textarea "code" =name "code" =id textarea>
- </textarea>
- <input "submit" =type input/>
- </form>
- <div "compiled" =id div>
- </div>
- <div "stack" =id div>
- </div>
- </body>
- </html>
- ] show ;
-
-
-"fjsc" [ fjsc-page ] install-cont-responder
-"fjsceval" [ fjsc-eval-page ] add-simple-responder
-"fjsc-resources" [
- [
- "apps/fjsc-responder/resources/" resource-path "doc-root" set
- file-responder
- ] with-scope
-] add-simple-responder
-
-
+++ /dev/null
-! Copyright (C) 2006 Chris Double. All Rights Reserved.
-! See http://factorcode.org/license.txt for BSD license.
-!
-REQUIRES: libs/httpd libs/fjsc ;
-
-PROVIDE: apps/fjsc-responder
-{
- +files+ {
- "fjsc-responder.factor"
- }
-} {
- +tests+ {
- }
-} {
- +help+
- {
- }
-} ;
+++ /dev/null
-function fjsc_eval(form) {
- var callback = {
- success: function(o) {
- var v = o.responseText;
- eval(v)
- display_datastack();
- document.getElementById('compiled').innerHTML="<pre>" + v + "</pre>";
- document.getElementById('code').value="";
-
- }
- };
- YAHOO.util.Connect.setForm(form);
- YAHOO.util.Connect.asyncRequest('POST', "/responder/fjsceval/", callback);
-}
-
-var data_stack = [ ]
-
-function fjsc_dup() {
- var v = data_stack.pop();
- data_stack.push(v);
- data_stack.push(v);
-}
-
-function fjsc_drop() {
- data_stack.pop();
-}
-
-function fjsc_alert() {
- alert(data_stack.pop())
-}
-
-function display_datastack() {
- var html=[];
- html.push("<table border='1'>")
- for(var i = 0; i < data_stack.length; ++i) {
- html.push("<tr><td>")
- html.push(data_stack[i])
- html.push("</td></tr>")
- }
- html.push("</table>")
- document.getElementById('stack').innerHTML=html.join("");
-}
+++ /dev/null
-/*
-Copyright (c) 2006, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-*/
-
-/**
- * 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.
- * @ class
- */
-YAHOO.util.Connect =
-{
- /**
- * Array of MSFT ActiveX ids for XMLHttpRequest.
- * @private
- * @type array
- */
- _msxml_progid:[
- 'MSXML2.XMLHTTP.5.0',
- 'MSXML2.XMLHTTP.4.0',
- 'MSXML2.XMLHTTP.3.0',
- 'MSXML2.XMLHTTP',
- 'Microsoft.XMLHTTP'
- ],
-
- /**
- * Array of HTTP header(s)
- * @private
- * @type array
- */
- _http_header:{},
-
- /**
- * Determines if HTTP headers are set.
- * @private
- * @type boolean
- */
- _has_http_headers:false,
-
- /**
- * Property modified by setForm() to determine if the data
- * should be submitted as an HTML form.
- * @private
- * @type boolean
- */
- _isFormSubmit:false,
-
- /**
- * Property modified by setForm() to set the HTML form data
- * for each transaction.
- * @private
- * @type string
- */
- _sFormData:null,
-
- /**
- * Collection of polling references to the polling mechanism in handleReadyState.
- * @private
- * @type string
- */
- _poll:[],
-
- /**
- * The polling frequency, in milliseconds, for HandleReadyState.
- * when attempting to determine a transaction's XHR readyState.
- * The default is 50 milliseconds.
- * @private
- * @type int
- */
- _polling_interval:50,
-
- /**
- * A transaction counter that increments the transaction id for each transaction.
- * @private
- * @type int
- */
- _transaction_id:0,
-
- /**
- * Member to add an ActiveX id to the existing xml_progid array.
- * In the event(unlikely) a new ActiveX id is introduced, it can be added
- * without internal code modifications.
- * @public
- * @param string id The ActiveX id to be added to initialize the XHR object.
- * @return void
- */
- setProgId:function(id)
- {
- this.msxml_progid.unshift(id);
- },
-
- /**
- * Member to modify the default polling interval.
- * @public
- * @param {int} i The polling interval in milliseconds.
- * @return void
- */
- setPollingInterval:function(i)
- {
- if(typeof i == 'number' && isFinite(i)){
- this._polling_interval = i;
- }
- },
-
- /**
- * Instantiates a XMLHttpRequest object and returns an object with two properties:
- * the XMLHttpRequest instance and the transaction id.
- * @private
- * @param {int} transactionId Property containing the transaction id for this transaction.
- * @return connection object
- */
- 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]);
- if(http){
- // Object literal with http and tId properties
- obj = { conn:http, tId:transactionId };
- break;
- }
- }
- catch(e){}
- }
- }
- finally
- {
- return obj;
- }
- },
-
- /**
- * 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.
- * @private
- * @return object
- */
- getConnectionObject:function()
- {
- var o;
- var tId = this._transaction_id;
-
- try
- {
- o = this.createXhrObject(tId);
- if(o){
- this._transaction_id++;
- }
- }
- catch(e){}
- finally
- {
- return o;
- }
- },
-
- /**
- * Method for initiating an asynchronous request via the XHR object.
- * @public
- * @param {string} method HTTP transaction method
- * @param {string} uri Fully qualified path of resource
- * @param callback User-defined callback function or object
- * @param {string} postData POST body
- * @return {object} Returns the connection object
- */
- asyncRequest:function(method, uri, callback, postData)
- {
- var o = this.getConnectionObject();
-
- if(!o){
- return null;
- }
- else{
- if(this._isFormSubmit){
- //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 == 'GET'){
- uri += "?" + this._sFormData;
- }
- else if(method == 'POST'){
- postData = this._sFormData;
- }
- this._sFormData = '';
- this._isFormSubmit = false;
- }
-
- o.conn.open(method, uri, true);
-
- if(postData){
- this.initHeader('Content-Type','application/x-www-form-urlencoded');
- }
-
- //Verify whether the transaction has any user-defined HTTP headers
- //and set them.
- if(this._has_http_headers){
- this.setHeader(o);
- }
-
- this.handleReadyState(o, callback);
- postData?o.conn.send(postData):o.conn.send(null);
-
- return o;
- }
- },
-
- /**
- * This method serves as a timer that polls the XHR object's readyState
- * property during a transaction, instead of binding a callback to the
- * onreadystatechange event. Upon readyState 4, handleTransactionResponse
- * will process the response, and the timer will be cleared.
- *
- * @private
- * @param {object} o The connection object
- * @param callback User-defined callback object
- * @return void
- */
- handleReadyState:function(o, callback)
- {
- var oConn = this;
- try
- {
- this._poll[o.tId] = window.setInterval(
- function(){
- if(o.conn && o.conn.readyState == 4){
- window.clearInterval(oConn._poll[o.tId]);
- oConn._poll.splice(o.tId);
- oConn.handleTransactionResponse(o, callback);
- }
- }
- ,this._polling_interval);
- }
- catch(e)
- {
- window.clearInterval(oConn._poll[o.tId]);
- oConn._poll.splice(o.tId);
- oConn.handleTransactionResponse(o, callback);
- }
- },
-
- /**
- * This method attempts to interpret the server response and
- * determine whether the transaction was successful, or if an error or
- * exception was encountered.
- *
- * @private
- * @param {object} o The connection object
- * @param {function} callback - User-defined callback object
- * @return void
- */
- handleTransactionResponse:function(o, callback)
- {
- // If no valid callback is provided, then do not process any callback handling.
- if(!callback){
- this.releaseObject(o);
- return;
- }
-
- var httpStatus;
- var responseObject;
-
- try
- {
- httpStatus = o.conn.status;
- }
- catch(e){
- // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
- // when the o object's status and statusText properties are
- // unavailable, and a query attempt throws an exception.
- httpStatus = 13030;
- }
-
- if(httpStatus >= 200 && httpStatus < 300){
- responseObject = this.createResponseObject(o, callback.argument);
- 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]);
- }
- }
- }
- else{
- switch(httpStatus){
- // The following case labels are wininet.dll error codes that may be encountered.
- // Server timeout
- case 12002:
- // 12029 to 12031 correspond to dropped connections.
- case 12029:
- case 12030:
- case 12031:
- // Connection closed by server.
- case 12152:
- // See above comments for variable status.
- case 13030:
- responseObject = this.createExceptionObject(o, callback.argument);
- if(callback.failure){
- if(!callback.scope){
- callback.failure(responseObject);
- }
- else{
- callback.failure.apply(callback.scope,[responseObject]);
- }
- }
- break;
- default:
- responseObject = this.createResponseObject(o, callback.argument);
- if(callback.failure){
- if(!callback.scope){
- callback.failure(responseObject);
- }
- else{
- callback.failure.apply(callback.scope,[responseObject]);
- }
- }
- }
- }
-
- this.releaseObject(o);
- },
-
- /**
- * This method evaluates the server response, creates and returns the results via
- * its properties. Success and failure cases will differ in the response
- * object's property values.
- * @private
- * @param {object} o The connection object
- * @param {} callbackArg 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+1);
- }
- }
-
- obj.tId = o.tId;
- obj.status = o.conn.status;
- obj.statusText = 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;
- }
- }
- catch(e){}
- finally
- {
- return obj;
- }
- },
-
- /**
- * If a transaction cannot be completed due to dropped or closed connections,
- * there may be not be enough information to build a full response object.
- * The failure callback will be fired and this specific condition can be identified
- * by a status property value of 0.
- * @private
- * @param {int} tId Transaction Id
- * @param callbackArg The user-defined arguments
- * @return object
- */
- createExceptionObject:function(tId, callbackArg)
- {
- var COMM_CODE = 0;
- var COMM_ERROR = 'communication failure';
-
- var obj = {};
-
- obj.tId = tId;
- obj.status = COMM_CODE;
- obj.statusText = COMM_ERROR;
- if(callbackArg){
- obj.argument = callbackArg;
- }
-
- return obj;
- },
-
- /**
- * Public method that stores the custom HTTP headers for each transaction.
- * @public
- * @param {string} label The HTTP header label
- * @param {string} value The HTTP header value
- * @return void
- */
- initHeader:function(label,value)
- {
- if(this._http_header[label] === undefined){
- this._http_header[label] = value;
- }
- else{
- this._http_header[label] = value + "," + this._http_header[label];
- }
-
- this._has_http_headers = true;
- },
-
- /**
- * Accessor that sets the HTTP headers for each transaction.
- * @private
- * @param {object} o The connection object for the transaction.
- * @return void
- */
- setHeader:function(o)
- {
- for(var prop in this._http_header){
- o.conn.setRequestHeader(prop, this._http_header[prop]);
- }
- delete this._http_header;
-
- this._http_header = {};
- this._has_http_headers = false;
- },
-
- /**
- * This method assembles the form label and value pairs and
- * constructs an encoded string.
- * asyncRequest() will automatically initialize the
- * transaction with a HTTP header Content-Type of
- * application/x-www-form-urlencoded.
- * @public
- * @param {string || object} form id or name attribute, or form object.
- * @return void
- */
- setForm:function(formId)
- {
- this._sFormData = '';
- 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.
- var oForm = (document.getElementById(formId) || document.forms[formId] );
- }
- else if(typeof formId == 'object'){
- var oForm = formId;
- }
- else{
- 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++){
- oDisabled = oForm.elements[i].disabled;
- // If the name attribute is not populated, the form field's
- // value will not be submitted.
- if(oForm.elements[i].name != ""){
- oElement = oForm.elements[i];
- oName = oForm.elements[i].name;
- oValue = oForm.elements[i].value;
- }
-
- // Do not submit fields that are disabled.
- if(!oDisabled)
- {
- switch (oElement.type)
- {
- case 'select-one':
- case 'select-multiple':
- for(var j=0; j<oElement.options.length; j++){
- if(oElement.options[j].selected){
- this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(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':
- // this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
- // 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){
- this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
- hasSubmit = true;
- }
- break;
- default:
- this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
- break;
- }
- }
- }
-
- this._isFormSubmit = true;
- this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
- },
-
- /**
- * Public method to terminate a transaction, if it has not reached readyState 4.
- * @public
- * @param {object} o The connection object returned by asyncRequest.
- * @return void
- */
- abort:function(o)
- {
- if(this.isCallInProgress(o)){
- window.clearInterval(this._poll[o.tId]);
- this._poll.splice(o.tId);
- o.conn.abort();
- this.releaseObject(o);
-
- return true;
- }
- else{
- return false;
- }
- },
-
- /**
- * Public method to check if the transaction is still being processed.
- * @public
- * @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.conn){
- return o.conn.readyState != 4 && o.conn.readyState != 0;
- }
- else{
- //The XHR object has been destroyed.
- return false;
- }
- },
-
- /**
- * Dereference the XHR instance and the connection object after the transaction is completed.
- * @private
- * @param {object} o The connection object
- * @return void
- */
- releaseObject:function(o)
- {
- //dereference the XHR instance.
- o.conn = null;
- //dereference the connection object.
- o = null;
- }
-};
+++ /dev/null
-/* \r
-Copyright (c) 2006, Yahoo! Inc. All rights reserved. \r
-Code licensed under the BSD License: \r
-http://developer.yahoo.net/yui/license.txt \r
-version: 0.10.0 \r
-*/ \r
-\r
-/**\r
- * The CustomEvent class lets you define events for your application\r
- * that can be subscribed to by one or more independent component.\r
- *\r
- * @param {String} type The type of event, which is passed to the callback\r
- * when the event fires\r
- * @param {Object} oScope The context the event will fire from. "this" will\r
- * refer to this object in the callback. Default value: \r
- * the window object. The listener can override this.\r
- * @constructor\r
- */\r
-YAHOO.util.CustomEvent = function(type, oScope) {\r
- /**\r
- * The type of event, returned to subscribers when the event fires\r
- * @type string\r
- */\r
- this.type = type;\r
-\r
- /**\r
- * The scope the the event will fire from by default. Defaults to the window \r
- * obj\r
- * @type object\r
- */\r
- this.scope = oScope || window;\r
-\r
- /**\r
- * The subscribers to this event\r
- * @type Subscriber[]\r
- */\r
- this.subscribers = [];\r
-\r
- // Register with the event utility for automatic cleanup. Made optional\r
- // so that CustomEvent can be used independently of pe.event\r
- if (YAHOO.util.Event) { \r
- YAHOO.util.Event.regCE(this);\r
- }\r
-};\r
-\r
-YAHOO.util.CustomEvent.prototype = {\r
- /**\r
- * Subscribes the caller to this event\r
- * @param {Function} fn The function to execute\r
- * @param {Object} obj An object to be passed along when the event fires\r
- * @param {boolean} bOverride If true, the obj passed in becomes the execution\r
- * scope of the listener\r
- */\r
- subscribe: function(fn, obj, bOverride) {\r
- this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );\r
- },\r
-\r
- /**\r
- * Unsubscribes the caller from this event\r
- * @param {Function} fn The function to execute\r
- * @param {Object} obj An object to be passed along when the event fires\r
- * @return {boolean} True if the subscriber was found and detached.\r
- */\r
- unsubscribe: function(fn, obj) {\r
- var found = false;\r
- for (var i=0, len=this.subscribers.length; i<len; ++i) {\r
- var s = this.subscribers[i];\r
- if (s && s.contains(fn, obj)) {\r
- this._delete(i);\r
- found = true;\r
- }\r
- }\r
-\r
- return found;\r
- },\r
-\r
- /**\r
- * Notifies the subscribers. The callback functions will be executed\r
- * from the scope specified when the event was created, and with the following\r
- * parameters:\r
- * <pre>\r
- * - The type of event\r
- * - All of the arguments fire() was executed with as an array\r
- * - The custom object (if any) that was passed into the subscribe() method\r
- * </pre>\r
- * \r
- * @param {Array} an arbitrary set of parameters to pass to the handler\r
- */\r
- fire: function() {\r
- for (var i=0, len=this.subscribers.length; i<len; ++i) {\r
- var s = this.subscribers[i];\r
- if (s) {\r
- var scope = (s.override) ? s.obj : this.scope;\r
- s.fn.call(scope, this.type, arguments, s.obj);\r
- }\r
- }\r
- },\r
-\r
- /**\r
- * Removes all listeners\r
- */\r
- unsubscribeAll: function() {\r
- for (var i=0, len=this.subscribers.length; i<len; ++i) {\r
- this._delete(i);\r
- }\r
- },\r
-\r
- /**\r
- * @private\r
- */\r
- _delete: function(index) {\r
- var s = this.subscribers[index];\r
- if (s) {\r
- delete s.fn;\r
- delete s.obj;\r
- }\r
-\r
- delete this.subscribers[index];\r
- }\r
-};\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-\r
-/**\r
- * @class Stores the subscriber information to be used when the event fires.\r
- * @param {Function} fn The function to execute\r
- * @param {Object} obj An object to be passed along when the event fires\r
- * @param {boolean} bOverride If true, the obj passed in becomes the execution\r
- * scope of the listener\r
- * @constructor\r
- */\r
-YAHOO.util.Subscriber = function(fn, obj, bOverride) {\r
- /**\r
- * The callback that will be execute when the event fires\r
- * @type function\r
- */\r
- this.fn = fn;\r
-\r
- /**\r
- * An optional custom object that will passed to the callback when\r
- * the event fires\r
- * @type object\r
- */\r
- this.obj = obj || null;\r
-\r
- /**\r
- * The default execution scope for the event listener is defined when the\r
- * event is created (usually the object which contains the event).\r
- * By setting override to true, the execution scope becomes the custom\r
- * object passed in by the subscriber\r
- * @type boolean\r
- */\r
- this.override = (bOverride);\r
-};\r
-\r
-/**\r
- * Returns true if the fn and obj match this objects properties.\r
- * Used by the unsubscribe method to match the right subscriber.\r
- *\r
- * @param {Function} fn the function to execute\r
- * @param {Object} obj an object to be passed along when the event fires\r
- * @return {boolean} true if the supplied arguments match this \r
- * subscriber's signature.\r
- */\r
-YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {\r
- return (this.fn == fn && this.obj == obj);\r
-};\r
-\r
-/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */\r
-\r
-// Only load this library once. If it is loaded a second time, existing\r
-// events cannot be detached.\r
-if (!YAHOO.util.Event) {\r
-\r
-/**\r
- * @class\r
- * The event utility provides functions to add and remove event listeners,\r
- * event cleansing. It also tries to automatically remove listeners it\r
- * registers during the unload event.\r
- * @constructor\r
- */\r
- YAHOO.util.Event = function() {\r
-\r
- /**\r
- * True after the onload event has fired\r
- * @type boolean\r
- * @private\r
- */\r
- var loadComplete = false;\r
-\r
- /**\r
- * Cache of wrapped listeners\r
- * @type array\r
- * @private\r
- */\r
- var listeners = [];\r
-\r
- /**\r
- * Listeners that will be attached during the onload event\r
- * @type array\r
- * @private\r
- */\r
- var delayedListeners = [];\r
-\r
- /**\r
- * User-defined unload function that will be fired before all events\r
- * are detached\r
- * @type array\r
- * @private\r
- */\r
- var unloadListeners = [];\r
-\r
- /**\r
- * Cache of the custom events that have been defined. Used for\r
- * automatic cleanup\r
- * @type array\r
- * @private\r
- */\r
- var customEvents = [];\r
-\r
- /**\r
- * Cache of DOM0 event handlers to work around issues with DOM2 events\r
- * in Safari\r
- * @private\r
- */\r
- var legacyEvents = [];\r
-\r
- /**\r
- * Listener stack for DOM0 events\r
- * @private\r
- */\r
- var legacyHandlers = [];\r
-\r
- /**\r
- * The number of times to poll after window.onload. This number is\r
- * increased if additional late-bound handlers are requested after\r
- * the page load.\r
- * @private\r
- */\r
- var retryCount = 0;\r
-\r
- /**\r
- * onAvailable listeners\r
- * @private\r
- */\r
- var onAvailStack = [];\r
-\r
- /**\r
- * Lookup table for legacy events\r
- * @private\r
- */\r
- var legacyMap = [];\r
-\r
- /**\r
- * Counter for auto id generation\r
- * @private\r
- */\r
- var counter = 0;\r
-\r
- return { // PREPROCESS\r
-\r
- /**\r
- * The number of times we should look for elements that are not\r
- * in the DOM at the time the event is requested after the document\r
- * has been loaded. The default is 200@50 ms, so it will poll\r
- * for 10 seconds or until all outstanding handlers are bound\r
- * (whichever comes first).\r
- * @type int\r
- */\r
- POLL_RETRYS: 200,\r
-\r
- /**\r
- * The poll interval in milliseconds\r
- * @type int\r
- */\r
- POLL_INTERVAL: 50,\r
-\r
- /**\r
- * Element to bind, int constant\r
- * @type int\r
- */\r
- EL: 0,\r
-\r
- /**\r
- * Type of event, int constant\r
- * @type int\r
- */\r
- TYPE: 1,\r
-\r
- /**\r
- * Function to execute, int constant\r
- * @type int\r
- */\r
- FN: 2,\r
-\r
- /**\r
- * Function wrapped for scope correction and cleanup, int constant\r
- * @type int\r
- */\r
- WFN: 3,\r
-\r
- /**\r
- * Object passed in by the user that will be returned as a \r
- * parameter to the callback, int constant\r
- * @type int\r
- */\r
- SCOPE: 3,\r
-\r
- /**\r
- * Adjusted scope, either the element we are registering the event\r
- * on or the custom object passed in by the listener, int constant\r
- * @type int\r
- */\r
- ADJ_SCOPE: 4,\r
-\r
- /**\r
- * Safari detection is necessary to work around the preventDefault\r
- * bug that makes it so you can't cancel a href click from the \r
- * handler. There is not a capabilities check we can use here.\r
- * @private\r
- */\r
- isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),\r
-\r
- /**\r
- * IE detection needed to properly calculate pageX and pageY. \r
- * capabilities checking didn't seem to work because another \r
- * browser that does not provide the properties have the values \r
- * calculated in a different manner than IE.\r
- * @private\r
- */\r
- isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && \r
- navigator.userAgent.match(/msie/gi)),\r
-\r
- /**\r
- * @private\r
- */\r
- addDelayedListener: function(el, sType, fn, oScope, bOverride) {\r
- delayedListeners[delayedListeners.length] =\r
- [el, sType, fn, oScope, bOverride];\r
-\r
- // If this happens after the inital page load, we need to\r
- // reset the poll counter so that we continue to search for\r
- // the element for a fixed period of time.\r
- if (loadComplete) {\r
- retryCount = this.POLL_RETRYS;\r
- this.startTimeout(0);\r
- // this._tryPreloadAttach();\r
- }\r
- },\r
-\r
- /**\r
- * @private\r
- */\r
- startTimeout: function(interval) {\r
- var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;\r
- var self = this;\r
- var callback = function() { self._tryPreloadAttach(); };\r
- this.timeout = setTimeout(callback, i);\r
- },\r
-\r
- /**\r
- * Executes the supplied callback when the item with the supplied\r
- * id is found. This is meant to be used to execute behavior as\r
- * soon as possible as the page loads. If you use this after the\r
- * initial page load it will poll for a fixed time for the element.\r
- * The number of times it will poll and the frequency are\r
- * configurable. By default it will poll for 10 seconds.\r
- * @param {string} p_id the id of the element to look for.\r
- * @param {function} p_fn what to execute when the element is found.\r
- * @param {object} p_obj an optional object to be passed back as\r
- * a parameter to p_fn.\r
- * @param {boolean} p_override If set to true, p_fn will execute\r
- * in the scope of p_obj\r
- *\r
- */\r
- onAvailable: function(p_id, p_fn, p_obj, p_override) {\r
- onAvailStack.push( { id: p_id, \r
- fn: p_fn, \r
- obj: p_obj, \r
- override: p_override } );\r
-\r
- retryCount = this.POLL_RETRYS;\r
- this.startTimeout(0);\r
- // this._tryPreloadAttach();\r
- },\r
-\r
- /**\r
- * Appends an event handler\r
- *\r
- * @param {Object} el The html element to assign the \r
- * event to\r
- * @param {String} sType The type of event to append\r
- * @param {Function} fn The method the event invokes\r
- * @param {Object} oScope An arbitrary object that will be \r
- * passed as a parameter to the handler\r
- * @param {boolean} bOverride If true, the obj passed in becomes\r
- * the execution scope of the listener\r
- * @return {boolean} True if the action was successful or defered,\r
- * false if one or more of the elements \r
- * could not have the event bound to it.\r
- */\r
- addListener: function(el, sType, fn, oScope, bOverride) {\r
-\r
- if (!fn || !fn.call) {\r
- return false;\r
- }\r
-\r
- // The el argument can be an array of elements or element ids.\r
- if ( this._isValidCollection(el)) {\r
- var ok = true;\r
- for (var i=0,len=el.length; i<len; ++i) {\r
- ok = ( this.on(el[i], \r
- sType, \r
- fn, \r
- oScope, \r
- bOverride) && ok );\r
- }\r
- return ok;\r
-\r
- } else if (typeof el == "string") {\r
- var oEl = this.getEl(el);\r
- // If the el argument is a string, we assume it is \r
- // actually the id of the element. If the page is loaded\r
- // we convert el to the actual element, otherwise we \r
- // defer attaching the event until onload event fires\r
-\r
- // check to see if we need to delay hooking up the event \r
- // until after the page loads.\r
- if (loadComplete && oEl) {\r
- el = oEl;\r
- } else {\r
- // defer adding the event until onload fires\r
- this.addDelayedListener(el, \r
- sType, \r
- fn, \r
- oScope, \r
- bOverride);\r
-\r
- return true;\r
- }\r
- }\r
-\r
- // Element should be an html element or an array if we get \r
- // here.\r
- if (!el) {\r
- return false;\r
- }\r
-\r
- // we need to make sure we fire registered unload events \r
- // prior to automatically unhooking them. So we hang on to \r
- // these instead of attaching them to the window and fire the\r
- // handles explicitly during our one unload event.\r
- if ("unload" == sType && oScope !== this) {\r
- unloadListeners[unloadListeners.length] =\r
- [el, sType, fn, oScope, bOverride];\r
- return true;\r
- }\r
-\r
-\r
- // if the user chooses to override the scope, we use the custom\r
- // object passed in, otherwise the executing scope will be the\r
- // HTML element that the event is registered on\r
- var scope = (bOverride) ? oScope : el;\r
-\r
- // wrap the function so we can return the oScope object when\r
- // the event fires;\r
- var wrappedFn = function(e) {\r
- return fn.call(scope, YAHOO.util.Event.getEvent(e), \r
- oScope);\r
- };\r
-\r
- var li = [el, sType, fn, wrappedFn, scope];\r
- var index = listeners.length;\r
- // cache the listener so we can try to automatically unload\r
- listeners[index] = li;\r
-\r
- if (this.useLegacyEvent(el, sType)) {\r
- var legacyIndex = this.getLegacyIndex(el, sType);\r
- if (legacyIndex == -1) {\r
-\r
- legacyIndex = legacyEvents.length;\r
- legacyMap[el.id + sType] = legacyIndex;\r
-\r
- // cache the signature for the DOM0 event, and \r
- // include the existing handler for the event, if any\r
- legacyEvents[legacyIndex] = \r
- [el, sType, el["on" + sType]];\r
- legacyHandlers[legacyIndex] = [];\r
-\r
- el["on" + sType] = \r
- function(e) {\r
- YAHOO.util.Event.fireLegacyEvent(\r
- YAHOO.util.Event.getEvent(e), legacyIndex);\r
- };\r
- }\r
-\r
- // add a reference to the wrapped listener to our custom\r
- // stack of events\r
- legacyHandlers[legacyIndex].push(index);\r
-\r
- // DOM2 Event model\r
- } else if (el.addEventListener) {\r
- el.addEventListener(sType, wrappedFn, false);\r
- // Internet Explorer abstraction\r
- } else if (el.attachEvent) {\r
- el.attachEvent("on" + sType, wrappedFn);\r
- }\r
-\r
- return true;\r
- \r
- },\r
-\r
- /**\r
- * Shorthand for YAHOO.util.Event.addListener\r
- * @type function\r
- */\r
- // on: this.addListener,\r
-\r
- /**\r
- * When using legacy events, the handler is routed to this object\r
- * so we can fire our custom listener stack.\r
- * @private\r
- */\r
- fireLegacyEvent: function(e, legacyIndex) {\r
- var ok = true;\r
-\r
- var le = legacyHandlers[legacyIndex];\r
- for (var i=0,len=le.length; i<len; ++i) {\r
- var index = le[i];\r
- if (index) {\r
- var li = listeners[index];\r
- if ( li && li[this.WFN] ) {\r
- var scope = li[this.ADJ_SCOPE];\r
- var ret = li[this.WFN].call(scope, e);\r
- ok = (ok && ret);\r
- } else {\r
- // This listener was removed, so delete it from\r
- // the array\r
- delete le[i];\r
- }\r
- }\r
- }\r
-\r
- return ok;\r
- },\r
-\r
- /**\r
- * Returns the legacy event index that matches the supplied \r
- * signature\r
- * @private\r
- */\r
- getLegacyIndex: function(el, sType) {\r
- /*\r
- for (var i=0,len=legacyEvents.length; i<len; ++i) {\r
- var le = legacyEvents[i];\r
- if (le && le[0] === el && le[1] === sType) {\r
- return i;\r
- }\r
- }\r
- return -1;\r
- */\r
-\r
- var key = this.generateId(el) + sType;\r
- if (typeof legacyMap[key] == "undefined") { \r
- return -1;\r
- } else {\r
- return legacyMap[key];\r
- }\r
-\r
- },\r
-\r
- /**\r
- * Logic that determines when we should automatically use legacy\r
- * events instead of DOM2 events.\r
- * @private\r
- */\r
- useLegacyEvent: function(el, sType) {\r
-\r
- if (!el.addEventListener && !el.attachEvent) {\r
- return true;\r
- } else if (this.isSafari) {\r
- if ("click" == sType || "dblclick" == sType) {\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
- },\r
- \r
- /**\r
- * Removes an event handler\r
- *\r
- * @param {Object} el the html element or the id of the element to \r
- * assign the event to.\r
- * @param {String} sType the type of event to remove\r
- * @param {Function} fn the method the event invokes\r
- * @return {boolean} true if the unbind was successful, false \r
- * otherwise\r
- */\r
- removeListener: function(el, sType, fn, index) {\r
-\r
- if (!fn || !fn.call) {\r
- return false;\r
- }\r
-\r
- // The el argument can be a string\r
- if (typeof el == "string") {\r
- el = this.getEl(el);\r
- // The el argument can be an array of elements or element ids.\r
- } else if ( this._isValidCollection(el)) {\r
- var ok = true;\r
- for (var i=0,len=el.length; i<len; ++i) {\r
- ok = ( this.removeListener(el[i], sType, fn) && ok );\r
- }\r
- return ok;\r
- }\r
-\r
- if ("unload" == sType) {\r
-\r
- for (i=0, len=unloadListeners.length; i<len; i++) {\r
- var li = unloadListeners[i];\r
- if (li && \r
- li[0] == el && \r
- li[1] == sType && \r
- li[2] == fn) {\r
- delete unloadListeners[i];\r
- return true;\r
- }\r
- }\r
-\r
- return false;\r
- }\r
-\r
- var cacheItem = null;\r
- \r
- if ("undefined" == typeof index) {\r
- index = this._getCacheIndex(el, sType, fn);\r
- }\r
-\r
- if (index >= 0) {\r
- cacheItem = listeners[index];\r
- }\r
-\r
- if (!el || !cacheItem) {\r
- return false;\r
- }\r
-\r
-\r
- if (el.removeEventListener) {\r
- el.removeEventListener(sType, cacheItem[this.WFN], false);\r
- } else if (el.detachEvent) {\r
- el.detachEvent("on" + sType, cacheItem[this.WFN]);\r
- }\r
-\r
- // removed the wrapped handler\r
- delete listeners[index][this.WFN];\r
- delete listeners[index][this.FN];\r
- delete listeners[index];\r
-\r
- return true;\r
-\r
- },\r
-\r
- /**\r
- * Returns the event's target element\r
- * @param {Event} ev the event\r
- * @param {boolean} resolveTextNode when set to true the target's\r
- * parent will be returned if the target is a \r
- * text node\r
- * @return {HTMLElement} the event's target\r
- */\r
- getTarget: function(ev, resolveTextNode) {\r
- var t = ev.target || ev.srcElement;\r
-\r
- if (resolveTextNode && t && "#text" == t.nodeName) {\r
- return t.parentNode;\r
- } else {\r
- return t;\r
- }\r
- },\r
-\r
- /**\r
- * Returns the event's pageX\r
- * @param {Event} ev the event\r
- * @return {int} the event's pageX\r
- */\r
- getPageX: function(ev) {\r
- var x = ev.pageX;\r
- if (!x && 0 !== x) {\r
- x = ev.clientX || 0;\r
-\r
- if ( this.isIE ) {\r
- x += this._getScrollLeft();\r
- }\r
- }\r
-\r
- return x;\r
- },\r
-\r
- /**\r
- * Returns the event's pageY\r
- * @param {Event} ev the event\r
- * @return {int} the event's pageY\r
- */\r
- getPageY: function(ev) {\r
- var y = ev.pageY;\r
- if (!y && 0 !== y) {\r
- y = ev.clientY || 0;\r
-\r
- if ( this.isIE ) {\r
- y += this._getScrollTop();\r
- }\r
- }\r
-\r
- return y;\r
- },\r
-\r
- /**\r
- * Returns the pageX and pageY properties as an indexed array.\r
- * @type int[]\r
- */\r
- getXY: function(ev) {\r
- return [this.getPageX(ev), this.getPageY(ev)];\r
- },\r
-\r
- /**\r
- * Returns the event's related target \r
- * @param {Event} ev the event\r
- * @return {HTMLElement} the event's relatedTarget\r
- */\r
- getRelatedTarget: function(ev) {\r
- var t = ev.relatedTarget;\r
- if (!t) {\r
- if (ev.type == "mouseout") {\r
- t = ev.toElement;\r
- } else if (ev.type == "mouseover") {\r
- t = ev.fromElement;\r
- }\r
- }\r
-\r
- return t;\r
- },\r
-\r
- /**\r
- * Returns the time of the event. If the time is not included, the\r
- * event is modified using the current time.\r
- * @param {Event} ev the event\r
- * @return {Date} the time of the event\r
- */\r
- getTime: function(ev) {\r
- if (!ev.time) {\r
- var t = new Date().getTime();\r
- try {\r
- ev.time = t;\r
- } catch(e) { \r
- // can't set the time property \r
- return t;\r
- }\r
- }\r
-\r
- return ev.time;\r
- },\r
-\r
- /**\r
- * Convenience method for stopPropagation + preventDefault\r
- * @param {Event} ev the event\r
- */\r
- stopEvent: function(ev) {\r
- this.stopPropagation(ev);\r
- this.preventDefault(ev);\r
- },\r
-\r
- /**\r
- * Stops event propagation\r
- * @param {Event} ev the event\r
- */\r
- stopPropagation: function(ev) {\r
- if (ev.stopPropagation) {\r
- ev.stopPropagation();\r
- } else {\r
- ev.cancelBubble = true;\r
- }\r
- },\r
-\r
- /**\r
- * Prevents the default behavior of the event\r
- * @param {Event} ev the event\r
- */\r
- preventDefault: function(ev) {\r
- if (ev.preventDefault) {\r
- ev.preventDefault();\r
- } else {\r
- ev.returnValue = false;\r
- }\r
- },\r
- \r
- /**\r
- * Finds the event in the window object, the caller's arguments, or\r
- * in the arguments of another method in the callstack. This is\r
- * executed automatically for events registered through the event\r
- * manager, so the implementer should not normally need to execute\r
- * this function at all.\r
- * @param {Event} the event parameter from the handler\r
- * @return {Event} the event \r
- */\r
- getEvent: function(e) {\r
- var ev = e || window.event;\r
-\r
- if (!ev) {\r
- var c = this.getEvent.caller;\r
- while (c) {\r
- ev = c.arguments[0];\r
- if (ev && Event == ev.constructor) {\r
- break;\r
- }\r
- c = c.caller;\r
- }\r
- }\r
-\r
- return ev;\r
- },\r
-\r
- /**\r
- * Returns the charcode for an event\r
- * @param {Event} ev the event\r
- * @return {int} the event's charCode\r
- */\r
- getCharCode: function(ev) {\r
- return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);\r
- },\r
-\r
- /**\r
- * @private\r
- * Locating the saved event handler data by function ref\r
- */\r
- _getCacheIndex: function(el, sType, fn) {\r
- for (var i=0,len=listeners.length; i<len; ++i) {\r
- var li = listeners[i];\r
- if ( li && \r
- li[this.FN] == fn && \r
- li[this.EL] == el && \r
- li[this.TYPE] == sType ) {\r
- return i;\r
- }\r
- }\r
-\r
- return -1;\r
- },\r
-\r
- /**\r
- * Generates an unique ID for the element if it does not already \r
- * have one.\r
- * @param el the element\r
- * @return {string} the id of the element\r
- */\r
- generateId: function(el) {\r
- var id = el.id;\r
-\r
- if (!id) {\r
- id = "yuievtautoid-" + (counter++);\r
- el.id = id;\r
- }\r
-\r
- return id;\r
- },\r
-\r
- /**\r
- * We want to be able to use getElementsByTagName as a collection\r
- * to attach a group of events to. Unfortunately, different \r
- * browsers return different types of collections. This function\r
- * tests to determine if the object is array-like. It will also \r
- * fail if the object is an array, but is empty.\r
- * @param o the object to test\r
- * @return {boolean} true if the object is array-like and populated\r
- * @private\r
- */\r
- _isValidCollection: function(o) {\r
-\r
- return ( o && // o is something\r
- o.length && // o is indexed\r
- typeof o != "string" && // o is not a string\r
- !o.tagName && // o is not an HTML element\r
- !o.alert && // o is not a window\r
- typeof o[0] != "undefined" );\r
-\r
- },\r
-\r
- /**\r
- * @private\r
- * DOM element cache\r
- */\r
- elCache: {},\r
-\r
- /**\r
- * We cache elements bound by id because when the unload event \r
- * fires, we can no longer use document.getElementById\r
- * @private\r
- */\r
- getEl: function(id) {\r
- return document.getElementById(id);\r
- },\r
-\r
- /**\r
- * Clears the element cache\r
- * @deprecated\r
- * @private\r
- */\r
- clearCache: function() { },\r
-\r
- /**\r
- * Called by CustomEvent instances to provide a handle to the \r
- * event * that can be removed later on. Should be package \r
- * protected.\r
- * @private\r
- */\r
- regCE: function(ce) {\r
- customEvents.push(ce);\r
- },\r
-\r
- /**\r
- * @private\r
- * hook up any deferred listeners\r
- */\r
- _load: function(e) {\r
- loadComplete = true;\r
- },\r
-\r
- /**\r
- * Polling function that runs before the onload event fires, \r
- * attempting * to attach to DOM Nodes as soon as they are \r
- * available\r
- * @private\r
- */\r
- _tryPreloadAttach: function() {\r
-\r
- if (this.locked) {\r
- return false;\r
- }\r
-\r
- this.locked = true;\r
-\r
-\r
- // keep trying until after the page is loaded. We need to \r
- // check the page load state prior to trying to bind the \r
- // elements so that we can be certain all elements have been \r
- // tested appropriately\r
- var tryAgain = !loadComplete;\r
- if (!tryAgain) {\r
- tryAgain = (retryCount > 0);\r
- }\r
-\r
- // Delayed listeners\r
- var stillDelayed = [];\r
-\r
- for (var i=0,len=delayedListeners.length; i<len; ++i) {\r
- var d = delayedListeners[i];\r
- // There may be a race condition here, so we need to \r
- // verify the array element is usable.\r
- if (d) {\r
-\r
- // el will be null if document.getElementById did not\r
- // work\r
- var el = this.getEl(d[this.EL]);\r
-\r
- if (el) {\r
- this.on(el, d[this.TYPE], d[this.FN], \r
- d[this.SCOPE], d[this.ADJ_SCOPE]);\r
- delete delayedListeners[i];\r
- } else {\r
- stillDelayed.push(d);\r
- }\r
- }\r
- }\r
-\r
- delayedListeners = stillDelayed;\r
-\r
- // onAvailable\r
- notAvail = [];\r
- for (i=0,len=onAvailStack.length; i<len ; ++i) {\r
- var item = onAvailStack[i];\r
- if (item) {\r
- el = this.getEl(item.id);\r
-\r
- if (el) {\r
- var scope = (item.override) ? item.obj : el;\r
- item.fn.call(scope, item.obj);\r
- delete onAvailStack[i];\r
- } else {\r
- notAvail.push(item);\r
- }\r
- }\r
- }\r
-\r
- retryCount = (stillDelayed.length === 0 && \r
- notAvail.length === 0) ? 0 : retryCount - 1;\r
-\r
- if (tryAgain) {\r
- this.startTimeout();\r
- }\r
-\r
- this.locked = false;\r
-\r
- },\r
-\r
- /**\r
- * Removes all listeners registered by pe.event. Called \r
- * automatically during the unload event.\r
- * @private\r
- */\r
- _unload: function(e, me) {\r
- for (var i=0,len=unloadListeners.length; i<len; ++i) {\r
- var l = unloadListeners[i];\r
- if (l) {\r
- var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;\r
- l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );\r
- }\r
- }\r
-\r
- if (listeners && listeners.length > 0) {\r
- for (i=0,len=listeners.length; i<len ; ++i) {\r
- l = listeners[i];\r
- if (l) {\r
- this.removeListener(l[this.EL], l[this.TYPE], \r
- l[this.FN], i);\r
- }\r
- }\r
-\r
- this.clearCache();\r
- }\r
-\r
- for (i=0,len=customEvents.length; i<len; ++i) {\r
- customEvents[i].unsubscribeAll();\r
- delete customEvents[i];\r
- }\r
-\r
- for (i=0,len=legacyEvents.length; i<len; ++i) {\r
- // dereference the element\r
- delete legacyEvents[i][0];\r
- // delete the array item\r
- delete legacyEvents[i];\r
- }\r
- },\r
-\r
- /**\r
- * Returns scrollLeft\r
- * @private\r
- */\r
- _getScrollLeft: function() {\r
- return this._getScroll()[1];\r
- },\r
-\r
- /**\r
- * Returns scrollTop\r
- * @private\r
- */\r
- _getScrollTop: function() {\r
- return this._getScroll()[0];\r
- },\r
-\r
- /**\r
- * Returns the scrollTop and scrollLeft. Used to calculate the \r
- * pageX and pageY in Internet Explorer\r
- * @private\r
- */\r
- _getScroll: function() {\r
- var dd = document.documentElement; db = document.body;\r
- if (dd && dd.scrollTop) {\r
- return [dd.scrollTop, dd.scrollLeft];\r
- } else if (db) {\r
- return [db.scrollTop, db.scrollLeft];\r
- } else {\r
- return [0, 0];\r
- }\r
- }\r
- };\r
- } ();\r
-\r
- /**\r
- * @private\r
- */\r
- YAHOO.util.Event.on = YAHOO.util.Event.addListener;\r
-\r
- if (document && document.body) {\r
- YAHOO.util.Event._load();\r
- } else {\r
- YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load, \r
- YAHOO.util.Event, true);\r
- }\r
-\r
- YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload, \r
- YAHOO.util.Event, true);\r
-\r
- YAHOO.util.Event._tryPreloadAttach();\r
-\r
-}\r
-\r
+++ /dev/null
-/* \r
-Copyright (c) 2006, Yahoo! Inc. All rights reserved. \r
-Code licensed under the BSD License: \r
-http://developer.yahoo.net/yui/license.txt \r
-version: 0.10.0 \r
-*/ \r
-\r
-/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */\r
-\r
-/**\r
- * The Yahoo global namespace\r
- * @constructor\r
- */\r
-var YAHOO = window.YAHOO || {};\r
-\r
-/**\r
- * Returns the namespace specified and creates it if it doesn't exist\r
- *\r
- * YAHOO.namespace("property.package");\r
- * YAHOO.namespace("YAHOO.property.package");\r
- *\r
- * Either of the above would create YAHOO.property, then\r
- * YAHOO.property.package\r
- *\r
- * @param {String} sNameSpace String representation of the desired \r
- * namespace\r
- * @return {Object} A reference to the namespace object\r
- */\r
-YAHOO.namespace = function( sNameSpace ) {\r
-\r
- if (!sNameSpace || !sNameSpace.length) {\r
- return null;\r
- }\r
-\r
- var levels = sNameSpace.split(".");\r
-\r
- var currentNS = YAHOO;\r
-\r
- // YAHOO is implied, so it is ignored if it is included\r
- for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {\r
- currentNS[levels[i]] = currentNS[levels[i]] || {};\r
- currentNS = currentNS[levels[i]];\r
- }\r
-\r
- return currentNS;\r
-};\r
-\r
-/**\r
- * Global log method.\r
- */\r
-YAHOO.log = function(sMsg,sCategory) {\r
- if(YAHOO.widget.Logger) {\r
- YAHOO.widget.Logger.log(null, sMsg, sCategory);\r
- } else {\r
- return false;\r
- }\r
-};\r
-\r
-YAHOO.namespace("util");\r
-YAHOO.namespace("widget");\r
-YAHOO.namespace("example");\r
--- /dev/null
+! Copyright (C) 2006 Chris Double. All Rights Reserved.
+! See http://factorcode.org/license.txt for BSD license.
+!
+IN: furnace:fjsc
+USING: kernel html furnace xml io httpd sequences
+ namespaces file-responder parser-combinators lazy-lists
+ fjsc ;
+
+: script ( path -- )
+ #! given a path to a javascript file, output the
+ #! script tag that references it.
+ <script "text/javascript" =type =src script> </script> ;
+
+: fjsc-page ( scripts title quot -- )
+ #! Display a web page importing the given script
+ #! tags and using the title. The body of the page
+ #! is generated by calling the quotation.
+ -rot xhtml-preamble
+ chars>entities
+ <html " xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\"" write-html html>
+ <head>
+ <title> write </title>
+ [ script ] each
+ </head>
+ <body>
+ call
+ </body>
+ </html> ;
+
+: fjsc-render ( template title -- )
+ #! Render the fjsc page importing the required
+ #! scripts.
+ serving-html {
+ "/responder/fjsc-resources/yahoo/yahoo.js"
+ "/responder/fjsc-resources/yahoo/event.js"
+ "/responder/fjsc-resources/yahoo/connection.js"
+ "/responder/fjsc-resources/bootstrap.js"
+ } swap [
+ [
+ f swap render-template
+ ] fjsc-page
+ ] with-html-stream ;
+
+: compile ( code -- )
+ #! Compile the facor code as a string, outputting the http
+ #! response containing the javascript.
+ serving-text
+ 'expression' parse car parse-result-parsed fjsc-compile
+ write flush ;
+
+! The 'compile' action results in an URL that looks like
+! 'responder/fjsc/compile'. It takes one query or post
+! parameter called 'code'. It calls the 'compile' word
+! passing the parameter to it on the stack.
+\ compile {
+ { "code" v-required }
+} define-action
+
+: repl ( -- )
+ #! The main 'repl' page.
+ f "repl" "Factor to Javascript REPL" fjsc-render ;
+
+! An action called 'repl'
+\ repl { } define-action
+
+! Create the web app, providing access
+! under '/responder/fjsc' which calls the
+! 'repl' action.
+"fjsc" "repl" "apps/furnace-fjsc" web-app
+
+! An URL to the javascript resource files used by
+! the 'fjsc' responder.
+"fjsc-resources" [
+ [
+ "apps/furnace-fjsc/resources/" resource-path "doc-root" set
+ file-responder
+ ] with-scope
+] add-simple-responder
--- /dev/null
+! Copyright (C) 2006 Chris Double. All Rights Reserved.
+! See http://factorcode.org/license.txt for BSD license.
+!
+REQUIRES: libs/furnace libs/fjsc ;
+
+PROVIDE: apps/furnace-fjsc
+{
+ +files+ {
+ "furnace-fjsc.factor"
+ }
+} {
+ +tests+ {
+ }
+} {
+ +help+
+ {
+ }
+} ;
--- /dev/null
+<form id="toeval" onsubmit="fjsc_eval(document.getElementById('toeval'));return false;" method="post">
+ <textarea name="code" id="code">
+ </textarea>
+ <input type="submit"/>
+</form>
+<div id="compiled">
+</div>
+<div id="stack">
+</div>
\ No newline at end of file
--- /dev/null
+function fjsc_eval(form) {
+ var callback = {
+ success: function(o) {
+ var v = o.responseText;
+ eval(v)
+ display_datastack();
+ document.getElementById('compiled').innerHTML="<pre>" + v + "</pre>";
+ document.getElementById('code').value="";
+
+ }
+ };
+ YAHOO.util.Connect.setForm(form);
+ YAHOO.util.Connect.asyncRequest('POST', "/responder/fjsc/compile", callback);
+}
+
+var data_stack = [ ]
+
+function fjsc_dup() {
+ var v = data_stack.pop();
+ data_stack.push(v);
+ data_stack.push(v);
+}
+
+function fjsc_drop() {
+ data_stack.pop();
+}
+
+function fjsc_alert() {
+ alert(data_stack.pop())
+}
+
+function display_datastack() {
+ var html=[];
+ html.push("<table border='1'>")
+ for(var i = 0; i < data_stack.length; ++i) {
+ html.push("<tr><td>")
+ html.push(data_stack[i])
+ html.push("</td></tr>")
+ }
+ html.push("</table>")
+ document.getElementById('stack').innerHTML=html.join("");
+}
--- /dev/null
+/*
+Copyright (c) 2006, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+*/
+
+/**
+ * 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.
+ * @ class
+ */
+YAHOO.util.Connect =
+{
+ /**
+ * Array of MSFT ActiveX ids for XMLHttpRequest.
+ * @private
+ * @type array
+ */
+ _msxml_progid:[
+ 'MSXML2.XMLHTTP.5.0',
+ 'MSXML2.XMLHTTP.4.0',
+ 'MSXML2.XMLHTTP.3.0',
+ 'MSXML2.XMLHTTP',
+ 'Microsoft.XMLHTTP'
+ ],
+
+ /**
+ * Array of HTTP header(s)
+ * @private
+ * @type array
+ */
+ _http_header:{},
+
+ /**
+ * Determines if HTTP headers are set.
+ * @private
+ * @type boolean
+ */
+ _has_http_headers:false,
+
+ /**
+ * Property modified by setForm() to determine if the data
+ * should be submitted as an HTML form.
+ * @private
+ * @type boolean
+ */
+ _isFormSubmit:false,
+
+ /**
+ * Property modified by setForm() to set the HTML form data
+ * for each transaction.
+ * @private
+ * @type string
+ */
+ _sFormData:null,
+
+ /**
+ * Collection of polling references to the polling mechanism in handleReadyState.
+ * @private
+ * @type string
+ */
+ _poll:[],
+
+ /**
+ * The polling frequency, in milliseconds, for HandleReadyState.
+ * when attempting to determine a transaction's XHR readyState.
+ * The default is 50 milliseconds.
+ * @private
+ * @type int
+ */
+ _polling_interval:50,
+
+ /**
+ * A transaction counter that increments the transaction id for each transaction.
+ * @private
+ * @type int
+ */
+ _transaction_id:0,
+
+ /**
+ * Member to add an ActiveX id to the existing xml_progid array.
+ * In the event(unlikely) a new ActiveX id is introduced, it can be added
+ * without internal code modifications.
+ * @public
+ * @param string id The ActiveX id to be added to initialize the XHR object.
+ * @return void
+ */
+ setProgId:function(id)
+ {
+ this.msxml_progid.unshift(id);
+ },
+
+ /**
+ * Member to modify the default polling interval.
+ * @public
+ * @param {int} i The polling interval in milliseconds.
+ * @return void
+ */
+ setPollingInterval:function(i)
+ {
+ if(typeof i == 'number' && isFinite(i)){
+ this._polling_interval = i;
+ }
+ },
+
+ /**
+ * Instantiates a XMLHttpRequest object and returns an object with two properties:
+ * the XMLHttpRequest instance and the transaction id.
+ * @private
+ * @param {int} transactionId Property containing the transaction id for this transaction.
+ * @return connection object
+ */
+ 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]);
+ if(http){
+ // Object literal with http and tId properties
+ obj = { conn:http, tId:transactionId };
+ break;
+ }
+ }
+ catch(e){}
+ }
+ }
+ finally
+ {
+ return obj;
+ }
+ },
+
+ /**
+ * 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.
+ * @private
+ * @return object
+ */
+ getConnectionObject:function()
+ {
+ var o;
+ var tId = this._transaction_id;
+
+ try
+ {
+ o = this.createXhrObject(tId);
+ if(o){
+ this._transaction_id++;
+ }
+ }
+ catch(e){}
+ finally
+ {
+ return o;
+ }
+ },
+
+ /**
+ * Method for initiating an asynchronous request via the XHR object.
+ * @public
+ * @param {string} method HTTP transaction method
+ * @param {string} uri Fully qualified path of resource
+ * @param callback User-defined callback function or object
+ * @param {string} postData POST body
+ * @return {object} Returns the connection object
+ */
+ asyncRequest:function(method, uri, callback, postData)
+ {
+ var o = this.getConnectionObject();
+
+ if(!o){
+ return null;
+ }
+ else{
+ if(this._isFormSubmit){
+ //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 == 'GET'){
+ uri += "?" + this._sFormData;
+ }
+ else if(method == 'POST'){
+ postData = this._sFormData;
+ }
+ this._sFormData = '';
+ this._isFormSubmit = false;
+ }
+
+ o.conn.open(method, uri, true);
+
+ if(postData){
+ this.initHeader('Content-Type','application/x-www-form-urlencoded');
+ }
+
+ //Verify whether the transaction has any user-defined HTTP headers
+ //and set them.
+ if(this._has_http_headers){
+ this.setHeader(o);
+ }
+
+ this.handleReadyState(o, callback);
+ postData?o.conn.send(postData):o.conn.send(null);
+
+ return o;
+ }
+ },
+
+ /**
+ * This method serves as a timer that polls the XHR object's readyState
+ * property during a transaction, instead of binding a callback to the
+ * onreadystatechange event. Upon readyState 4, handleTransactionResponse
+ * will process the response, and the timer will be cleared.
+ *
+ * @private
+ * @param {object} o The connection object
+ * @param callback User-defined callback object
+ * @return void
+ */
+ handleReadyState:function(o, callback)
+ {
+ var oConn = this;
+ try
+ {
+ this._poll[o.tId] = window.setInterval(
+ function(){
+ if(o.conn && o.conn.readyState == 4){
+ window.clearInterval(oConn._poll[o.tId]);
+ oConn._poll.splice(o.tId);
+ oConn.handleTransactionResponse(o, callback);
+ }
+ }
+ ,this._polling_interval);
+ }
+ catch(e)
+ {
+ window.clearInterval(oConn._poll[o.tId]);
+ oConn._poll.splice(o.tId);
+ oConn.handleTransactionResponse(o, callback);
+ }
+ },
+
+ /**
+ * This method attempts to interpret the server response and
+ * determine whether the transaction was successful, or if an error or
+ * exception was encountered.
+ *
+ * @private
+ * @param {object} o The connection object
+ * @param {function} callback - User-defined callback object
+ * @return void
+ */
+ handleTransactionResponse:function(o, callback)
+ {
+ // If no valid callback is provided, then do not process any callback handling.
+ if(!callback){
+ this.releaseObject(o);
+ return;
+ }
+
+ var httpStatus;
+ var responseObject;
+
+ try
+ {
+ httpStatus = o.conn.status;
+ }
+ catch(e){
+ // 13030 is the custom code to indicate the condition -- in Mozilla/FF --
+ // when the o object's status and statusText properties are
+ // unavailable, and a query attempt throws an exception.
+ httpStatus = 13030;
+ }
+
+ if(httpStatus >= 200 && httpStatus < 300){
+ responseObject = this.createResponseObject(o, callback.argument);
+ 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]);
+ }
+ }
+ }
+ else{
+ switch(httpStatus){
+ // The following case labels are wininet.dll error codes that may be encountered.
+ // Server timeout
+ case 12002:
+ // 12029 to 12031 correspond to dropped connections.
+ case 12029:
+ case 12030:
+ case 12031:
+ // Connection closed by server.
+ case 12152:
+ // See above comments for variable status.
+ case 13030:
+ responseObject = this.createExceptionObject(o, callback.argument);
+ if(callback.failure){
+ if(!callback.scope){
+ callback.failure(responseObject);
+ }
+ else{
+ callback.failure.apply(callback.scope,[responseObject]);
+ }
+ }
+ break;
+ default:
+ responseObject = this.createResponseObject(o, callback.argument);
+ if(callback.failure){
+ if(!callback.scope){
+ callback.failure(responseObject);
+ }
+ else{
+ callback.failure.apply(callback.scope,[responseObject]);
+ }
+ }
+ }
+ }
+
+ this.releaseObject(o);
+ },
+
+ /**
+ * This method evaluates the server response, creates and returns the results via
+ * its properties. Success and failure cases will differ in the response
+ * object's property values.
+ * @private
+ * @param {object} o The connection object
+ * @param {} callbackArg 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+1);
+ }
+ }
+
+ obj.tId = o.tId;
+ obj.status = o.conn.status;
+ obj.statusText = 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;
+ }
+ }
+ catch(e){}
+ finally
+ {
+ return obj;
+ }
+ },
+
+ /**
+ * If a transaction cannot be completed due to dropped or closed connections,
+ * there may be not be enough information to build a full response object.
+ * The failure callback will be fired and this specific condition can be identified
+ * by a status property value of 0.
+ * @private
+ * @param {int} tId Transaction Id
+ * @param callbackArg The user-defined arguments
+ * @return object
+ */
+ createExceptionObject:function(tId, callbackArg)
+ {
+ var COMM_CODE = 0;
+ var COMM_ERROR = 'communication failure';
+
+ var obj = {};
+
+ obj.tId = tId;
+ obj.status = COMM_CODE;
+ obj.statusText = COMM_ERROR;
+ if(callbackArg){
+ obj.argument = callbackArg;
+ }
+
+ return obj;
+ },
+
+ /**
+ * Public method that stores the custom HTTP headers for each transaction.
+ * @public
+ * @param {string} label The HTTP header label
+ * @param {string} value The HTTP header value
+ * @return void
+ */
+ initHeader:function(label,value)
+ {
+ if(this._http_header[label] === undefined){
+ this._http_header[label] = value;
+ }
+ else{
+ this._http_header[label] = value + "," + this._http_header[label];
+ }
+
+ this._has_http_headers = true;
+ },
+
+ /**
+ * Accessor that sets the HTTP headers for each transaction.
+ * @private
+ * @param {object} o The connection object for the transaction.
+ * @return void
+ */
+ setHeader:function(o)
+ {
+ for(var prop in this._http_header){
+ o.conn.setRequestHeader(prop, this._http_header[prop]);
+ }
+ delete this._http_header;
+
+ this._http_header = {};
+ this._has_http_headers = false;
+ },
+
+ /**
+ * This method assembles the form label and value pairs and
+ * constructs an encoded string.
+ * asyncRequest() will automatically initialize the
+ * transaction with a HTTP header Content-Type of
+ * application/x-www-form-urlencoded.
+ * @public
+ * @param {string || object} form id or name attribute, or form object.
+ * @return void
+ */
+ setForm:function(formId)
+ {
+ this._sFormData = '';
+ 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.
+ var oForm = (document.getElementById(formId) || document.forms[formId] );
+ }
+ else if(typeof formId == 'object'){
+ var oForm = formId;
+ }
+ else{
+ 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++){
+ oDisabled = oForm.elements[i].disabled;
+ // If the name attribute is not populated, the form field's
+ // value will not be submitted.
+ if(oForm.elements[i].name != ""){
+ oElement = oForm.elements[i];
+ oName = oForm.elements[i].name;
+ oValue = oForm.elements[i].value;
+ }
+
+ // Do not submit fields that are disabled.
+ if(!oDisabled)
+ {
+ switch (oElement.type)
+ {
+ case 'select-one':
+ case 'select-multiple':
+ for(var j=0; j<oElement.options.length; j++){
+ if(oElement.options[j].selected){
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(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':
+ // this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+ // 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){
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+ hasSubmit = true;
+ }
+ break;
+ default:
+ this._sFormData += encodeURIComponent(oName) + '=' + encodeURIComponent(oValue) + '&';
+ break;
+ }
+ }
+ }
+
+ this._isFormSubmit = true;
+ this._sFormData = this._sFormData.substr(0, this._sFormData.length - 1);
+ },
+
+ /**
+ * Public method to terminate a transaction, if it has not reached readyState 4.
+ * @public
+ * @param {object} o The connection object returned by asyncRequest.
+ * @return void
+ */
+ abort:function(o)
+ {
+ if(this.isCallInProgress(o)){
+ window.clearInterval(this._poll[o.tId]);
+ this._poll.splice(o.tId);
+ o.conn.abort();
+ this.releaseObject(o);
+
+ return true;
+ }
+ else{
+ return false;
+ }
+ },
+
+ /**
+ * Public method to check if the transaction is still being processed.
+ * @public
+ * @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.conn){
+ return o.conn.readyState != 4 && o.conn.readyState != 0;
+ }
+ else{
+ //The XHR object has been destroyed.
+ return false;
+ }
+ },
+
+ /**
+ * Dereference the XHR instance and the connection object after the transaction is completed.
+ * @private
+ * @param {object} o The connection object
+ * @return void
+ */
+ releaseObject:function(o)
+ {
+ //dereference the XHR instance.
+ o.conn = null;
+ //dereference the connection object.
+ o = null;
+ }
+};
--- /dev/null
+/* \r
+Copyright (c) 2006, Yahoo! Inc. All rights reserved. \r
+Code licensed under the BSD License: \r
+http://developer.yahoo.net/yui/license.txt \r
+version: 0.10.0 \r
+*/ \r
+\r
+/**\r
+ * The CustomEvent class lets you define events for your application\r
+ * that can be subscribed to by one or more independent component.\r
+ *\r
+ * @param {String} type The type of event, which is passed to the callback\r
+ * when the event fires\r
+ * @param {Object} oScope The context the event will fire from. "this" will\r
+ * refer to this object in the callback. Default value: \r
+ * the window object. The listener can override this.\r
+ * @constructor\r
+ */\r
+YAHOO.util.CustomEvent = function(type, oScope) {\r
+ /**\r
+ * The type of event, returned to subscribers when the event fires\r
+ * @type string\r
+ */\r
+ this.type = type;\r
+\r
+ /**\r
+ * The scope the the event will fire from by default. Defaults to the window \r
+ * obj\r
+ * @type object\r
+ */\r
+ this.scope = oScope || window;\r
+\r
+ /**\r
+ * The subscribers to this event\r
+ * @type Subscriber[]\r
+ */\r
+ this.subscribers = [];\r
+\r
+ // Register with the event utility for automatic cleanup. Made optional\r
+ // so that CustomEvent can be used independently of pe.event\r
+ if (YAHOO.util.Event) { \r
+ YAHOO.util.Event.regCE(this);\r
+ }\r
+};\r
+\r
+YAHOO.util.CustomEvent.prototype = {\r
+ /**\r
+ * Subscribes the caller to this event\r
+ * @param {Function} fn The function to execute\r
+ * @param {Object} obj An object to be passed along when the event fires\r
+ * @param {boolean} bOverride If true, the obj passed in becomes the execution\r
+ * scope of the listener\r
+ */\r
+ subscribe: function(fn, obj, bOverride) {\r
+ this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );\r
+ },\r
+\r
+ /**\r
+ * Unsubscribes the caller from this event\r
+ * @param {Function} fn The function to execute\r
+ * @param {Object} obj An object to be passed along when the event fires\r
+ * @return {boolean} True if the subscriber was found and detached.\r
+ */\r
+ unsubscribe: function(fn, obj) {\r
+ var found = false;\r
+ for (var i=0, len=this.subscribers.length; i<len; ++i) {\r
+ var s = this.subscribers[i];\r
+ if (s && s.contains(fn, obj)) {\r
+ this._delete(i);\r
+ found = true;\r
+ }\r
+ }\r
+\r
+ return found;\r
+ },\r
+\r
+ /**\r
+ * Notifies the subscribers. The callback functions will be executed\r
+ * from the scope specified when the event was created, and with the following\r
+ * parameters:\r
+ * <pre>\r
+ * - The type of event\r
+ * - All of the arguments fire() was executed with as an array\r
+ * - The custom object (if any) that was passed into the subscribe() method\r
+ * </pre>\r
+ * \r
+ * @param {Array} an arbitrary set of parameters to pass to the handler\r
+ */\r
+ fire: function() {\r
+ for (var i=0, len=this.subscribers.length; i<len; ++i) {\r
+ var s = this.subscribers[i];\r
+ if (s) {\r
+ var scope = (s.override) ? s.obj : this.scope;\r
+ s.fn.call(scope, this.type, arguments, s.obj);\r
+ }\r
+ }\r
+ },\r
+\r
+ /**\r
+ * Removes all listeners\r
+ */\r
+ unsubscribeAll: function() {\r
+ for (var i=0, len=this.subscribers.length; i<len; ++i) {\r
+ this._delete(i);\r
+ }\r
+ },\r
+\r
+ /**\r
+ * @private\r
+ */\r
+ _delete: function(index) {\r
+ var s = this.subscribers[index];\r
+ if (s) {\r
+ delete s.fn;\r
+ delete s.obj;\r
+ }\r
+\r
+ delete this.subscribers[index];\r
+ }\r
+};\r
+\r
+/////////////////////////////////////////////////////////////////////\r
+\r
+/**\r
+ * @class Stores the subscriber information to be used when the event fires.\r
+ * @param {Function} fn The function to execute\r
+ * @param {Object} obj An object to be passed along when the event fires\r
+ * @param {boolean} bOverride If true, the obj passed in becomes the execution\r
+ * scope of the listener\r
+ * @constructor\r
+ */\r
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {\r
+ /**\r
+ * The callback that will be execute when the event fires\r
+ * @type function\r
+ */\r
+ this.fn = fn;\r
+\r
+ /**\r
+ * An optional custom object that will passed to the callback when\r
+ * the event fires\r
+ * @type object\r
+ */\r
+ this.obj = obj || null;\r
+\r
+ /**\r
+ * The default execution scope for the event listener is defined when the\r
+ * event is created (usually the object which contains the event).\r
+ * By setting override to true, the execution scope becomes the custom\r
+ * object passed in by the subscriber\r
+ * @type boolean\r
+ */\r
+ this.override = (bOverride);\r
+};\r
+\r
+/**\r
+ * Returns true if the fn and obj match this objects properties.\r
+ * Used by the unsubscribe method to match the right subscriber.\r
+ *\r
+ * @param {Function} fn the function to execute\r
+ * @param {Object} obj an object to be passed along when the event fires\r
+ * @return {boolean} true if the supplied arguments match this \r
+ * subscriber's signature.\r
+ */\r
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {\r
+ return (this.fn == fn && this.obj == obj);\r
+};\r
+\r
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */\r
+\r
+// Only load this library once. If it is loaded a second time, existing\r
+// events cannot be detached.\r
+if (!YAHOO.util.Event) {\r
+\r
+/**\r
+ * @class\r
+ * The event utility provides functions to add and remove event listeners,\r
+ * event cleansing. It also tries to automatically remove listeners it\r
+ * registers during the unload event.\r
+ * @constructor\r
+ */\r
+ YAHOO.util.Event = function() {\r
+\r
+ /**\r
+ * True after the onload event has fired\r
+ * @type boolean\r
+ * @private\r
+ */\r
+ var loadComplete = false;\r
+\r
+ /**\r
+ * Cache of wrapped listeners\r
+ * @type array\r
+ * @private\r
+ */\r
+ var listeners = [];\r
+\r
+ /**\r
+ * Listeners that will be attached during the onload event\r
+ * @type array\r
+ * @private\r
+ */\r
+ var delayedListeners = [];\r
+\r
+ /**\r
+ * User-defined unload function that will be fired before all events\r
+ * are detached\r
+ * @type array\r
+ * @private\r
+ */\r
+ var unloadListeners = [];\r
+\r
+ /**\r
+ * Cache of the custom events that have been defined. Used for\r
+ * automatic cleanup\r
+ * @type array\r
+ * @private\r
+ */\r
+ var customEvents = [];\r
+\r
+ /**\r
+ * Cache of DOM0 event handlers to work around issues with DOM2 events\r
+ * in Safari\r
+ * @private\r
+ */\r
+ var legacyEvents = [];\r
+\r
+ /**\r
+ * Listener stack for DOM0 events\r
+ * @private\r
+ */\r
+ var legacyHandlers = [];\r
+\r
+ /**\r
+ * The number of times to poll after window.onload. This number is\r
+ * increased if additional late-bound handlers are requested after\r
+ * the page load.\r
+ * @private\r
+ */\r
+ var retryCount = 0;\r
+\r
+ /**\r
+ * onAvailable listeners\r
+ * @private\r
+ */\r
+ var onAvailStack = [];\r
+\r
+ /**\r
+ * Lookup table for legacy events\r
+ * @private\r
+ */\r
+ var legacyMap = [];\r
+\r
+ /**\r
+ * Counter for auto id generation\r
+ * @private\r
+ */\r
+ var counter = 0;\r
+\r
+ return { // PREPROCESS\r
+\r
+ /**\r
+ * The number of times we should look for elements that are not\r
+ * in the DOM at the time the event is requested after the document\r
+ * has been loaded. The default is 200@50 ms, so it will poll\r
+ * for 10 seconds or until all outstanding handlers are bound\r
+ * (whichever comes first).\r
+ * @type int\r
+ */\r
+ POLL_RETRYS: 200,\r
+\r
+ /**\r
+ * The poll interval in milliseconds\r
+ * @type int\r
+ */\r
+ POLL_INTERVAL: 50,\r
+\r
+ /**\r
+ * Element to bind, int constant\r
+ * @type int\r
+ */\r
+ EL: 0,\r
+\r
+ /**\r
+ * Type of event, int constant\r
+ * @type int\r
+ */\r
+ TYPE: 1,\r
+\r
+ /**\r
+ * Function to execute, int constant\r
+ * @type int\r
+ */\r
+ FN: 2,\r
+\r
+ /**\r
+ * Function wrapped for scope correction and cleanup, int constant\r
+ * @type int\r
+ */\r
+ WFN: 3,\r
+\r
+ /**\r
+ * Object passed in by the user that will be returned as a \r
+ * parameter to the callback, int constant\r
+ * @type int\r
+ */\r
+ SCOPE: 3,\r
+\r
+ /**\r
+ * Adjusted scope, either the element we are registering the event\r
+ * on or the custom object passed in by the listener, int constant\r
+ * @type int\r
+ */\r
+ ADJ_SCOPE: 4,\r
+\r
+ /**\r
+ * Safari detection is necessary to work around the preventDefault\r
+ * bug that makes it so you can't cancel a href click from the \r
+ * handler. There is not a capabilities check we can use here.\r
+ * @private\r
+ */\r
+ isSafari: (/Safari|Konqueror|KHTML/gi).test(navigator.userAgent),\r
+\r
+ /**\r
+ * IE detection needed to properly calculate pageX and pageY. \r
+ * capabilities checking didn't seem to work because another \r
+ * browser that does not provide the properties have the values \r
+ * calculated in a different manner than IE.\r
+ * @private\r
+ */\r
+ isIE: (!this.isSafari && !navigator.userAgent.match(/opera/gi) && \r
+ navigator.userAgent.match(/msie/gi)),\r
+\r
+ /**\r
+ * @private\r
+ */\r
+ addDelayedListener: function(el, sType, fn, oScope, bOverride) {\r
+ delayedListeners[delayedListeners.length] =\r
+ [el, sType, fn, oScope, bOverride];\r
+\r
+ // If this happens after the inital page load, we need to\r
+ // reset the poll counter so that we continue to search for\r
+ // the element for a fixed period of time.\r
+ if (loadComplete) {\r
+ retryCount = this.POLL_RETRYS;\r
+ this.startTimeout(0);\r
+ // this._tryPreloadAttach();\r
+ }\r
+ },\r
+\r
+ /**\r
+ * @private\r
+ */\r
+ startTimeout: function(interval) {\r
+ var i = (interval || interval === 0) ? interval : this.POLL_INTERVAL;\r
+ var self = this;\r
+ var callback = function() { self._tryPreloadAttach(); };\r
+ this.timeout = setTimeout(callback, i);\r
+ },\r
+\r
+ /**\r
+ * Executes the supplied callback when the item with the supplied\r
+ * id is found. This is meant to be used to execute behavior as\r
+ * soon as possible as the page loads. If you use this after the\r
+ * initial page load it will poll for a fixed time for the element.\r
+ * The number of times it will poll and the frequency are\r
+ * configurable. By default it will poll for 10 seconds.\r
+ * @param {string} p_id the id of the element to look for.\r
+ * @param {function} p_fn what to execute when the element is found.\r
+ * @param {object} p_obj an optional object to be passed back as\r
+ * a parameter to p_fn.\r
+ * @param {boolean} p_override If set to true, p_fn will execute\r
+ * in the scope of p_obj\r
+ *\r
+ */\r
+ onAvailable: function(p_id, p_fn, p_obj, p_override) {\r
+ onAvailStack.push( { id: p_id, \r
+ fn: p_fn, \r
+ obj: p_obj, \r
+ override: p_override } );\r
+\r
+ retryCount = this.POLL_RETRYS;\r
+ this.startTimeout(0);\r
+ // this._tryPreloadAttach();\r
+ },\r
+\r
+ /**\r
+ * Appends an event handler\r
+ *\r
+ * @param {Object} el The html element to assign the \r
+ * event to\r
+ * @param {String} sType The type of event to append\r
+ * @param {Function} fn The method the event invokes\r
+ * @param {Object} oScope An arbitrary object that will be \r
+ * passed as a parameter to the handler\r
+ * @param {boolean} bOverride If true, the obj passed in becomes\r
+ * the execution scope of the listener\r
+ * @return {boolean} True if the action was successful or defered,\r
+ * false if one or more of the elements \r
+ * could not have the event bound to it.\r
+ */\r
+ addListener: function(el, sType, fn, oScope, bOverride) {\r
+\r
+ if (!fn || !fn.call) {\r
+ return false;\r
+ }\r
+\r
+ // The el argument can be an array of elements or element ids.\r
+ if ( this._isValidCollection(el)) {\r
+ var ok = true;\r
+ for (var i=0,len=el.length; i<len; ++i) {\r
+ ok = ( this.on(el[i], \r
+ sType, \r
+ fn, \r
+ oScope, \r
+ bOverride) && ok );\r
+ }\r
+ return ok;\r
+\r
+ } else if (typeof el == "string") {\r
+ var oEl = this.getEl(el);\r
+ // If the el argument is a string, we assume it is \r
+ // actually the id of the element. If the page is loaded\r
+ // we convert el to the actual element, otherwise we \r
+ // defer attaching the event until onload event fires\r
+\r
+ // check to see if we need to delay hooking up the event \r
+ // until after the page loads.\r
+ if (loadComplete && oEl) {\r
+ el = oEl;\r
+ } else {\r
+ // defer adding the event until onload fires\r
+ this.addDelayedListener(el, \r
+ sType, \r
+ fn, \r
+ oScope, \r
+ bOverride);\r
+\r
+ return true;\r
+ }\r
+ }\r
+\r
+ // Element should be an html element or an array if we get \r
+ // here.\r
+ if (!el) {\r
+ return false;\r
+ }\r
+\r
+ // we need to make sure we fire registered unload events \r
+ // prior to automatically unhooking them. So we hang on to \r
+ // these instead of attaching them to the window and fire the\r
+ // handles explicitly during our one unload event.\r
+ if ("unload" == sType && oScope !== this) {\r
+ unloadListeners[unloadListeners.length] =\r
+ [el, sType, fn, oScope, bOverride];\r
+ return true;\r
+ }\r
+\r
+\r
+ // if the user chooses to override the scope, we use the custom\r
+ // object passed in, otherwise the executing scope will be the\r
+ // HTML element that the event is registered on\r
+ var scope = (bOverride) ? oScope : el;\r
+\r
+ // wrap the function so we can return the oScope object when\r
+ // the event fires;\r
+ var wrappedFn = function(e) {\r
+ return fn.call(scope, YAHOO.util.Event.getEvent(e), \r
+ oScope);\r
+ };\r
+\r
+ var li = [el, sType, fn, wrappedFn, scope];\r
+ var index = listeners.length;\r
+ // cache the listener so we can try to automatically unload\r
+ listeners[index] = li;\r
+\r
+ if (this.useLegacyEvent(el, sType)) {\r
+ var legacyIndex = this.getLegacyIndex(el, sType);\r
+ if (legacyIndex == -1) {\r
+\r
+ legacyIndex = legacyEvents.length;\r
+ legacyMap[el.id + sType] = legacyIndex;\r
+\r
+ // cache the signature for the DOM0 event, and \r
+ // include the existing handler for the event, if any\r
+ legacyEvents[legacyIndex] = \r
+ [el, sType, el["on" + sType]];\r
+ legacyHandlers[legacyIndex] = [];\r
+\r
+ el["on" + sType] = \r
+ function(e) {\r
+ YAHOO.util.Event.fireLegacyEvent(\r
+ YAHOO.util.Event.getEvent(e), legacyIndex);\r
+ };\r
+ }\r
+\r
+ // add a reference to the wrapped listener to our custom\r
+ // stack of events\r
+ legacyHandlers[legacyIndex].push(index);\r
+\r
+ // DOM2 Event model\r
+ } else if (el.addEventListener) {\r
+ el.addEventListener(sType, wrappedFn, false);\r
+ // Internet Explorer abstraction\r
+ } else if (el.attachEvent) {\r
+ el.attachEvent("on" + sType, wrappedFn);\r
+ }\r
+\r
+ return true;\r
+ \r
+ },\r
+\r
+ /**\r
+ * Shorthand for YAHOO.util.Event.addListener\r
+ * @type function\r
+ */\r
+ // on: this.addListener,\r
+\r
+ /**\r
+ * When using legacy events, the handler is routed to this object\r
+ * so we can fire our custom listener stack.\r
+ * @private\r
+ */\r
+ fireLegacyEvent: function(e, legacyIndex) {\r
+ var ok = true;\r
+\r
+ var le = legacyHandlers[legacyIndex];\r
+ for (var i=0,len=le.length; i<len; ++i) {\r
+ var index = le[i];\r
+ if (index) {\r
+ var li = listeners[index];\r
+ if ( li && li[this.WFN] ) {\r
+ var scope = li[this.ADJ_SCOPE];\r
+ var ret = li[this.WFN].call(scope, e);\r
+ ok = (ok && ret);\r
+ } else {\r
+ // This listener was removed, so delete it from\r
+ // the array\r
+ delete le[i];\r
+ }\r
+ }\r
+ }\r
+\r
+ return ok;\r
+ },\r
+\r
+ /**\r
+ * Returns the legacy event index that matches the supplied \r
+ * signature\r
+ * @private\r
+ */\r
+ getLegacyIndex: function(el, sType) {\r
+ /*\r
+ for (var i=0,len=legacyEvents.length; i<len; ++i) {\r
+ var le = legacyEvents[i];\r
+ if (le && le[0] === el && le[1] === sType) {\r
+ return i;\r
+ }\r
+ }\r
+ return -1;\r
+ */\r
+\r
+ var key = this.generateId(el) + sType;\r
+ if (typeof legacyMap[key] == "undefined") { \r
+ return -1;\r
+ } else {\r
+ return legacyMap[key];\r
+ }\r
+\r
+ },\r
+\r
+ /**\r
+ * Logic that determines when we should automatically use legacy\r
+ * events instead of DOM2 events.\r
+ * @private\r
+ */\r
+ useLegacyEvent: function(el, sType) {\r
+\r
+ if (!el.addEventListener && !el.attachEvent) {\r
+ return true;\r
+ } else if (this.isSafari) {\r
+ if ("click" == sType || "dblclick" == sType) {\r
+ return true;\r
+ }\r
+ }\r
+\r
+ return false;\r
+ },\r
+ \r
+ /**\r
+ * Removes an event handler\r
+ *\r
+ * @param {Object} el the html element or the id of the element to \r
+ * assign the event to.\r
+ * @param {String} sType the type of event to remove\r
+ * @param {Function} fn the method the event invokes\r
+ * @return {boolean} true if the unbind was successful, false \r
+ * otherwise\r
+ */\r
+ removeListener: function(el, sType, fn, index) {\r
+\r
+ if (!fn || !fn.call) {\r
+ return false;\r
+ }\r
+\r
+ // The el argument can be a string\r
+ if (typeof el == "string") {\r
+ el = this.getEl(el);\r
+ // The el argument can be an array of elements or element ids.\r
+ } else if ( this._isValidCollection(el)) {\r
+ var ok = true;\r
+ for (var i=0,len=el.length; i<len; ++i) {\r
+ ok = ( this.removeListener(el[i], sType, fn) && ok );\r
+ }\r
+ return ok;\r
+ }\r
+\r
+ if ("unload" == sType) {\r
+\r
+ for (i=0, len=unloadListeners.length; i<len; i++) {\r
+ var li = unloadListeners[i];\r
+ if (li && \r
+ li[0] == el && \r
+ li[1] == sType && \r
+ li[2] == fn) {\r
+ delete unloadListeners[i];\r
+ return true;\r
+ }\r
+ }\r
+\r
+ return false;\r
+ }\r
+\r
+ var cacheItem = null;\r
+ \r
+ if ("undefined" == typeof index) {\r
+ index = this._getCacheIndex(el, sType, fn);\r
+ }\r
+\r
+ if (index >= 0) {\r
+ cacheItem = listeners[index];\r
+ }\r
+\r
+ if (!el || !cacheItem) {\r
+ return false;\r
+ }\r
+\r
+\r
+ if (el.removeEventListener) {\r
+ el.removeEventListener(sType, cacheItem[this.WFN], false);\r
+ } else if (el.detachEvent) {\r
+ el.detachEvent("on" + sType, cacheItem[this.WFN]);\r
+ }\r
+\r
+ // removed the wrapped handler\r
+ delete listeners[index][this.WFN];\r
+ delete listeners[index][this.FN];\r
+ delete listeners[index];\r
+\r
+ return true;\r
+\r
+ },\r
+\r
+ /**\r
+ * Returns the event's target element\r
+ * @param {Event} ev the event\r
+ * @param {boolean} resolveTextNode when set to true the target's\r
+ * parent will be returned if the target is a \r
+ * text node\r
+ * @return {HTMLElement} the event's target\r
+ */\r
+ getTarget: function(ev, resolveTextNode) {\r
+ var t = ev.target || ev.srcElement;\r
+\r
+ if (resolveTextNode && t && "#text" == t.nodeName) {\r
+ return t.parentNode;\r
+ } else {\r
+ return t;\r
+ }\r
+ },\r
+\r
+ /**\r
+ * Returns the event's pageX\r
+ * @param {Event} ev the event\r
+ * @return {int} the event's pageX\r
+ */\r
+ getPageX: function(ev) {\r
+ var x = ev.pageX;\r
+ if (!x && 0 !== x) {\r
+ x = ev.clientX || 0;\r
+\r
+ if ( this.isIE ) {\r
+ x += this._getScrollLeft();\r
+ }\r
+ }\r
+\r
+ return x;\r
+ },\r
+\r
+ /**\r
+ * Returns the event's pageY\r
+ * @param {Event} ev the event\r
+ * @return {int} the event's pageY\r
+ */\r
+ getPageY: function(ev) {\r
+ var y = ev.pageY;\r
+ if (!y && 0 !== y) {\r
+ y = ev.clientY || 0;\r
+\r
+ if ( this.isIE ) {\r
+ y += this._getScrollTop();\r
+ }\r
+ }\r
+\r
+ return y;\r
+ },\r
+\r
+ /**\r
+ * Returns the pageX and pageY properties as an indexed array.\r
+ * @type int[]\r
+ */\r
+ getXY: function(ev) {\r
+ return [this.getPageX(ev), this.getPageY(ev)];\r
+ },\r
+\r
+ /**\r
+ * Returns the event's related target \r
+ * @param {Event} ev the event\r
+ * @return {HTMLElement} the event's relatedTarget\r
+ */\r
+ getRelatedTarget: function(ev) {\r
+ var t = ev.relatedTarget;\r
+ if (!t) {\r
+ if (ev.type == "mouseout") {\r
+ t = ev.toElement;\r
+ } else if (ev.type == "mouseover") {\r
+ t = ev.fromElement;\r
+ }\r
+ }\r
+\r
+ return t;\r
+ },\r
+\r
+ /**\r
+ * Returns the time of the event. If the time is not included, the\r
+ * event is modified using the current time.\r
+ * @param {Event} ev the event\r
+ * @return {Date} the time of the event\r
+ */\r
+ getTime: function(ev) {\r
+ if (!ev.time) {\r
+ var t = new Date().getTime();\r
+ try {\r
+ ev.time = t;\r
+ } catch(e) { \r
+ // can't set the time property \r
+ return t;\r
+ }\r
+ }\r
+\r
+ return ev.time;\r
+ },\r
+\r
+ /**\r
+ * Convenience method for stopPropagation + preventDefault\r
+ * @param {Event} ev the event\r
+ */\r
+ stopEvent: function(ev) {\r
+ this.stopPropagation(ev);\r
+ this.preventDefault(ev);\r
+ },\r
+\r
+ /**\r
+ * Stops event propagation\r
+ * @param {Event} ev the event\r
+ */\r
+ stopPropagation: function(ev) {\r
+ if (ev.stopPropagation) {\r
+ ev.stopPropagation();\r
+ } else {\r
+ ev.cancelBubble = true;\r
+ }\r
+ },\r
+\r
+ /**\r
+ * Prevents the default behavior of the event\r
+ * @param {Event} ev the event\r
+ */\r
+ preventDefault: function(ev) {\r
+ if (ev.preventDefault) {\r
+ ev.preventDefault();\r
+ } else {\r
+ ev.returnValue = false;\r
+ }\r
+ },\r
+ \r
+ /**\r
+ * Finds the event in the window object, the caller's arguments, or\r
+ * in the arguments of another method in the callstack. This is\r
+ * executed automatically for events registered through the event\r
+ * manager, so the implementer should not normally need to execute\r
+ * this function at all.\r
+ * @param {Event} the event parameter from the handler\r
+ * @return {Event} the event \r
+ */\r
+ getEvent: function(e) {\r
+ var ev = e || window.event;\r
+\r
+ if (!ev) {\r
+ var c = this.getEvent.caller;\r
+ while (c) {\r
+ ev = c.arguments[0];\r
+ if (ev && Event == ev.constructor) {\r
+ break;\r
+ }\r
+ c = c.caller;\r
+ }\r
+ }\r
+\r
+ return ev;\r
+ },\r
+\r
+ /**\r
+ * Returns the charcode for an event\r
+ * @param {Event} ev the event\r
+ * @return {int} the event's charCode\r
+ */\r
+ getCharCode: function(ev) {\r
+ return ev.charCode || ((ev.type == "keypress") ? ev.keyCode : 0);\r
+ },\r
+\r
+ /**\r
+ * @private\r
+ * Locating the saved event handler data by function ref\r
+ */\r
+ _getCacheIndex: function(el, sType, fn) {\r
+ for (var i=0,len=listeners.length; i<len; ++i) {\r
+ var li = listeners[i];\r
+ if ( li && \r
+ li[this.FN] == fn && \r
+ li[this.EL] == el && \r
+ li[this.TYPE] == sType ) {\r
+ return i;\r
+ }\r
+ }\r
+\r
+ return -1;\r
+ },\r
+\r
+ /**\r
+ * Generates an unique ID for the element if it does not already \r
+ * have one.\r
+ * @param el the element\r
+ * @return {string} the id of the element\r
+ */\r
+ generateId: function(el) {\r
+ var id = el.id;\r
+\r
+ if (!id) {\r
+ id = "yuievtautoid-" + (counter++);\r
+ el.id = id;\r
+ }\r
+\r
+ return id;\r
+ },\r
+\r
+ /**\r
+ * We want to be able to use getElementsByTagName as a collection\r
+ * to attach a group of events to. Unfortunately, different \r
+ * browsers return different types of collections. This function\r
+ * tests to determine if the object is array-like. It will also \r
+ * fail if the object is an array, but is empty.\r
+ * @param o the object to test\r
+ * @return {boolean} true if the object is array-like and populated\r
+ * @private\r
+ */\r
+ _isValidCollection: function(o) {\r
+\r
+ return ( o && // o is something\r
+ o.length && // o is indexed\r
+ typeof o != "string" && // o is not a string\r
+ !o.tagName && // o is not an HTML element\r
+ !o.alert && // o is not a window\r
+ typeof o[0] != "undefined" );\r
+\r
+ },\r
+\r
+ /**\r
+ * @private\r
+ * DOM element cache\r
+ */\r
+ elCache: {},\r
+\r
+ /**\r
+ * We cache elements bound by id because when the unload event \r
+ * fires, we can no longer use document.getElementById\r
+ * @private\r
+ */\r
+ getEl: function(id) {\r
+ return document.getElementById(id);\r
+ },\r
+\r
+ /**\r
+ * Clears the element cache\r
+ * @deprecated\r
+ * @private\r
+ */\r
+ clearCache: function() { },\r
+\r
+ /**\r
+ * Called by CustomEvent instances to provide a handle to the \r
+ * event * that can be removed later on. Should be package \r
+ * protected.\r
+ * @private\r
+ */\r
+ regCE: function(ce) {\r
+ customEvents.push(ce);\r
+ },\r
+\r
+ /**\r
+ * @private\r
+ * hook up any deferred listeners\r
+ */\r
+ _load: function(e) {\r
+ loadComplete = true;\r
+ },\r
+\r
+ /**\r
+ * Polling function that runs before the onload event fires, \r
+ * attempting * to attach to DOM Nodes as soon as they are \r
+ * available\r
+ * @private\r
+ */\r
+ _tryPreloadAttach: function() {\r
+\r
+ if (this.locked) {\r
+ return false;\r
+ }\r
+\r
+ this.locked = true;\r
+\r
+\r
+ // keep trying until after the page is loaded. We need to \r
+ // check the page load state prior to trying to bind the \r
+ // elements so that we can be certain all elements have been \r
+ // tested appropriately\r
+ var tryAgain = !loadComplete;\r
+ if (!tryAgain) {\r
+ tryAgain = (retryCount > 0);\r
+ }\r
+\r
+ // Delayed listeners\r
+ var stillDelayed = [];\r
+\r
+ for (var i=0,len=delayedListeners.length; i<len; ++i) {\r
+ var d = delayedListeners[i];\r
+ // There may be a race condition here, so we need to \r
+ // verify the array element is usable.\r
+ if (d) {\r
+\r
+ // el will be null if document.getElementById did not\r
+ // work\r
+ var el = this.getEl(d[this.EL]);\r
+\r
+ if (el) {\r
+ this.on(el, d[this.TYPE], d[this.FN], \r
+ d[this.SCOPE], d[this.ADJ_SCOPE]);\r
+ delete delayedListeners[i];\r
+ } else {\r
+ stillDelayed.push(d);\r
+ }\r
+ }\r
+ }\r
+\r
+ delayedListeners = stillDelayed;\r
+\r
+ // onAvailable\r
+ notAvail = [];\r
+ for (i=0,len=onAvailStack.length; i<len ; ++i) {\r
+ var item = onAvailStack[i];\r
+ if (item) {\r
+ el = this.getEl(item.id);\r
+\r
+ if (el) {\r
+ var scope = (item.override) ? item.obj : el;\r
+ item.fn.call(scope, item.obj);\r
+ delete onAvailStack[i];\r
+ } else {\r
+ notAvail.push(item);\r
+ }\r
+ }\r
+ }\r
+\r
+ retryCount = (stillDelayed.length === 0 && \r
+ notAvail.length === 0) ? 0 : retryCount - 1;\r
+\r
+ if (tryAgain) {\r
+ this.startTimeout();\r
+ }\r
+\r
+ this.locked = false;\r
+\r
+ },\r
+\r
+ /**\r
+ * Removes all listeners registered by pe.event. Called \r
+ * automatically during the unload event.\r
+ * @private\r
+ */\r
+ _unload: function(e, me) {\r
+ for (var i=0,len=unloadListeners.length; i<len; ++i) {\r
+ var l = unloadListeners[i];\r
+ if (l) {\r
+ var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;\r
+ l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );\r
+ }\r
+ }\r
+\r
+ if (listeners && listeners.length > 0) {\r
+ for (i=0,len=listeners.length; i<len ; ++i) {\r
+ l = listeners[i];\r
+ if (l) {\r
+ this.removeListener(l[this.EL], l[this.TYPE], \r
+ l[this.FN], i);\r
+ }\r
+ }\r
+\r
+ this.clearCache();\r
+ }\r
+\r
+ for (i=0,len=customEvents.length; i<len; ++i) {\r
+ customEvents[i].unsubscribeAll();\r
+ delete customEvents[i];\r
+ }\r
+\r
+ for (i=0,len=legacyEvents.length; i<len; ++i) {\r
+ // dereference the element\r
+ delete legacyEvents[i][0];\r
+ // delete the array item\r
+ delete legacyEvents[i];\r
+ }\r
+ },\r
+\r
+ /**\r
+ * Returns scrollLeft\r
+ * @private\r
+ */\r
+ _getScrollLeft: function() {\r
+ return this._getScroll()[1];\r
+ },\r
+\r
+ /**\r
+ * Returns scrollTop\r
+ * @private\r
+ */\r
+ _getScrollTop: function() {\r
+ return this._getScroll()[0];\r
+ },\r
+\r
+ /**\r
+ * Returns the scrollTop and scrollLeft. Used to calculate the \r
+ * pageX and pageY in Internet Explorer\r
+ * @private\r
+ */\r
+ _getScroll: function() {\r
+ var dd = document.documentElement; db = document.body;\r
+ if (dd && dd.scrollTop) {\r
+ return [dd.scrollTop, dd.scrollLeft];\r
+ } else if (db) {\r
+ return [db.scrollTop, db.scrollLeft];\r
+ } else {\r
+ return [0, 0];\r
+ }\r
+ }\r
+ };\r
+ } ();\r
+\r
+ /**\r
+ * @private\r
+ */\r
+ YAHOO.util.Event.on = YAHOO.util.Event.addListener;\r
+\r
+ if (document && document.body) {\r
+ YAHOO.util.Event._load();\r
+ } else {\r
+ YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load, \r
+ YAHOO.util.Event, true);\r
+ }\r
+\r
+ YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload, \r
+ YAHOO.util.Event, true);\r
+\r
+ YAHOO.util.Event._tryPreloadAttach();\r
+\r
+}\r
+\r
--- /dev/null
+/* \r
+Copyright (c) 2006, Yahoo! Inc. All rights reserved. \r
+Code licensed under the BSD License: \r
+http://developer.yahoo.net/yui/license.txt \r
+version: 0.10.0 \r
+*/ \r
+\r
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */\r
+\r
+/**\r
+ * The Yahoo global namespace\r
+ * @constructor\r
+ */\r
+var YAHOO = window.YAHOO || {};\r
+\r
+/**\r
+ * Returns the namespace specified and creates it if it doesn't exist\r
+ *\r
+ * YAHOO.namespace("property.package");\r
+ * YAHOO.namespace("YAHOO.property.package");\r
+ *\r
+ * Either of the above would create YAHOO.property, then\r
+ * YAHOO.property.package\r
+ *\r
+ * @param {String} sNameSpace String representation of the desired \r
+ * namespace\r
+ * @return {Object} A reference to the namespace object\r
+ */\r
+YAHOO.namespace = function( sNameSpace ) {\r
+\r
+ if (!sNameSpace || !sNameSpace.length) {\r
+ return null;\r
+ }\r
+\r
+ var levels = sNameSpace.split(".");\r
+\r
+ var currentNS = YAHOO;\r
+\r
+ // YAHOO is implied, so it is ignored if it is included\r
+ for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {\r
+ currentNS[levels[i]] = currentNS[levels[i]] || {};\r
+ currentNS = currentNS[levels[i]];\r
+ }\r
+\r
+ return currentNS;\r
+};\r
+\r
+/**\r
+ * Global log method.\r
+ */\r
+YAHOO.log = function(sMsg,sCategory) {\r
+ if(YAHOO.widget.Logger) {\r
+ YAHOO.widget.Logger.log(null, sMsg, sCategory);\r
+ } else {\r
+ return false;\r
+ }\r
+};\r
+\r
+YAHOO.namespace("util");\r
+YAHOO.namespace("widget");\r
+YAHOO.namespace("example");\r
(compile) "; " ,
] each ;
-: compile ( ast -- string )
+: fjsc-compile ( ast -- string )
[
[ (compile) ] { } make [ write ] each
] string-out ;