diff options
Diffstat (limited to 'framework/Web/Javascripts/js/debug/ajax.js')
-rw-r--r-- | framework/Web/Javascripts/js/debug/ajax.js | 2605 |
1 files changed, 935 insertions, 1670 deletions
diff --git a/framework/Web/Javascripts/js/debug/ajax.js b/framework/Web/Javascripts/js/debug/ajax.js index 9a61cabb..61881bf9 100644 --- a/framework/Web/Javascripts/js/debug/ajax.js +++ b/framework/Web/Javascripts/js/debug/ajax.js @@ -116,7 +116,7 @@ Ajax.Request.prototype = Object.extend(new Ajax.Base(), { var requestHeaders = ['X-Requested-With', 'XMLHttpRequest', 'X-Prototype-Version', Prototype.Version, - 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; + 'Accept', 'text/javascript, text/html, application/xml, text/xml']; if (this.options.method == 'post') { requestHeaders.push('Content-type', this.options.contentType); @@ -287,432 +287,540 @@ Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { /**
- * Prado AJAX service. The default service provider is JPSpan.
+ * Override Prototype's response implementation.
*/
-Prado.AJAX = { Service : 'Prototype' };
-
-/**
- * Parse and execute javascript embedded in html.
- */
-Prado.AJAX.EvalScript = function(output)
+Object.extend(Ajax.Request.prototype,
{
-
- var match = new RegExp(Ajax.Updater.ScriptFragment, 'img');
- var scripts = output.match(match);
- if (scripts)
+ /**
+ * Customize the response, dispatch onXXX response code events, and
+ * tries to execute response actions (javascript statements).
+ */
+ respondToReadyState : function(readyState)
{
- match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
- setTimeout((function()
- {
- for (var i = 0; i < scripts.length; i++)
- eval(scripts[i].match(match)[1]);
- }).bind(this), 50);
- }
-}
-
+ var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.getHeaderData(Prado.CallbackRequest.DATA_HEADER);
+
+ if (event == 'Complete')
+ {
+ try
+ {
+ Prado.CallbackRequest.updatePageState(this,transport);
+ Ajax.Responders.dispatch('on' + transport.status, this, transport, json);
+ Prado.CallbackRequest.dispatchActions(transport,this.getHeaderData(Prado.CallbackRequest.ACTION_HEADER));
+
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(this, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(this, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+ if (event == 'Complete')
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
-/**
- * AJAX service request using Prototype's AJAX request class.
- */
-Prado.AJAX.Request = Class.create();
-Prado.AJAX.Request.prototype = Object.extend(Ajax.Request.prototype,
-{
/**
- * Evaluate the respond JSON data, override parent implementing.
- * If default eval fails, try parsing the JSON data (slower).
+ * Gets header data assuming JSON encoding.
+ * @param string header name
+ * @return object header data as javascript structures.
*/
- evalJSON: function()
+ getHeaderData : function(name)
{
try
{
- var json = this.transport.getResponseHeader('X-JSON'), object;
- object = eval(json);
- return object;
+ var json = this.header(name);
+ return eval('(' + json + ')');
}
catch (e)
{
- if(isString(json))
- {
- return Prado.AJAX.JSON.parse(json);
- }
+ if(typeof(json) == "string")
+ return Prado.CallbackRequest.decode(json);
}
- },
-
- respondToReadyState: function(readyState) {
- var event = Ajax.Request.Events[readyState];
- var transport = this.transport, json = this.evalJSON();
-
-
- if(event == 'Complete' && transport.status)
- Ajax.Responders.dispatch('on' + transport.status, this, transport, json);
-
- (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
- Ajax.Responders.dispatch('on' + event, this, transport, json);
-
- if (event == 'Complete')
- (this.options['on' + this.transport.status]
- || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
- || Prototype.emptyFunction)(transport, json);
-
-
- /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
- if (event == 'Complete')
- this.transport.onreadystatechange = Prototype.emptyFunction;
- }
-
+ }
});
-Prado.AJAX.Error = function(e, code)
-{
- e.name = 'Prado.AJAX.Error';
- e.code = code;
- return e;
-}
+/**
+ * Prado Callback client-side request handler.
+ */
+Prado.CallbackRequest = Class.create();
/**
- * Post data builder, serialize the data using JSON.
+ * Static definitions.
*/
-Prado.AJAX.RequestBuilder = Class.create();
-Prado.AJAX.RequestBuilder.prototype =
+Object.extend(Prado.CallbackRequest,
{
- initialize : function()
+ /**
+ * Callback request target POST field name.
+ */
+ FIELD_CALLBACK_TARGET : 'PRADO_CALLBACK_TARGET',
+ /**
+ * Callback request parameter POST field name.
+ */
+ FIELD_CALLBACK_PARAMETER : 'PRADO_CALLBACK_PARAMETER',
+ /**
+ * Callback request page state field name,
+ */
+ FIELD_CALLBACK_PAGESTATE : 'PRADO_PAGESTATE',
+
+ FIELD_POSTBACK_TARGET : 'PRADO_POSTBACK_TARGET',
+
+ FIELD_POSTBACK_PARAMETER : 'PRADO_POSTBACK_PARAMETER',
+
+ /**
+ * List of form fields that will be collected during callback.
+ */
+ PostDataLoaders : [],
+ /**
+ * Response data header name.
+ */
+ DATA_HEADER : 'X-PRADO-DATA',
+ /**
+ * Response javascript execution statement header name.
+ */
+ ACTION_HEADER : 'X-PRADO-ACTIONS',
+ /**
+ * Response errors/exceptions header name.
+ */
+ ERROR_HEADER : 'X-PRADO-ERROR',
+ /**
+ * Page state header name.
+ */
+ PAGESTATE_HEADER : 'X-PRADO-PAGESTATE',
+ /**
+ * Current requests in progress.
+ */
+ requestInProgress : null,
+
+ /**
+ * Add ids of inputs element to post in the request.
+ */
+ addPostLoaders : function(ids)
{
- this.body = '';
- this.data = [];
+ this.PostDataLoaders = this.PostDataLoaders.concat(ids);
+ list = [];
+ this.PostDataLoaders.each(function(id)
+ {
+ if(list.indexOf(id) < 0)
+ list.push(id);
+ });
+ this.PostDataLoaders = list;
},
- encode : function(data)
+
+ /**
+ * Dispatch callback response actions.
+ */
+ dispatchActions : function(transport,actions)
{
- return Prado.AJAX.JSON.stringify(data);
+ if(actions && actions.length > 0)
+ actions.each(this.__run.bind(this,transport));
},
- build : function(data)
+
+ /**
+ * Prase and evaluate a Callback clien-side action
+ */
+ __run : function(transport, command)
{
- var sep = '';
- for ( var argName in data)
+ for(var method in command)
{
- if(isFunction(data[argName])) continue;
- try
+ try
{
- this.body += sep + argName + '=';
- this.body += encodeURIComponent(this.encode(data[argName]));
- } catch (e) {
- throw Prado.AJAX.Error(e, 1006);
- }
- sep = '&';
- }
- },
+ method.toFunction().apply(this,command[method].concat(transport));
+ }
+ catch(e)
+ {
+ if(typeof(Logger) != "undefined")
+ Prado.CallbackRequest.Exception.onException(null,e);
+ }
+ }
+ },
- getAll : function()
+ /**
+ * Respond to Prado Callback request exceptions.
+ */
+ Exception :
{
- this.build(this.data);
- return this.body;
- }
-}
-
+ /**
+ * Server returns 500 exception. Just log it.
+ */
+ "on500" : function(request, transport, data)
+ {
+ var e = request.getHeaderData(Prado.CallbackRequest.ERROR_HEADER);
+ Logger.error("Callback Server Error "+e.code, this.formatException(e));
+ },
+
+ /**
+ * Callback OnComplete event,logs reponse and data to console.
+ */
+ 'on200' : function(request, transport, data)
+ {
+ if(transport.status < 500)
+ {
+ var msg = 'HTTP '+transport.status+" with response : \n";
+ msg += transport.responseText + "\n";
+ msg += "Data : \n"+inspect(data)+"\n";
+ msg += "Actions : \n";
+ data = request.getHeaderData(Prado.CallbackRequest.ACTION_HEADER);
+ if(data && data.length > 0)
+ {
+ data.each(function(action)
+ {
+ msg += inspect(action)+"\n";
+ });
+ }
+ Logger.warn(msg);
+ }
+ },
-Prado.AJAX.RemoteObject = function(){};
+ /**
+ * Uncaught exceptions during callback response.
+ */
+ onException : function(request,e)
+ {
+ msg = "";
+ $H(e).each(function(item)
+ {
+ msg += item.key+": "+item.value+"\n";
+ })
+ Logger.error('Uncaught Callback Client Exception:', msg);
+ },
+
+ /**
+ * Formats the exception message for display in console.
+ */
+ formatException : function(e)
+ {
+ var msg = e.type + " with message \""+e.message+"\"";
+ msg += " in "+e.file+"("+e.line+")\n";
+ msg += "Stack trace:\n";
+ var trace = e.trace;
+ for(var i = 0; i<trace.length; i++)
+ {
+ msg += " #"+i+" "+trace[i].file;
+ msg += "("+trace[i].line+"): ";
+ msg += trace[i]["class"]+"->"+trace[i]["function"]+"()"+"\n";
+ }
+ msg += e.version+" "+e.time+"\n";
+ return msg;
+ }
+ },
-/**
- * AJAX service request for Prado RemoteObjects
- */
-Prado.AJAX.RemoteObject.Request = Class.create();
-Prado.AJAX.RemoteObject.Request.prototype = Object.extend(Prado.AJAX.Request.prototype,
-{
/**
- * Initialize the RemoteObject Request, overrides parent
- * implementation by delaying the request to invokeRemoteObject.
+ * @return string JSON encoded data.
*/
- initialize : function(options)
+ encode : function(data)
{
- this.transport = Ajax.getTransport();
- this.setOptions(options);
- this.post = new Prado.AJAX.RequestBuilder();
+ return Prado.JSON.stringify(data);
},
/**
- * Call the remote object,
- * @param string the remote server url
- * @param array additional arguments
+ * @return mixed javascript data decoded from string using JSON decoding.
*/
- invokeRemoteObject : function(url, args)
+ decode : function(data)
{
- this.initParameters(args);
- this.options.postBody = this.post.getAll();
- this.request(url);
+ if(typeof(data) == "string" && data.trim().length > 0)
+ return Prado.JSON.parse(data);
+ else
+ return null;
},
/**
- * Set the additional arguments as post data with key '__parameters'
+ * Dispatch a priority request, it will call abortRequestInProgress first.
*/
- initParameters : function(args)
+ dispatchPriorityRequest : function(callback)
{
- this.post.data['__parameters'] = [];
- for(var i = 0; i<args.length; i++)
- this.post.data['__parameters'][i] = args[i];
- }
-});
+ //Logger.info("priority request "+callback.id)
+ this.abortRequestInProgress();
-/**
- * Base proxy class for Prado RemoteObjects via AJAX.
- * e.g.
- * <code>
- * var TestObject1 = Class.create();
- * TestObject1.prototype = Object.extend(new Prado.AJAX.RemoteObject(),
- * {
- * initialize : function(handlers, options)
- * {
- * this.__serverurl = 'http://127.0.0.1/.....';
- * this.baseInitialize(handlers, options);
- * }
- *
- * method1 : function()
- * {
- * return this.__call(this.__serverurl, 'method1', arguments);
- * }
- * });
- *</code>
- * And client usage,
- * <code>
- * var test1 = new TestObject1(); //create new remote object
- * test1.method1(); //call the method, no onComplete hook
- *
- * var onComplete = { method1 : function(result){ alert(result) } };
- * //create new remote object with onComplete callback
- * var test2 = new TestObject1(onComplete);
- * test2.method1(); //call it, on success, onComplete's method1 is called.
- * </code>
- */
-Prado.AJAX.RemoteObject.prototype =
-{
- baseInitialize : function(handlers, options)
- {
- this.__handlers = handlers || {};
- this.__service = new Prado.AJAX.RemoteObject.Request(options);
- },
+ callback.request = new Ajax.Request(callback.url, callback.options);
+ callback.timeout = setTimeout(function()
+ {
+ // Logger.warn("priority timeout");
+ Prado.CallbackRequest.abortRequestInProgress();
+ },callback.options.RequestTimeOut);
- __call : function(url, method, args)
- {
- this.__service.options.onSuccess = this.__onSuccess.bind(this);
- this.__callback = method;
- return this.__service.invokeRemoteObject(url+"/"+method, args);
+ this.requestInProgress = callback;
+ return true;
+ //Logger.info("dispatched "+this.requestInProgress)
},
- __onSuccess : function(transport, json)
- {
- if(this.__handlers[this.__callback])
- this.__handlers[this.__callback](json, transport.responseText);
- }
-};
-
-/**
- * Respond to Prado AJAX request exceptions.
- */
-Prado.AJAX.Exception =
-{
/**
- * Server returns 505 exception. Just log it.
+ * Dispatch a normal request, no timeouts or aborting of requests.
*/
- "on505" : function(request, transport, e)
+ dispatchNormalRequest : function(callback)
{
- var msg = 'HTTP '+transport.status+" with response";
- Logger.error(msg, transport.responseText);
- Logger.exception(e);
+ // Logger.info("dispatching normal request");
+ new Ajax.Request(callback.url, callback.options);
+ return true;
},
- onComplete : function(request, transport, e)
+ /**
+ * Abort the current priority request in progress.
+ */
+ abortRequestInProgress : function()
{
- if(transport.status != 505)
+ inProgress = Prado.CallbackRequest.requestInProgress;
+ //Logger.info("aborting ... "+inProgress);
+ if(inProgress)
{
- var msg = 'HTTP '+transport.status+" with response : \n";
- msg += transport.responseText + "\n";
- msg += "Data : \n"+inspect(e);
- Logger.warn(msg);
+ // Logger.warn("aborted "+inProgress.id)
+ inProgress.request.transport.abort();
+ clearTimeout(inProgress.timeout);
+ Prado.CallbackRequest.requestInProgress = null;
+ return true;
}
+ return false;
},
- format : function(e)
+ /**
+ * Updates the page state. It will update only if EnablePageStateUpdate and
+ * HasPriority options are both true.
+ */
+ updatePageState : function(request, transport)
{
- var msg = e.type + " with message \""+e.message+"\"";
- msg += " in "+e.file+"("+e.line+")\n";
- msg += "Stack trace:\n";
- var trace = e.trace;
- for(var i = 0; i<trace.length; i++)
+ pagestate = $(this.FIELD_CALLBACK_PAGESTATE);
+ if(request.options.EnablePageStateUpdate && request.options.HasPriority && pagestate)
{
- msg += " #"+i+" "+trace[i].file;
- msg += "("+trace[i].line+"): ";
- msg += trace[i]["class"]+"->"+trace[i]["function"]+"()"+"\n";
+ data = request.header(this.PAGESTATE_HEADER);
+ if(typeof(data) == "string" && data.length > 0)
+ pagestate.value = data;
+ else
+ {
+ if(typeof(Logger) != "undefined")
+ Logger.debug("Bad page state:"+data);
+ }
}
- return msg;
- },
-
- logException : function(e)
- {
- var msg = Prado.AJAX.Exception.format(e);
- Logger.error("Server Error "+e.code, msg);
}
-}
+})
+
+/**
+ * Automatically aborts the current request when a priority request has returned.
+ */
+Ajax.Responders.register({onComplete : function(request)
+{
+ if(request.options.HasPriority)
+ Prado.CallbackRequest.abortRequestInProgress();
+}});
//Add HTTP exception respones when logger is enabled.
Event.OnLoad(function()
{
if(typeof Logger != "undefined")
- {
- Logger.exception = Prado.AJAX.Exception.logException;
- Ajax.Responders.register(Prado.AJAX.Exception);
- }
+ Ajax.Responders.register(Prado.CallbackRequest.Exception);
});
/**
- * Prado Callback service that provides component intergration,
- * viewstate (read only), and automatic form data serialization.
- * Usage: <code>new Prado.AJAX.Callback('MyPage.MyComponentID.raiseCallbackEvent', options)</code>
- * These classes should be called by the components developers.
- * For inline callback service, use <t>Prado.Callback(callbackID, params)</t>.
+ * Create and prepare a new callback request.
+ * Call the dispatch() method to start the callback request.
+ * <code>
+ * request = new Prado.CallbackRequest(UniqueID, callback);
+ * request.dispatch();
+ * </code>
*/
-Prado.AJAX.Callback = Class.create();
-Prado.AJAX.Callback.prototype = Object.extend(new Prado.AJAX.RemoteObject(),
+Prado.CallbackRequest.prototype =
{
+ /**
+ * Callback URL, same url as the current page.
+ */
+ url : window.location.href,
/**
- * Create and request a new Prado callback service.
- * @param string|element the callback ID, must be of the form, <t>ClassName.ComponentID.MethodName</t>
- * @param list options with list key onCallbackReturn, and more.
- *
+ * Callback options, including onXXX events.
*/
- initialize : function(ID, options)
- {
- if(!isString(ID) && typeof(ID.id) != "undefined")
- ID = ID.id;
- if(!isString(ID))
- throw new Error('A Control ID must be specified');
- this.baseInitialize(this, options);
- this.options = options || [];
- this.__service.post.data['__ID'] = ID;
- this.requestCallback();
- },
+ options : { },
/**
- * Get form data for components that implements IPostBackHandler.
+ * Callback target ID. E.g. $control->getUniqueID();
*/
- collectPostData : function()
+ id : null,
+
+ /**
+ * Current callback request.
+ */
+ request : null,
+
+ /**
+ * Prepare and inititate a callback request.
+ */
+ initialize : function(id, options)
{
- var IDs = Prado.AJAX.Callback.IDs;
- this.__service.post.data['__data'] = {};
- for(var i = 0; i<IDs.length; i++)
+ this.id = id;
+ this.options = Object.extend(
{
- var id = IDs[i];
- if(id.indexOf("[]") > -1)
- this.__service.post.data['__data'][id] =
- this.collectArrayPostData(id);
- else if(isObject($(id)))
- this.__service.post.data['__data'][id] = $F(id);
- }
+ RequestTimeOut : 30000, // 30 second timeout.
+ EnablePageStateUpdate : true,
+ HasPriority : true,
+ CausesValidation : true,
+ ValidationGroup : null,
+ PostInputs : true
+ }, options || {});
},
- collectArrayPostData : function(name)
+ /**
+ * Sets the request parameter
+ * @param {Object} parameter value
+ */
+ setParameter : function(value)
{
- var elements = document.getElementsByName(name);
- var data = [];
- $A(elements).each(function(el)
- {
- if($F(el)) data.push($F(el));
- });
- return data;
+ this.options['params'] = value;
},
/**
- * Prepares and calls the AJAX request.
- * Collects the data from components that implements IPostBackHandler
- * and the viewstate as part of the request payload.
+ * @return {Object} request paramater value.
*/
- requestCallback : function()
+ getParameter : function()
{
- this.collectPostData();
- if(Prado.AJAX.Validate(this.options))
- return this.__call(Prado.AJAX.Callback.Server, 'handleCallback', this.options.params);
+ return this.options['params'];
},
/**
- * On callback request return, call the onSuccess function.
+ * Sets the callback request timeout.
+ * @param {integer} timeout in milliseconds
*/
- handleCallback : function(result, output)
+ setRequestTimeOut : function(timeout)
{
- if(typeof(result) != "undefined" && !isNull(result))
- {
- this.options.onSuccess(result['data'], output);
- if(result['actions'])
- result.actions.each(Prado.AJAX.Callback.Action.__run);
- }
- }
-});
+ this.options['RequestTimeOut'] = timeout;
+ },
-/**
- * Prase and evaluate Callback clien-side actions.
- */
-Prado.AJAX.Callback.Action =
-{
- __run : function(command)
+ /**
+ * @return {integer} request timeout in milliseconds
+ */
+ getRequestTimeOut : function()
{
- for(var name in command)
- {
- //first parameter must be a valid element or begins with '@'
- if(command[name][0] && ($(command[name][0]) || command[name][0].indexOf("[]") > -1))
- {
- name.toFunction().apply(this,command[name]);
- }
- }
- }
-};
+ return this.options['RequestTimeOut'];
+ },
+
+ /**
+ * Set true to enable validation on callback dispatch.
+ * @param {boolean} true to validate
+ */
+ setCausesValidation : function(validate)
+ {
+ this.options['CausesValidation'] = validate;
+ },
+ /**
+ * @return {boolean} validate on request dispatch
+ */
+ getCausesValidation : function()
+ {
+ return this.options['CausesValidation'];
+ },
-/**
- * Returns false if validation required and validates to false,
- * returns true otherwise.
- * @return boolean true if validation passes.
- */
-Prado.AJAX.Validate = function(options)
-{
- if(options.CausesValidation)
+ /**
+ * Sets the validation group to validate during request dispatch.
+ * @param {string} validation group name
+ */
+ setValidationGroup : function(group)
{
- if(options.ValidatorGroup)
- return Prado.Validation.ValidateValidatorGroup(options.ValidatorGroup);
- else if(options.ValidationGroup)
- return Prado.Validation.ValidateValidationGroup(options.ValidationGroup);
- else
- return Prado.Validation.ValidateNonGroup(options.ValidationForm);
- }
- else
- return true;
-};
+ this.options['ValidationGroup'] = group;
+ },
+
+ /**
+ * @return {string} validation group name.
+ */
+ getValidationGroup : function()
+ {
+ return this.options['ValidationGroup'];
+ },
+
+ /**
+ * Dispatch the callback request.
+ */
+ dispatch : function()
+ {
+ //override parameter and postBody options.
+ Object.extend(this.options,
+ {
+ postBody : this._getPostData(),
+ parameters : ''
+ });
+ if(this.options.CausesValidation && typeof(Prado.Validation) != "undefined")
+ {
+ var form = this.options.Form || Prado.Validation.getForm();
+ if(Prado.Validation.validate(form,this.options.ValidationGroup,this) == false)
+ return false;
+ }
-//Available callback service
-Prado.AJAX.Callback.Server = '';
+ if(this.options.HasPriority)
+ return Prado.CallbackRequest.dispatchPriorityRequest(this);
+ else
+ return Prado.CallbackRequest.dispatchNormalRequest(this);
+ },
-//List of IDs that implements IPostBackHandler
-Prado.AJAX.Callback.IDs = [];
+ /**
+ * Collects the form inputs, encode the parameters, and sets the callback
+ * target id. The resulting string is the request content body.
+ * @return string request body content containing post data.
+ */
+ _getPostData : function()
+ {
+ var data = {};
+ var callback = Prado.CallbackRequest;
+ if(this.options.PostInputs != false)
+ {
+ callback.PostDataLoaders.each(function(name)
+ {
+ $A(document.getElementsByName(name)).each(function(element)
+ {
+ //IE will try to get elements with ID == name as well.
+ if(element.type && element.name == name)
+ {
+ value = $F(element);
+ if(typeof(value) != "undefined")
+ data[name] = value;
+ }
+ })
+ })
+ }
+ if(typeof(this.options.params) != "undefined")
+ data[callback.FIELD_CALLBACK_PARAMETER] = callback.encode(this.options.params);
+ var pageState = $F(callback.FIELD_CALLBACK_PAGESTATE);
+ if(typeof(pageState) != "undefined")
+ data[callback.FIELD_CALLBACK_PAGESTATE] = pageState;
+ data[callback.FIELD_CALLBACK_TARGET] = this.id;
+ if(this.options.EventTarget)
+ data[callback.FIELD_POSTBACK_TARGET] = this.options.EventTarget;
+ if(this.options.EventParameter)
+ data[callback.FIELD_POSTBACK_PARAMETER] = this.options.EventParameter;
+ return $H(data).toQueryString();
+ }
+}
/**
- * Simple AJAX callback interface, suitable for inline javascript.
- * e.g., <code><a href="..." onclick="Prado.Callback('..', 'Hello');">Click me</a></code>
- * @param {String} callback ID
- * @param {Array} parameters to pass to the callback service
- * @param {Function} on callback success handler method
- * @param {Object} additional callback options
+ * Create a new callback request using default settings.
+ * @param string callback handler unique ID.
+ * @param mixed parameter to pass to callback handler on the server side.
+ * @param function client side onSuccess event handler.
+ * @param object additional request options.
+ * @return boolean always false.
*/
-Prado.Callback = function(ID, params, onSuccess, options)
+Prado.Callback = function(UniqueID, parameter, onSuccess, options)
{
var callback =
{
- 'params' : [params] || [],
- 'onSuccess' : onSuccess || Prototype.emptyFunction,
- 'CausesValidation' : true
+ 'params' : parameter || '',
+ 'onSuccess' : onSuccess || Prototype.emptyFunction
};
Object.extend(callback, options || {});
- new Prado.AJAX.Callback(ID, callback);
+ request = new Prado.CallbackRequest(UniqueID, callback);
+ request.dispatch();
return false;
-} +}
+ /*
Copyright (c) 2005 JSON.org
@@ -737,7 +845,7 @@ SOFTWARE. Array.prototype.______array = '______array';
-Prado.AJAX.JSON = {
+Prado.JSON = {
org: 'http://www.JSON.org',
copyright: '(c)2005 JSON.org',
license: 'http://www.crockford.com/JSON/license.html',
@@ -1878,1426 +1986,583 @@ Form.Element.DelayedObserver.prototype = { }; -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) -// -// See scriptaculous.js for full license. - -/*--------------------------------------------------------------------------*/ - -if(typeof Effect == 'undefined') - throw("dragdrop.js requires including script.aculo.us' effects.js library"); - -var Droppables = { - drops: [], - - remove: function(element) { - this.drops = this.drops.reject(function(d) { return d.element==$(element) }); - }, - - add: function(element) { - element = $(element); - var options = Object.extend({ - greedy: true, - hoverclass: null, - tree: false - }, arguments[1] || {}); - - // cache containers - if(options.containment) { - options._containers = []; - var containment = options.containment; - if((typeof containment == 'object') && - (containment.constructor == Array)) { - containment.each( function(c) { options._containers.push($(c)) }); - } else { - options._containers.push($(containment)); - } - } - - if(options.accept) options.accept = [options.accept].flatten(); - - Element.makePositioned(element); // fix IE - options.element = element; - - this.drops.push(options); - }, - - findDeepestChild: function(drops) { - deepest = drops[0]; - - for (i = 1; i < drops.length; ++i) - if (Element.isParent(drops[i].element, deepest.element)) - deepest = drops[i]; - - return deepest; - }, - - isContained: function(element, drop) { - var containmentNode; - if(drop.tree) { - containmentNode = element.treeNode; - } else { - containmentNode = element.parentNode; - } - return drop._containers.detect(function(c) { return containmentNode == c }); - }, - - isAffected: function(point, element, drop) { - return ( - (drop.element!=element) && - ((!drop._containers) || - this.isContained(element, drop)) && - ((!drop.accept) || - (Element.classNames(element).detect( - function(v) { return drop.accept.include(v) } ) )) && - Position.within(drop.element, point[0], point[1]) ); - }, - - deactivate: function(drop) { - if(drop.hoverclass) - Element.removeClassName(drop.element, drop.hoverclass); - this.last_active = null; - }, - - activate: function(drop) { - if(drop.hoverclass) - Element.addClassName(drop.element, drop.hoverclass); - this.last_active = drop; - }, - - show: function(point, element) { - if(!this.drops.length) return; - var affected = []; - - if(this.last_active) this.deactivate(this.last_active); - this.drops.each( function(drop) { - if(Droppables.isAffected(point, element, drop)) - affected.push(drop); - }); - - if(affected.length>0) { - drop = Droppables.findDeepestChild(affected); - Position.within(drop.element, point[0], point[1]); - if(drop.onHover) - drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); - - Droppables.activate(drop); - } - }, - - fire: function(event, element) { - if(!this.last_active) return; - Position.prepare(); - - if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) - if (this.last_active.onDrop) - this.last_active.onDrop(element, this.last_active.element, event); - }, - - reset: function() { - if(this.last_active) - this.deactivate(this.last_active); - } -} - -var Draggables = { - drags: [], - observers: [], - - register: function(draggable) { - if(this.drags.length == 0) { - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.updateDrag.bindAsEventListener(this); - this.eventKeypress = this.keyPress.bindAsEventListener(this); - - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - Event.observe(document, "keypress", this.eventKeypress); - } - this.drags.push(draggable); - }, - - unregister: function(draggable) { - this.drags = this.drags.reject(function(d) { return d==draggable }); - if(this.drags.length == 0) { - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - Event.stopObserving(document, "keypress", this.eventKeypress); - } - }, - - activate: function(draggable) { - window.focus(); // allows keypress events if window isn't currently focused, fails for Safari - this.activeDraggable = draggable; - }, - - deactivate: function() { - this.activeDraggable = null; - }, - - updateDrag: function(event) { - if(!this.activeDraggable) return; - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - // Mozilla-based browsers fire successive mousemove events with - // the same coordinates, prevent needless redrawing (moz bug?) - if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; - this._lastPointer = pointer; - this.activeDraggable.updateDrag(event, pointer); - }, - - endDrag: function(event) { - if(!this.activeDraggable) return; - this._lastPointer = null; - this.activeDraggable.endDrag(event); - this.activeDraggable = null; - }, - - keyPress: function(event) { - if(this.activeDraggable) - this.activeDraggable.keyPress(event); - }, - - addObserver: function(observer) { - this.observers.push(observer); - this._cacheObserverCallbacks(); - }, - - removeObserver: function(element) { // element instead of observer fixes mem leaks - this.observers = this.observers.reject( function(o) { return o.element==element }); - this._cacheObserverCallbacks(); - }, - - notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' - if(this[eventName+'Count'] > 0) - this.observers.each( function(o) { - if(o[eventName]) o[eventName](eventName, draggable, event); - }); - }, - - _cacheObserverCallbacks: function() { - ['onStart','onEnd','onDrag'].each( function(eventName) { - Draggables[eventName+'Count'] = Draggables.observers.select( - function(o) { return o[eventName]; } - ).length; - }); - } -} - -/*--------------------------------------------------------------------------*/ - -var Draggable = Class.create(); -Draggable._revertCache = {}; -Draggable._dragging = {}; - -Draggable.prototype = { - initialize: function(element) { - var options = Object.extend({ - handle: false, - starteffect: function(element) { - element._opacity = Element.getOpacity(element); - Draggable._dragging[element] = true; - new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); - }, - reverteffect: function(element, top_offset, left_offset) { - var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; - Draggable._revertCache[element] = - new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, - queue: {scope:'_draggable', position:'end'} - }); - }, - endeffect: function(element) { - var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; - new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, - queue: {scope:'_draggable', position:'end'}, - afterFinish: function(){ Draggable._dragging[element] = false } - }); - }, - zindex: 1000, - revert: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } - }, arguments[1] || {}); - - this.element = $(element); - - if(options.handle && (typeof options.handle == 'string')) { - var h = Element.childrenWithClassName(this.element, options.handle, true); - if(h.length>0) this.handle = h[0]; - } - if(!this.handle) this.handle = $(options.handle); - if(!this.handle) this.handle = this.element; - - if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) - options.scroll = $(options.scroll); - - Element.makePositioned(this.element); // fix IE - - this.delta = this.currentDelta(); - this.options = options; - this.dragging = false; - - this.eventMouseDown = this.initDrag.bindAsEventListener(this); - Event.observe(this.handle, "mousedown", this.eventMouseDown); - - Draggables.register(this); - }, - - destroy: function() { - Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); - Draggables.unregister(this); - }, - - currentDelta: function() { - return([ - parseInt(Element.getStyle(this.element,'left') || '0'), - parseInt(Element.getStyle(this.element,'top') || '0')]); - }, - - initDrag: function(event) { - if(typeof Draggable._dragging[this.element] != undefined && - Draggable._dragging[this.element]) return; - if(Event.isLeftClick(event)) { - // abort on form elements, fixes a Firefox issue - var src = Event.element(event); - if(src.tagName && ( - src.tagName=='INPUT' || - src.tagName=='SELECT' || - src.tagName=='OPTION' || - src.tagName=='BUTTON' || - src.tagName=='TEXTAREA')) return; - - if(Draggable._revertCache[this.element]) { - Draggable._revertCache[this.element].cancel(); - Draggable._revertCache[this.element] = null; - } - - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var pos = Position.cumulativeOffset(this.element); - this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); - - Draggables.activate(this); - Event.stop(event); - } - }, - - startDrag: function(event) { - this.dragging = true; - - if(this.options.zindex) { - this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); - this.element.style.zIndex = this.options.zindex; - } - - if(this.options.ghosting) { - this._clone = this.element.cloneNode(true); - Position.absolutize(this.element); - this.element.parentNode.insertBefore(this._clone, this.element); - } - - if(this.options.scroll) { - if (this.options.scroll == window) { - var where = this._getWindowScroll(this.options.scroll); - this.originalScrollLeft = where.left; - this.originalScrollTop = where.top; - } else { - this.originalScrollLeft = this.options.scroll.scrollLeft; - this.originalScrollTop = this.options.scroll.scrollTop; - } - } - - Draggables.notify('onStart', this, event); - if(this.options.starteffect) this.options.starteffect(this.element); - }, - - updateDrag: function(event, pointer) { - if(!this.dragging) this.startDrag(event); - Position.prepare(); - Droppables.show(pointer, this.element); - Draggables.notify('onDrag', this, event); - this.draw(pointer); - if(this.options.change) this.options.change(this); - - if(this.options.scroll) { - this.stopScrolling(); - - var p; - if (this.options.scroll == window) { - with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } - } else { - p = Position.page(this.options.scroll); - p[0] += this.options.scroll.scrollLeft; - p[1] += this.options.scroll.scrollTop; - p.push(p[0]+this.options.scroll.offsetWidth); - p.push(p[1]+this.options.scroll.offsetHeight); - } - var speed = [0,0]; - if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); - if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); - if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); - if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); - this.startScrolling(speed); - } - - // fix AppleWebKit rendering - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - - Event.stop(event); - }, - - finishDrag: function(event, success) { - this.dragging = false; - - if(this.options.ghosting) { - Position.relativize(this.element); - Element.remove(this._clone); - this._clone = null; - } - - if(success) Droppables.fire(event, this.element); - Draggables.notify('onEnd', this, event); - - var revert = this.options.revert; - if(revert && typeof revert == 'function') revert = revert(this.element); - - var d = this.currentDelta(); - if(revert && this.options.reverteffect) { - this.options.reverteffect(this.element, - d[1]-this.delta[1], d[0]-this.delta[0]); - } else { - this.delta = d; - } - - if(this.options.zindex) - this.element.style.zIndex = this.originalZ; - - if(this.options.endeffect) - this.options.endeffect(this.element); - - Draggables.deactivate(this); - Droppables.reset(); - }, - - keyPress: function(event) { - if(event.keyCode!=Event.KEY_ESC) return; - this.finishDrag(event, false); - Event.stop(event); - }, - - endDrag: function(event) { - if(!this.dragging) return; - this.stopScrolling(); - this.finishDrag(event, true); - Event.stop(event); - }, - - draw: function(point) { - var pos = Position.cumulativeOffset(this.element); - var d = this.currentDelta(); - pos[0] -= d[0]; pos[1] -= d[1]; - - if(this.options.scroll && (this.options.scroll != window)) { - pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; - pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; - } - - var p = [0,1].map(function(i){ - return (point[i]-pos[i]-this.offset[i]) - }.bind(this)); - - if(this.options.snap) { - if(typeof this.options.snap == 'function') { - p = this.options.snap(p[0],p[1],this); - } else { - if(this.options.snap instanceof Array) { - p = p.map( function(v, i) { - return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) - } else { - p = p.map( function(v) { - return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) - } - }} - - var style = this.element.style; - if((!this.options.constraint) || (this.options.constraint=='horizontal')) - style.left = p[0] + "px"; - if((!this.options.constraint) || (this.options.constraint=='vertical')) - style.top = p[1] + "px"; - if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering - }, - - stopScrolling: function() { - if(this.scrollInterval) { - clearInterval(this.scrollInterval); - this.scrollInterval = null; - Draggables._lastScrollPointer = null; - } - }, - - startScrolling: function(speed) { - if(!(speed[0] || speed[1])) return; - this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; - this.lastScrolled = new Date(); - this.scrollInterval = setInterval(this.scroll.bind(this), 10); - }, - - scroll: function() { - var current = new Date(); - var delta = current - this.lastScrolled; - this.lastScrolled = current; - if(this.options.scroll == window) { - with (this._getWindowScroll(this.options.scroll)) { - if (this.scrollSpeed[0] || this.scrollSpeed[1]) { - var d = delta / 1000; - this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); - } - } - } else { - this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; - this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; - } - - Position.prepare(); - Droppables.show(Draggables._lastPointer, this.element); - Draggables.notify('onDrag', this); - Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); - Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; - Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; - if (Draggables._lastScrollPointer[0] < 0) - Draggables._lastScrollPointer[0] = 0; - if (Draggables._lastScrollPointer[1] < 0) - Draggables._lastScrollPointer[1] = 0; - this.draw(Draggables._lastScrollPointer); - - if(this.options.change) this.options.change(this); - }, - - _getWindowScroll: function(w) { - var T, L, W, H; - with (w.document) { - if (w.document.documentElement && documentElement.scrollTop) { - T = documentElement.scrollTop; - L = documentElement.scrollLeft; - } else if (w.document.body) { - T = body.scrollTop; - L = body.scrollLeft; - } - if (w.innerWidth) { - W = w.innerWidth; - H = w.innerHeight; - } else if (w.document.documentElement && documentElement.clientWidth) { - W = documentElement.clientWidth; - H = documentElement.clientHeight; - } else { - W = body.offsetWidth; - H = body.offsetHeight - } - } - return { top: T, left: L, width: W, height: H }; - } -} - -/*--------------------------------------------------------------------------*/ - -var SortableObserver = Class.create(); -SortableObserver.prototype = { - initialize: function(element, observer) { - this.element = $(element); - this.observer = observer; - this.lastValue = Sortable.serialize(this.element); - }, - - onStart: function() { - this.lastValue = Sortable.serialize(this.element); - }, - - onEnd: function() { - Sortable.unmark(); - if(this.lastValue != Sortable.serialize(this.element)) - this.observer(this.element) - } -} - -var Sortable = { - sortables: {}, - - _findRootElement: function(element) { - while (element.tagName != "BODY") { - if(element.id && Sortable.sortables[element.id]) return element; - element = element.parentNode; - } - }, - - options: function(element) { - element = Sortable._findRootElement($(element)); - if(!element) return; - return Sortable.sortables[element.id]; - }, - - destroy: function(element){ - var s = Sortable.options(element); - - if(s) { - Draggables.removeObserver(s.element); - s.droppables.each(function(d){ Droppables.remove(d) }); - s.draggables.invoke('destroy'); - - delete Sortable.sortables[s.element.id]; - } - }, - - create: function(element) { - element = $(element); - var options = Object.extend({ - element: element, - tag: 'li', // assumes li children, override with tag: 'tagname' - dropOnEmpty: false, - tree: false, - treeTag: 'ul', - overlap: 'vertical', // one of 'vertical', 'horizontal' - constraint: 'vertical', // one of 'vertical', 'horizontal', false - containment: element, // also takes array of elements (or id's); or false - handle: false, // or a CSS class - only: false, - hoverclass: null, - ghosting: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - format: /^[^_]*_(.*)$/, - onChange: Prototype.emptyFunction, - onUpdate: Prototype.emptyFunction - }, arguments[1] || {}); - - // clear any old sortable with same element - this.destroy(element); - - // build options for the draggables - var options_for_draggable = { - revert: true, - scroll: options.scroll, - scrollSpeed: options.scrollSpeed, - scrollSensitivity: options.scrollSensitivity, - ghosting: options.ghosting, - constraint: options.constraint, - handle: options.handle }; - - if(options.starteffect) - options_for_draggable.starteffect = options.starteffect; - - if(options.reverteffect) - options_for_draggable.reverteffect = options.reverteffect; - else - if(options.ghosting) options_for_draggable.reverteffect = function(element) { - element.style.top = 0; - element.style.left = 0; - }; - - if(options.endeffect) - options_for_draggable.endeffect = options.endeffect; - - if(options.zindex) - options_for_draggable.zindex = options.zindex; - - // build options for the droppables - var options_for_droppable = { - overlap: options.overlap, - containment: options.containment, - tree: options.tree, - hoverclass: options.hoverclass, - onHover: Sortable.onHover - //greedy: !options.dropOnEmpty - } - - var options_for_tree = { - onHover: Sortable.onEmptyHover, - overlap: options.overlap, - containment: options.containment, - hoverclass: options.hoverclass - } - - // fix for gecko engine - Element.cleanWhitespace(element); - - options.draggables = []; - options.droppables = []; - - // drop on empty handling - if(options.dropOnEmpty || options.tree) { - Droppables.add(element, options_for_tree); - options.droppables.push(element); - } - - (this.findElements(element, options) || []).each( function(e) { - // handles are per-draggable - var handle = options.handle ? - Element.childrenWithClassName(e, options.handle)[0] : e; - options.draggables.push( - new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); - Droppables.add(e, options_for_droppable); - if(options.tree) e.treeNode = element; - options.droppables.push(e); - }); - - if(options.tree) { - (Sortable.findTreeElements(element, options) || []).each( function(e) { - Droppables.add(e, options_for_tree); - e.treeNode = element; - options.droppables.push(e); - }); - } - - // keep reference - this.sortables[element.id] = options; - - // for onupdate - Draggables.addObserver(new SortableObserver(element, options.onUpdate)); - - }, - - // return all suitable-for-sortable elements in a guaranteed order - findElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.tag); - }, - - findTreeElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.treeTag); - }, - - onHover: function(element, dropon, overlap) { - if(Element.isParent(dropon, element)) return; - - if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { - return; - } else if(overlap>0.5) { - Sortable.mark(dropon, 'before'); - if(dropon.previousSibling != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, dropon); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } else { - Sortable.mark(dropon, 'after'); - var nextElement = dropon.nextSibling || null; - if(nextElement != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, nextElement); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } - }, - - onEmptyHover: function(element, dropon, overlap) { - var oldParentNode = element.parentNode; - var droponOptions = Sortable.options(dropon); - - if(!Element.isParent(dropon, element)) { - var index; - - var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); - var child = null; - - if(children) { - var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); - - for (index = 0; index < children.length; index += 1) { - if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { - offset -= Element.offsetSize (children[index], droponOptions.overlap); - } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { - child = index + 1 < children.length ? children[index + 1] : null; - break; - } else { - child = children[index]; - break; - } - } - } - - dropon.insertBefore(element, child); - - Sortable.options(oldParentNode).onChange(element); - droponOptions.onChange(element); - } - }, - - unmark: function() { - if(Sortable._marker) Element.hide(Sortable._marker); - }, - - mark: function(dropon, position) { - // mark on ghosting only - var sortable = Sortable.options(dropon.parentNode); - if(sortable && !sortable.ghosting) return; - - if(!Sortable._marker) { - Sortable._marker = $('dropmarker') || document.createElement('DIV'); - Element.hide(Sortable._marker); - Element.addClassName(Sortable._marker, 'dropmarker'); - Sortable._marker.style.position = 'absolute'; - document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); - } - var offsets = Position.cumulativeOffset(dropon); - Sortable._marker.style.left = offsets[0] + 'px'; - Sortable._marker.style.top = offsets[1] + 'px'; - - if(position=='after') - if(sortable.overlap == 'horizontal') - Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px'; - else - Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px'; - - Element.show(Sortable._marker); - }, - - _tree: function(element, options, parent) { - var children = Sortable.findElements(element, options) || []; - - for (var i = 0; i < children.length; ++i) { - var match = children[i].id.match(options.format); - - if (!match) continue; - - var child = { - id: encodeURIComponent(match ? match[1] : null), - element: element, - parent: parent, - children: new Array, - position: parent.children.length, - container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()) - } - - /* Get the element containing the children and recurse over it */ - if (child.container) - this._tree(child.container, options, child) - - parent.children.push (child); - } - - return parent; - }, - - /* Finds the first element of the given tag type within a parent element. - Used for finding the first LI[ST] within a L[IST]I[TEM].*/ - _findChildrenElement: function (element, containerTag) { - if (element && element.hasChildNodes) - for (var i = 0; i < element.childNodes.length; ++i) - if (element.childNodes[i].tagName == containerTag) - return element.childNodes[i]; - - return null; - }, - - tree: function(element) { - element = $(element); - var sortableOptions = this.options(element); - var options = Object.extend({ - tag: sortableOptions.tag, - treeTag: sortableOptions.treeTag, - only: sortableOptions.only, - name: element.id, - format: sortableOptions.format - }, arguments[1] || {}); - - var root = { - id: null, - parent: null, - children: new Array, - container: element, - position: 0 - } - - return Sortable._tree (element, options, root); - }, - - /* Construct a [i] index for a particular node */ - _constructIndex: function(node) { - var index = ''; - do { - if (node.id) index = '[' + node.position + ']' + index; - } while ((node = node.parent) != null); - return index; - }, - - sequence: function(element) { - element = $(element); - var options = Object.extend(this.options(element), arguments[1] || {}); - - return $(this.findElements(element, options) || []).map( function(item) { - return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; - }); - }, - - setSequence: function(element, new_sequence) { - element = $(element); - var options = Object.extend(this.options(element), arguments[2] || {}); - - var nodeMap = {}; - this.findElements(element, options).each( function(n) { - if (n.id.match(options.format)) - nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; - n.parentNode.removeChild(n); - }); - - new_sequence.each(function(ident) { - var n = nodeMap[ident]; - if (n) { - n[1].appendChild(n[0]); - delete nodeMap[ident]; - } - }); - }, - - serialize: function(element) { - element = $(element); - var options = Object.extend(Sortable.options(element), arguments[1] || {}); - var name = encodeURIComponent( - (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); - - if (options.tree) { - return Sortable.tree(element, arguments[1]).children.map( function (item) { - return [name + Sortable._constructIndex(item) + "[id]=" + - encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); - }).flatten().join('&'); - } else { - return Sortable.sequence(element, arguments[1]).map( function(item) { - return name + "[]=" + encodeURIComponent(item); - }).join('&'); - } - } -} - -/* Returns true if child is contained within element */ -Element.isParent = function(child, element) { - if (!child.parentNode || child == element) return false; - - if (child.parentNode == element) return true; - - return Element.isParent(child.parentNode, element); -} - -Element.findChildren = function(element, only, recursive, tagName) { - if(!element.hasChildNodes()) return null; - tagName = tagName.toUpperCase(); - if(only) only = [only].flatten(); - var elements = []; - $A(element.childNodes).each( function(e) { - if(e.tagName && e.tagName.toUpperCase()==tagName && - (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) - elements.push(e); - if(recursive) { - var grandchildren = Element.findChildren(e, only, recursive, tagName); - if(grandchildren) elements.push(grandchildren); - } - }); - - return (elements.length>0 ? elements.flatten() : []); -} - -Element.offsetSize = function (element, type) { - if (type == 'vertical' || type == 'height') - return element.offsetHeight; - else - return element.offsetWidth; -} - -// Copyright (c) 2005 Marty Haught, Thomas Fuchs -// -// See http://script.aculo.us for more info -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -if(!Control) var Control = {}; -Control.Slider = Class.create(); - -// options: -// axis: 'vertical', or 'horizontal' (default) -// -// callbacks: -// onChange(value) -// onSlide(value) -Control.Slider.prototype = { - initialize: function(handle, track, options) { - var slider = this; - - if(handle instanceof Array) { - this.handles = handle.collect( function(e) { return $(e) }); - } else { - this.handles = [$(handle)]; - } - - this.track = $(track); - this.options = options || {}; - - this.axis = this.options.axis || 'horizontal'; - this.increment = this.options.increment || 1; - this.step = parseInt(this.options.step || '1'); - this.range = this.options.range || $R(0,1); - - this.value = 0; // assure backwards compat - this.values = this.handles.map( function() { return 0 }); - this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; - this.options.startSpan = $(this.options.startSpan || null); - this.options.endSpan = $(this.options.endSpan || null); - - this.restricted = this.options.restricted || false; - - this.maximum = this.options.maximum || this.range.end; - this.minimum = this.options.minimum || this.range.start; - - // Will be used to align the handle onto the track, if necessary - this.alignX = parseInt(this.options.alignX || '0'); - this.alignY = parseInt(this.options.alignY || '0'); - - this.trackLength = this.maximumOffset() - this.minimumOffset(); - - this.handleLength = this.isVertical() ? - (this.handles[0].offsetHeight != 0 ? - this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,"")) : - (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : - this.handles[0].style.width.replace(/px$/,"")); - - this.active = false; - this.dragging = false; - this.disabled = false; - - if(this.options.disabled) this.setDisabled(); - - // Allowed values array - this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; - if(this.allowedValues) { - this.minimum = this.allowedValues.min(); - this.maximum = this.allowedValues.max(); - } - - this.eventMouseDown = this.startDrag.bindAsEventListener(this); - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.update.bindAsEventListener(this); - - // Initialize handles in reverse (make sure first handle is active) - this.handles.each( function(h,i) { - i = slider.handles.length-1-i; - slider.setValue(parseFloat( - (slider.options.sliderValue instanceof Array ? - slider.options.sliderValue[i] : slider.options.sliderValue) || - slider.range.start), i); - Element.makePositioned(h); // fix IE - Event.observe(h, "mousedown", slider.eventMouseDown); - }); - - Event.observe(this.track, "mousedown", this.eventMouseDown); - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - - this.initialized = true; - }, - dispose: function() { - var slider = this; - Event.stopObserving(this.track, "mousedown", this.eventMouseDown); - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - this.handles.each( function(h) { - Event.stopObserving(h, "mousedown", slider.eventMouseDown); - }); - }, - setDisabled: function(){ - this.disabled = true; - }, - setEnabled: function(){ - this.disabled = false; - }, - getNearestValue: function(value){ - if(this.allowedValues){ - if(value >= this.allowedValues.max()) return(this.allowedValues.max()); - if(value <= this.allowedValues.min()) return(this.allowedValues.min()); - - var offset = Math.abs(this.allowedValues[0] - value); - var newValue = this.allowedValues[0]; - this.allowedValues.each( function(v) { - var currentOffset = Math.abs(v - value); - if(currentOffset <= offset){ - newValue = v; - offset = currentOffset; - } - }); - return newValue; - } - if(value > this.range.end) return this.range.end; - if(value < this.range.start) return this.range.start; - return value; - }, - setValue: function(sliderValue, handleIdx){ - if(!this.active) { - this.activeHandleIdx = handleIdx || 0; - this.activeHandle = this.handles[this.activeHandleIdx]; - this.updateStyles(); - } - handleIdx = handleIdx || this.activeHandleIdx || 0; - if(this.initialized && this.restricted) { - if((handleIdx>0) && (sliderValue<this.values[handleIdx-1])) - sliderValue = this.values[handleIdx-1]; - if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1])) - sliderValue = this.values[handleIdx+1]; - } - sliderValue = this.getNearestValue(sliderValue); - this.values[handleIdx] = sliderValue; - this.value = this.values[0]; // assure backwards compat - - this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = - this.translateToPx(sliderValue); - - this.drawSpans(); - if(!this.dragging || !this.event) this.updateFinished(); - }, - setValueBy: function(delta, handleIdx) { - this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, - handleIdx || this.activeHandleIdx || 0); - }, - translateToPx: function(value) { - return Math.round( - ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * - (value - this.range.start)) + "px"; - }, - translateToValue: function(offset) { - return ((offset/(this.trackLength-this.handleLength) * - (this.range.end-this.range.start)) + this.range.start); - }, - getRange: function(range) { - var v = this.values.sortBy(Prototype.K); - range = range || 0; - return $R(v[range],v[range+1]); - }, - minimumOffset: function(){ - return(this.isVertical() ? this.alignY : this.alignX); - }, - maximumOffset: function(){ - return(this.isVertical() ? - (this.track.offsetHeight != 0 ? this.track.offsetHeight : - this.track.style.height.replace(/px$/,"")) - this.alignY : - (this.track.offsetWidth != 0 ? this.track.offsetWidth : - this.track.style.width.replace(/px$/,"")) - this.alignY); - }, - isVertical: function(){ - return (this.axis == 'vertical'); - }, - drawSpans: function() { - var slider = this; - if(this.spans) - $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); - if(this.options.startSpan) - this.setSpan(this.options.startSpan, - $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); - if(this.options.endSpan) - this.setSpan(this.options.endSpan, - $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); - }, - setSpan: function(span, range) { - if(this.isVertical()) { - span.style.top = this.translateToPx(range.start); - span.style.height = this.translateToPx(range.end - range.start + this.range.start); - } else { - span.style.left = this.translateToPx(range.start); - span.style.width = this.translateToPx(range.end - range.start + this.range.start); - } - }, - updateStyles: function() { - this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); - Element.addClassName(this.activeHandle, 'selected'); - }, - startDrag: function(event) { - if(Event.isLeftClick(event)) { - if(!this.disabled){ - this.active = true; - - var handle = Event.element(event); - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var track = handle; - if(track==this.track) { - var offsets = Position.cumulativeOffset(this.track); - this.event = event; - this.setValue(this.translateToValue( - (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) - )); - var offsets = Position.cumulativeOffset(this.activeHandle); - this.offsetX = (pointer[0] - offsets[0]); - this.offsetY = (pointer[1] - offsets[1]); - } else { - // find the handle (prevents issues with Safari) - while((this.handles.indexOf(handle) == -1) && handle.parentNode) - handle = handle.parentNode; - - this.activeHandle = handle; - this.activeHandleIdx = this.handles.indexOf(this.activeHandle); - this.updateStyles(); - - var offsets = Position.cumulativeOffset(this.activeHandle); - this.offsetX = (pointer[0] - offsets[0]); - this.offsetY = (pointer[1] - offsets[1]); - } - } - Event.stop(event); - } - }, - update: function(event) { - if(this.active) { - if(!this.dragging) this.dragging = true; - this.draw(event); - // fix AppleWebKit rendering - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - Event.stop(event); - } - }, - draw: function(event) { - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var offsets = Position.cumulativeOffset(this.track); - pointer[0] -= this.offsetX + offsets[0]; - pointer[1] -= this.offsetY + offsets[1]; - this.event = event; - this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); - if(this.initialized && this.options.onSlide) - this.options.onSlide(this.values.length>1 ? this.values : this.value, this); - }, - endDrag: function(event) { - if(this.active && this.dragging) { - this.finishDrag(event, true); - Event.stop(event); - } - this.active = false; - this.dragging = false; - }, - finishDrag: function(event, success) { - this.active = false; - this.dragging = false; - this.updateFinished(); - }, - updateFinished: function() { - if(this.initialized && this.options.onChange) - this.options.onChange(this.values.length>1 ? this.values : this.value, this); - this.event = null; - } -} - /**
- * Auto complete textbox via AJAX.
+ * Generic postback control.
*/
-Prado.AutoCompleter = Class.create();
+Prado.WebUI.CallbackControl = Class.extend(Prado.WebUI.PostBackControl,
+{
+ onPostBack : function(event, options)
+ {
+ request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ Event.stop(event);
+ }
+});
+/**
+ * TActiveButton control.
+ */
+Prado.WebUI.TActiveButton = Class.extend(Prado.WebUI.CallbackControl);
+/**
+ * TActiveLinkButton control.
+ */
+Prado.WebUI.TActiveLinkButton = Class.extend(Prado.WebUI.CallbackControl);
+Prado.WebUI.TActiveImageButton = Class.extend(Prado.WebUI.TImageButton,
+{
+ onPostBack : function(event, options)
+ {
+ this.addXYInput(event,options);
+ request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ Event.stop(event);
+ }
+});
/**
- * Overrides parent implementation of updateElement by trimming the value.
+ * Active check box.
*/
-Prado.AutoCompleter.Base = function(){};
-Prado.AutoCompleter.Base.prototype = Object.extend(Autocompleter.Base.prototype,
+Prado.WebUI.TActiveCheckBox = Class.extend(Prado.WebUI.CallbackControl,
{
- updateElement: function(selectedElement)
- {
- if (this.options.updateElement) {
- this.options.updateElement(selectedElement);
- return;
- }
+ onPostBack : function(event, options)
+ {
+ request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ }
+});
- var value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal');
- var lastTokenPos = this.findLastToken();
- if (lastTokenPos != -1) {
- var newValue = this.element.value.substr(0, lastTokenPos + 1);
- var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/);
- if (whitespace)
- newValue += whitespace[0];
- this.element.value = (newValue + value).trim();
- } else {
- this.element.value = value.trim();
- }
- this.element.focus();
-
- if (this.options.afterUpdateElement)
- this.options.afterUpdateElement(this.element, selectedElement);
- }
+/**
+ * TActiveRadioButton control.
+ */
+Prado.WebUI.TActiveRadioButton = Class.extend(Prado.WebUI.TActiveCheckBox);
+
+
+/**
+ * TActiveTextBox control, handles onchange event.
+ */
+Prado.WebUI.TActiveTextBox = Class.extend(Prado.WebUI.TTextBox,
+{
+ onInit : function(options)
+ {
+ if(options['TextMode'] != 'MultiLine')
+ Event.observe(this.element, "keydown", this.handleReturnKey.bind(this));
+ Event.observe(this.element, "change", this.doCallback.bindEvent(this,options));
+ },
+
+ doCallback : function(event, options)
+ {
+ request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ Event.stop(event);
+ }
});
/**
- * Based on the Prototype Autocompleter class.
- * This client-side component should be instantiated from a Prado component.
- * Usage: <t>new Prado.AutoCompleter('textboxID', 'updateDivID', {callbackID : '...'});
+ * TAutoComplete control.
*/
-Prado.AutoCompleter.prototype = Object.extend(new Autocompleter.Base(),
+Prado.WebUI.TAutoComplete = Class.extend(Autocompleter.Base, Prado.WebUI.TActiveTextBox.prototype);
+Prado.WebUI.TAutoComplete = Class.extend(Prado.WebUI.TAutoComplete,
{
- /**
- * This component is initialized by
- * <code>new Prado.AutoCompleter(...)</code>
- * @param string the ID of the textbox element to observe
- * @param string the ID of the div to display the auto-complete options
- * @param array a hash of options, e.g. auto-completion token separator.
- */
- initialize : function(element, update, options)
+ initialize : function(options)
+ {
+ this.options = options;
+ this.baseInitialize(options.ID, options.ResultPanel, options);
+ Object.extend(this.options,
+ {
+ onSuccess : this.onComplete.bind(this)
+ });
+
+ if(options.AutoPostBack)
+ this.onInit(options);
+ },
+
+ doCallback : function(event, options)
{
- this.baseInitialize(element, update, options);
+ if(!this.active)
+ {
+ request = new Prado.CallbackRequest(options.EventTarget, options);
+ request.dispatch();
+ Event.stop(event);
+ }
},
- /**
- * The callback function, i.e., function called on successful AJAX return.
- * Calls update choices in the Autocompleter.
- * @param string new auto-complete options for display
- */
- onUpdateReturn : function(result)
+ //Overrides parent implementation, fires onchange event.
+ onClick: function(event)
{
- if(isString(result) && result.length > 0)
- this.updateChoices(result);
+ var element = Event.findElement(event, 'LI');
+ this.index = element.autocompleteIndex;
+ this.selectEntry();
+ this.hide();
+ Event.fireEvent(this.element, "change");
},
- /**
- * Requesting new choices using Prado's client-side callback scheme.
- */
getUpdatedChoices : function()
{
- Prado.Callback(this.element.id, this.getToken(), this.onUpdateReturn.bind(this));
+ options = new Array(this.getToken(),"__TAutoComplete_onSuggest__");
+ Prado.Callback(this.options.EventTarget, options, null, this.options);
+ },
+
+ onComplete : function(request, boundary)
+ {
+ result = Prado.Element.extractContent(request.transport.responseText, boundary);
+ if(typeof(result) == "string" && result.length > 0)
+ this.updateChoices(result);
}
});
/**
- * Prado TActivePanel client javascript. Usage
- * <code>
- * Prado.ActivePanel.register("id", options);
- * Prado.ActivePanel.update("id", "hello");
- * </code>
+ * Time Triggered Callback class.
*/
-Prado.ActivePanel =
+Prado.WebUI.TTimeTriggeredCallback = Base.extend(
{
- callbacks : {},
+ count : 0,
+ timeout : 0,
+
+ constructor : function(options)
+ {
+ this.options = Object.extend(
+ {
+ Interval : 1,
+ DecayRate : 0
+ }, options || {})
- register : function(id, options)
+ this.onComplete = this.options.onComplete;
+ Prado.WebUI.TTimeTriggeredCallback.register(this);
+ },
+
+ startTimer : function()
+ {
+ this.options.onComplete = this.onRequestComplete.bind(this);
+ setTimeout(this.onTimerEvent.bind(this), 200);
+ },
+
+ stopTimer : function()
{
- Prado.ActivePanel.callbacks[id] = options;
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ this.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ this.timer = undefined;
+ this.count = 0;
},
- update : function(id, param)
+ onTimerEvent : function()
{
- var request = new Prado.ActivePanel.Request(id,
- Prado.ActivePanel.callbacks[id]);
- request.callback(param);
+ this.options.params = this.timeout/1000;
+ request = new Prado.CallbackRequest(this.options.ID, this.options);
+ request.dispatch();
+ },
+
+ onRequestComplete : function()
+ {
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ this.timer = setTimeout(this.onTimerEvent.bind(this), this.getNewTimeout())
+ },
+
+ getNewTimeout : function()
+ {
+ switch(this.options.DecayType)
+ {
+ case 'Exponential':
+ t = (Math.exp(this.options.DecayRate*this.count*this.options.Interval))-1;
+ break;
+ case 'Linear':
+ t = this.options.DecayRate*this.count*this.options.Interval;
+ break;
+ case 'Quadratic':
+ t = this.options.DecayRate*this.count*this.count*this.options.Interval;
+ break;
+ case 'Cubic':
+ t = this.options.DecayRate*this.count*this.count*this.count*this.options.Interval;
+ break;
+ default : t = 0;
+ }
+ this.timeout = (t + this.options.Interval)*1000;
+ this.count++;
+ return parseInt(this.timeout);
}
-}
+},
+//class methods
+{
+ timers : {},
+
+ register : function(timer)
+ {
+ this.timers[timer.options.ID] = timer;
+ },
+
+ start : function(id)
+ {
+ if(this.timers[id])
+ this.timers[id].startTimer();
+ },
+
+ stop : function(id)
+ {
+ if(this.timers[id])
+ this.timers[id].stopTimer();
+ }
+});
+
+Prado.WebUI.ActiveListControl = Base.extend(
+{
+ constructor : function(options)
+ {
+ this.element = $(options.ID);
+ this.options = options;
+ Event.observe(this.element, "change", this.doCallback.bind(this));
+ },
+
+ doCallback : function(event)
+ {
+ request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.dispatch();
+ Event.stop(event);
+ }
+});
+
+Prado.WebUI.TActiveDropDownList = Prado.WebUI.ActiveListControl;
+Prado.WebUI.TActiveListBox = Prado.WebUI.ActiveListControl;
+
+/**
+ * Observe event of a particular control to trigger a callback request.
+ */
+Prado.WebUI.TEventTriggeredCallback = Base.extend(
+{
+ constructor : function(options)
+ {
+ this.options = options;
+ element = $(options['ControlID']);
+ if(element)
+ Event.observe(element, this.getEventName(element), this.doCallback.bind(this));
+ },
+
+ getEventName : function(element)
+ {
+ name = this.options.EventName;
+ if(typeof(name) == "undefined" && element.type)
+ {
+ switch (element.type.toLowerCase())
+ {
+ case 'password':
+ case 'text':
+ case 'textarea':
+ case 'select-one':
+ case 'select-multiple':
+ return 'change';
+ }
+ }
+ return typeof(name) == "undefined" || name == "undefined" ? 'click' : name;
+ },
+
+ doCallback : function(event)
+ {
+ request = new Prado.CallbackRequest(this.options.ID, this.options);
+ request.dispatch();
+ if(this.options.StopEvent == true)
+ Event.stop(event);
+ }
+});
/**
- * Client-script for TActivePanel. Uses Callback to notify the server
- * for updates, if update option is set, the innerHTML of the update ID
- * is set to the returned output.
+ * Observe changes to a property of a particular control to trigger a callback.
*/
-Prado.ActivePanel.Request = Class.create();
-Prado.ActivePanel.Request.prototype =
+Prado.WebUI.TValueTriggeredCallback = Base.extend(
+{
+ count : 1,
+
+ observing : true,
+
+ constructor : function(options)
+ {
+ this.options = options;
+ this.options.PropertyName = this.options.PropertyName || 'value';
+ element = $(options['ControlID']);
+ this.value = element ? element[this.options.PropertyName] : undefined;
+ Prado.WebUI.TValueTriggeredCallback.register(this);
+ this.startObserving();
+ },
+
+ stopObserving : function()
+ {
+ clearTimeout(this.timer);
+ this.observing = false;
+ },
+
+ startObserving : function()
+ {
+ this.timer = setTimeout(this.checkChanges.bind(this), this.options.Interval*1000);
+ },
+
+ checkChanges : function()
+ {
+ element = $(this.options.ControlID);
+ if(element)
+ {
+ value = element[this.options.PropertyName];
+ if(this.value != value)
+ {
+ this.doCallback(this.value, value);
+ this.value = value;
+ this.count=1;
+ }
+ else
+ this.count = this.count + this.options.Decay;
+ if(this.observing)
+ this.time = setTimeout(this.checkChanges.bind(this),
+ parseInt(this.options.Interval*1000*this.count));
+ }
+ },
+
+ doCallback : function(oldValue, newValue)
+ {
+ request = new Prado.CallbackRequest(this.options.ID, this.options);
+ param = {'OldValue' : oldValue, 'NewValue' : newValue};
+ request.setParameter(param);
+ request.dispatch();
+ }
+},
+//class methods
{
- initialize : function(element, options)
+ timers : {},
+
+ register : function(timer)
{
- this.element = element;
- this.setOptions(options);
+ this.timers[timer.options.ID] = timer;
+ },
+
+ stop : function(id)
+ {
+ if(this.timers[id])
+ this.timers[id].stopObserving();
+ }
+});
+ + +Prado.WebUI.TInPlaceTextBox = Base.extend(
+{
+ isSaving : false,
+ isEditing : false,
+ editField : null,
+
+ constructor : function(options)
+ {
+ this.options = Object.extend(
+ {
+ LoadTextFromSource : false,
+ TextMode : 'SingleLine'
+
+ }, options || {});
+ this.element = $(this.options.ID);
+
+ this.initializeListeners();
+ },
+
+ /**
+ * Initialize the listeners.
+ */
+ initializeListeners : function()
+ {
+ this.onclickListener = this.enterEditMode.bindAsEventListener(this);
+ Event.observe(this.element, 'click', this.onclickListener);
+ if (this.options.ExternalControl)
+ Event.observe($(this.options.ExternalControl), 'click', this.onclickListener);
},
/**
- * Set some options.
+ * Changes the panel to an editable input.
+ * @param {Event} evt event source
*/
- setOptions : function(options)
+ enterEditMode : function(evt)
+ {
+ if (this.isSaving) return;
+ if (this.isEditing) return;
+ this.isEditing = true;
+ this.onEnterEditMode();
+ this.createEditorInput();
+ this.showTextBox();
+ this.editField.disabled = false;
+ if(this.options.LoadTextOnEdit)
+ this.loadExternalText();
+ Prado.Element.focus(this.editField);
+ if (evt)
+ Event.stop(evt);
+ return false;
+ },
+
+ showTextBox : function()
+ {
+ Element.hide(this.element);
+ Element.show(this.editField);
+ },
+
+ showLabel : function()
{
- this.options =
+ Element.show(this.element);
+ Element.hide(this.editField);
+ },
+
+ /**
+ * Create the edit input field.
+ */
+ createEditorInput : function()
+ {
+ if(this.editField == null)
+ this.createTextBox();
+
+ this.editField.value = this.getText();
+ },
+
+ loadExternalText : function()
+ {
+ this.editField.disabled = true;
+ this.onLoadingText();
+ options = new Array('__InlineEditor_loadExternalText__', this.getText());
+ request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.setCausesValidation(false);
+ request.setParameter(options);
+ request.options.onSuccess = this.onloadExternalTextSuccess.bind(this);
+ request.options.onFailure = this.onloadExternalTextFailure.bind(this);
+ request.dispatch();
+ },
+
+ /**
+ * Create a new input textbox or textarea
+ */
+ createTextBox : function()
+ {
+ cssClass= this.element.className || '';
+ inputName = this.options.EventTarget;
+ options = {'className' : cssClass, name : inputName, id : this.options.TextBoxID};
+ if(this.options.TextMode == 'SingleLine')
+ {
+ if(this.options.MaxLength > 0)
+ options['maxlength'] = this.options.MaxLength;
+ this.editField = INPUT(options);
+ }
+ else
{
- onSuccess : this.onSuccess.bind(this)
+ if(this.options.Rows > 0)
+ options['rows'] = this.options.Rows;
+ if(this.options.Columns > 0)
+ options['cols'] = this.options.Columns;
+ if(this.options.Wrap)
+ options['wrap'] = 'off';
+ this.editField = TEXTAREA(options);
}
- Object.extend(this.options, options || {});
+
+ this.editField.style.display="none";
+ this.element.parentNode.insertBefore(this.editField,this.element)
+
+ //handle return key within single line textbox
+ if(this.options.TextMode == 'SingleLine')
+ {
+ Event.observe(this.editField, "keydown", function(e)
+ {
+ if(Event.keyCode(e) == Event.KEY_RETURN)
+ {
+ var target = Event.element(e);
+ if(target)
+ {
+ Event.fireEvent(target, "blur");
+ Event.stop(e);
+ }
+ }
+ });
+ }
+
+ Event.observe(this.editField, "blur", this.onTextBoxBlur.bind(this));
},
/**
- * Make the callback request
+ * @return {String} panel inner html text.
*/
- callback : function(param)
+ getText: function()
{
- this.options.params = [param];
- new Prado.AJAX.Callback(this.element, this.options);
- },
+ return this.element.innerHTML;
+ },
/**
- * Callback onSuccess handler, update the element innerHTML if necessary
+ * Edit mode entered, calls optional event handlers.
*/
- onSuccess : function(result, output)
+ onEnterEditMode : function()
+ {
+ if(typeof(this.options.onEnterEditMode) == "function")
+ this.options.onEnterEditMode(this,null);
+ },
+
+ onTextBoxBlur : function(e)
{
- if(this.options.update)
+ text = this.element.innerHTML;
+ if(this.options.AutoPostBack && text != this.editField.value)
+ this.onTextChanged(text);
+ else
{
- if (!this.options.evalScripts)
- output = output.stripScripts();
- Element.update(this.options.update, output);
+ this.element.innerHTML = this.editField.value;
+ this.isEditing = false;
+ if(this.options.AutoHide)
+ this.showLabel();
}
- }
-}
+ },
-/**
- * Drop container to accept draggable component drops.
- */
-Prado.DropContainer = Class.create();
-Prado.DropContainer.prototype = Object.extend(new Prado.ActivePanel.Request(),
-{
- initialize : function(element, options)
+ /**
+ * When the text input value has changed.
+ * @param {String} original text
+ */
+ onTextChanged : function(text)
{
- this.element = element;
- this.setOptions(options);
- Object.extend(this.options,
+ request = new Prado.CallbackRequest(this.options.EventTarget, this.options);
+ request.setParameter(text);
+ request.options.onSuccess = this.onTextChangedSuccess.bind(this);
+ request.options.onFailure = this.onTextChangedFailure.bind(this);
+ if(request.dispatch())
{
- onDrop : this.onDrop.bind(this),
- evalScripts : true,
- onSuccess : options.onSuccess || this.onSuccess.bind(this)
- });
- Droppables.add(element, this.options);
+ this.isSaving = true;
+ this.editField.disabled = true;
+ }
},
- onDrop : function(draggable, droppable)
+ /**
+ * When loading external text.
+ */
+ onLoadingText : function()
{
- this.callback(draggable.id)
- }
-});
+ //Logger.info("on loading text");
+ },
-Prado.ActiveImageButton = Class.create();
-Prado.ActiveImageButton.prototype =
-{
- initialize : function(element, options)
+ onloadExternalTextSuccess : function(request, parameter)
{
- this.element = $(element);
- this.options = options;
- Event.observe(this.element, "click", this.click.bind(this));
+ this.isEditing = true;
+ this.editField.disabled = false;
+ this.editField.value = this.getText();
+ Prado.Element.focus(this.editField);
},
- click : function(e)
+ onloadExternalTextFailure : function(request, parameter)
{
- var el = $('{$this->ClientID}');
- var imagePos = Position.cumulativeOffset(this.element);
- var clickedPos = [e.clientX, e.clientY];
- var param = (clickedPos[0]-imagePos[0]+1)+","+(clickedPos[1]-imagePos[1]+1);
- Prado.Callback(this.element, param, null, this.options);
- Event.stop(e);
- }
-}
+ this.isSaving = false;
+ this.isEditing = false;
+ this.showLabel();
+ },
+ /**
+ * Text change successfully.
+ * @param {Object} sender
+ * @param {Object} parameter
+ */
+ onTextChangedSuccess : function(sender, parameter)
+ {
+ this.isSaving = false;
+ this.isEditing = false;
+ if(this.options.AutoHide)
+ this.showLabel();
+ this.element.innerHTML = parameter == null ? this.editField.value : parameter;
+ this.editField.disabled = false;
+ },
- + onTextChangedFailure : function(sender, parameter)
+ {
+ this.editField.disabled = false;
+ this.isSaving = false;
+ this.isEditing = false;
+ }
+}); |