summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--framework/Web/Javascripts/js/compressed/ajax.js354
-rw-r--r--framework/Web/Javascripts/js/compressed/prado.js128
-rw-r--r--framework/Web/Javascripts/js/compressed/validator.js8
-rw-r--r--framework/Web/Javascripts/js/debug/ajax.js2605
-rw-r--r--framework/Web/Javascripts/js/debug/prado.js723
-rw-r--r--framework/Web/Javascripts/js/debug/validator.js19
-rw-r--r--framework/Web/Javascripts/prado/inlineeditor.js30
-rw-r--r--framework/Web/Javascripts/prado/validation3.js6
-rw-r--r--framework/Web/UI/ActiveControls/TActiveRadioButton.php1
-rw-r--r--framework/Web/UI/ActiveControls/TInPlaceTextBox.php246
-rw-r--r--framework/Web/UI/ActiveControls/TTriggeredCallback.php4
-rw-r--r--tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.page27
-rw-r--r--tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.php5
13 files changed, 2016 insertions, 2140 deletions
diff --git a/framework/Web/Javascripts/js/compressed/ajax.js b/framework/Web/Javascripts/js/compressed/ajax.js
index f39f8325..b65892cc 100644
--- a/framework/Web/Javascripts/js/compressed/ajax.js
+++ b/framework/Web/Javascripts/js/compressed/ajax.js
@@ -5,7 +5,7 @@ this.responders.push(responderToAdd);},unregister:function(responderToRemove){th
Object.extend(this.options,options||{});},responseIsSuccess:function(){return this.transport.status==undefined||this.transport.status==0||(this.transport.status>=200&&this.transport.status<300);},responseIsFailure:function(){return!this.responseIsSuccess();}}
Ajax.Request=Class.create();Ajax.Request.Events=['Uninitialized','Loading','Loaded','Interactive','Complete'];Ajax.Request.prototype=Object.extend(new Ajax.Base(),{initialize:function(url,options){this.transport=Ajax.getTransport();this.setOptions(options);this.request(url);},request:function(url){var parameters=this.options.parameters||'';if(parameters.length>0)parameters+='&_=';try{this.url=url;if(this.options.method=='get'&&parameters.length>0)
this.url+=(this.url.match(/\?/)?'&':'?')+parameters;Ajax.Responders.dispatch('onCreate',this,this.transport);this.transport.open(this.options.method,this.url,this.options.asynchronous);if(this.options.asynchronous){this.transport.onreadystatechange=this.onStateChange.bind(this);setTimeout((function(){this.respondToReadyState(1)}).bind(this),10);}
-this.setRequestHeaders();var body=this.options.postBody?this.options.postBody:parameters;this.transport.send(this.options.method=='post'?body:null);}catch(e){this.dispatchException(e);}},setRequestHeaders:function(){var requestHeaders=['X-Requested-With','XMLHttpRequest','X-Prototype-Version',Prototype.Version,'Accept','text/javascript, text/html, application/xml, text/xml, */*'];if(this.options.method=='post'){requestHeaders.push('Content-type',this.options.contentType);if(this.transport.overrideMimeType)
+this.setRequestHeaders();var body=this.options.postBody?this.options.postBody:parameters;this.transport.send(this.options.method=='post'?body:null);}catch(e){this.dispatchException(e);}},setRequestHeaders:function(){var requestHeaders=['X-Requested-With','XMLHttpRequest','X-Prototype-Version',Prototype.Version,'Accept','text/javascript, text/html, application/xml, text/xml'];if(this.options.method=='post'){requestHeaders.push('Content-type',this.options.contentType);if(this.transport.overrideMimeType)
requestHeaders.push('Connection','close');}
if(this.options.requestHeaders)
requestHeaders.push.apply(requestHeaders,this.options.requestHeaders);for(var i=0;i<requestHeaders.length;i+=2)
@@ -20,74 +20,92 @@ this.transport=Ajax.getTransport();this.setOptions(options);var onComplete=this.
response=response.stripScripts();if(receiver){if(this.options.insertion){new this.options.insertion(receiver,response);}else{Element.update(receiver,response);}}
if(this.responseIsSuccess()){if(this.onComplete)
setTimeout(this.onComplete.bind(this),10);}}});Ajax.PeriodicalUpdater=Class.create();Ajax.PeriodicalUpdater.prototype=Object.extend(new Ajax.Base(),{initialize:function(container,url,options){this.setOptions(options);this.onComplete=this.options.onComplete;this.frequency=(this.options.frequency||2);this.decay=(this.options.decay||1);this.updater={};this.container=container;this.url=url;this.start();},start:function(){this.options.onComplete=this.updateComplete.bind(this);this.onTimerEvent();},stop:function(){this.updater.onComplete=undefined;clearTimeout(this.timer);(this.onComplete||Prototype.emptyFunction).apply(this,arguments);},updateComplete:function(request){if(this.options.decay){this.decay=(request.responseText==this.lastText?this.decay*this.options.decay:1);this.lastText=request.responseText;}
-this.timer=setTimeout(this.onTimerEvent.bind(this),this.decay*this.frequency*1000);},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options);}});Prado.AJAX={Service:'Prototype'};Prado.AJAX.EvalScript=function(output)
-{var match=new RegExp(Ajax.Updater.ScriptFragment,'img');var scripts=output.match(match);if(scripts)
-{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);}}
-Prado.AJAX.Request=Class.create();Prado.AJAX.Request.prototype=Object.extend(Ajax.Request.prototype,{evalJSON:function()
+this.timer=setTimeout(this.onTimerEvent.bind(this),this.decay*this.frequency*1000);},onTimerEvent:function(){this.updater=new Ajax.Updater(this.container,this.url,this.options);}});Object.extend(Ajax.Request.prototype,{respondToReadyState:function(readyState)
+{var event=Ajax.Request.Events[readyState];var transport=this.transport,json=this.getHeaderData(Prado.CallbackRequest.DATA_HEADER);if(event=='Complete')
{try
-{var json=this.transport.getResponseHeader('X-JSON'),object;object=eval(json);return object;}
+{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);}
+if(event=='Complete')
+this.transport.onreadystatechange=Prototype.emptyFunction;},getHeaderData:function(name)
+{try
+{var json=this.header(name);return eval('('+json+')');}
+catch(e)
+{if(typeof(json)=="string")
+return Prado.CallbackRequest.decode(json);}}});Prado.CallbackRequest=Class.create();Object.extend(Prado.CallbackRequest,{FIELD_CALLBACK_TARGET:'PRADO_CALLBACK_TARGET',FIELD_CALLBACK_PARAMETER:'PRADO_CALLBACK_PARAMETER',FIELD_CALLBACK_PAGESTATE:'PRADO_PAGESTATE',FIELD_POSTBACK_TARGET:'PRADO_POSTBACK_TARGET',FIELD_POSTBACK_PARAMETER:'PRADO_POSTBACK_PARAMETER',PostDataLoaders:[],DATA_HEADER:'X-PRADO-DATA',ACTION_HEADER:'X-PRADO-ACTIONS',ERROR_HEADER:'X-PRADO-ERROR',PAGESTATE_HEADER:'X-PRADO-PAGESTATE',requestInProgress:null,addPostLoaders:function(ids)
+{this.PostDataLoaders=this.PostDataLoaders.concat(ids);list=[];this.PostDataLoaders.each(function(id)
+{if(list.indexOf(id)<0)
+list.push(id);});this.PostDataLoaders=list;},dispatchActions:function(transport,actions)
+{if(actions&&actions.length>0)
+actions.each(this.__run.bind(this,transport));},__run:function(transport,command)
+{for(var method in command)
+{try
+{method.toFunction().apply(this,command[method].concat(transport));}
catch(e)
-{if(isString(json))
-{return Prado.AJAX.JSON.parse(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);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.AJAX.RequestBuilder=Class.create();Prado.AJAX.RequestBuilder.prototype={initialize:function()
-{this.body='';this.data=[];},encode:function(data)
-{return Prado.AJAX.JSON.stringify(data);},build:function(data)
-{var sep='';for(var argName in data)
-{if(isFunction(data[argName]))continue;try
-{this.body+=sep+argName+'=';this.body+=encodeURIComponent(this.encode(data[argName]));}catch(e){throw Prado.AJAX.Error(e,1006);}
-sep='&';}},getAll:function()
-{this.build(this.data);return this.body;}}
-Prado.AJAX.RemoteObject=function(){};Prado.AJAX.RemoteObject.Request=Class.create();Prado.AJAX.RemoteObject.Request.prototype=Object.extend(Prado.AJAX.Request.prototype,{initialize:function(options)
-{this.transport=Ajax.getTransport();this.setOptions(options);this.post=new Prado.AJAX.RequestBuilder();},invokeRemoteObject:function(url,args)
-{this.initParameters(args);this.options.postBody=this.post.getAll();this.request(url);},initParameters:function(args)
-{this.post.data['__parameters']=[];for(var i=0;i<args.length;i++)
-this.post.data['__parameters'][i]=args[i];}});Prado.AJAX.RemoteObject.prototype={baseInitialize:function(handlers,options)
-{this.__handlers=handlers||{};this.__service=new Prado.AJAX.RemoteObject.Request(options);},__call:function(url,method,args)
-{this.__service.options.onSuccess=this.__onSuccess.bind(this);this.__callback=method;return this.__service.invokeRemoteObject(url+"/"+method,args);},__onSuccess:function(transport,json)
-{if(this.__handlers[this.__callback])
-this.__handlers[this.__callback](json,transport.responseText);}};Prado.AJAX.Exception={"on505":function(request,transport,e)
-{var msg='HTTP '+transport.status+" with response";Logger.error(msg,transport.responseText);Logger.exception(e);},onComplete:function(request,transport,e)
-{if(transport.status!=505)
-{var msg='HTTP '+transport.status+" with response : \n";msg+=transport.responseText+"\n";msg+="Data : \n"+inspect(e);Logger.warn(msg);}},format:function(e)
+{if(typeof(Logger)!="undefined")
+Prado.CallbackRequest.Exception.onException(null,e);}}},Exception:{"on500":function(request,transport,data)
+{var e=request.getHeaderData(Prado.CallbackRequest.ERROR_HEADER);Logger.error("Callback Server Error "+e.code,this.formatException(e));},'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);}},onException:function(request,e)
+{msg="";$H(e).each(function(item)
+{msg+=item.key+": "+item.value+"\n";})
+Logger.error('Uncaught Callback Client Exception:',msg);},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";}
-return msg;},logException:function(e)
-{var msg=Prado.AJAX.Exception.format(e);Logger.error("Server Error "+e.code,msg);}}
-Event.OnLoad(function()
+msg+=e.version+" "+e.time+"\n";return msg;}},encode:function(data)
+{return Prado.JSON.stringify(data);},decode:function(data)
+{if(typeof(data)=="string"&&data.trim().length>0)
+return Prado.JSON.parse(data);else
+return null;},dispatchPriorityRequest:function(callback)
+{this.abortRequestInProgress();callback.request=new Ajax.Request(callback.url,callback.options);callback.timeout=setTimeout(function()
+{Prado.CallbackRequest.abortRequestInProgress();},callback.options.RequestTimeOut);this.requestInProgress=callback;return true;},dispatchNormalRequest:function(callback)
+{new Ajax.Request(callback.url,callback.options);return true;},abortRequestInProgress:function()
+{inProgress=Prado.CallbackRequest.requestInProgress;if(inProgress)
+{inProgress.request.transport.abort();clearTimeout(inProgress.timeout);Prado.CallbackRequest.requestInProgress=null;return true;}
+return false;},updatePageState:function(request,transport)
+{pagestate=$(this.FIELD_CALLBACK_PAGESTATE);if(request.options.EnablePageStateUpdate&&request.options.HasPriority&&pagestate)
+{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);}}}})
+Ajax.Responders.register({onComplete:function(request)
+{if(request.options.HasPriority)
+Prado.CallbackRequest.abortRequestInProgress();}});Event.OnLoad(function()
{if(typeof Logger!="undefined")
-{Logger.exception=Prado.AJAX.Exception.logException;Ajax.Responders.register(Prado.AJAX.Exception);}});Prado.AJAX.Callback=Class.create();Prado.AJAX.Callback.prototype=Object.extend(new Prado.AJAX.RemoteObject(),{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();},collectPostData:function()
-{var IDs=Prado.AJAX.Callback.IDs;this.__service.post.data['__data']={};for(var i=0;i<IDs.length;i++)
-{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);}},collectArrayPostData:function(name)
-{var elements=document.getElementsByName(name);var data=[];$A(elements).each(function(el)
-{if($F(el))data.push($F(el));});return data;},requestCallback:function()
-{this.collectPostData();if(Prado.AJAX.Validate(this.options))
-return this.__call(Prado.AJAX.Callback.Server,'handleCallback',this.options.params);},handleCallback:function(result,output)
-{if(typeof(result)!="undefined"&&!isNull(result))
-{this.options.onSuccess(result['data'],output);if(result['actions'])
-result.actions.each(Prado.AJAX.Callback.Action.__run);}}});Prado.AJAX.Callback.Action={__run:function(command)
-{for(var name in command)
-{if(command[name][0]&&($(command[name][0])||command[name][0].indexOf("[]")>-1))
-{name.toFunction().apply(this,command[name]);}}}};Prado.AJAX.Validate=function(options)
-{if(options.CausesValidation)
-{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;};Prado.AJAX.Callback.Server='';Prado.AJAX.Callback.IDs=[];Prado.Callback=function(ID,params,onSuccess,options)
-{var callback={'params':[params]||[],'onSuccess':onSuccess||Prototype.emptyFunction,'CausesValidation':true};Object.extend(callback,options||{});new Prado.AJAX.Callback(ID,callback);return false;}
-Array.prototype.______array='______array';Prado.AJAX.JSON={org:'http://www.JSON.org',copyright:'(c)2005 JSON.org',license:'http://www.crockford.com/JSON/license.html',stringify:function(arg){var c,i,l,s='',v;switch(typeof arg){case'object':if(arg){if(arg.______array=='______array'){for(i=0;i<arg.length;++i){v=this.stringify(arg[i]);if(s){s+=',';}
+Ajax.Responders.register(Prado.CallbackRequest.Exception);});Prado.CallbackRequest.prototype={url:window.location.href,options:{},id:null,request:null,initialize:function(id,options)
+{this.id=id;this.options=Object.extend({RequestTimeOut:30000,EnablePageStateUpdate:true,HasPriority:true,CausesValidation:true,ValidationGroup:null,PostInputs:true},options||{});},setParameter:function(value)
+{this.options['params']=value;},getParameter:function()
+{return this.options['params'];},setRequestTimeOut:function(timeout)
+{this.options['RequestTimeOut']=timeout;},getRequestTimeOut:function()
+{return this.options['RequestTimeOut'];},setCausesValidation:function(validate)
+{this.options['CausesValidation']=validate;},getCausesValidation:function()
+{return this.options['CausesValidation'];},setValidationGroup:function(group)
+{this.options['ValidationGroup']=group;},getValidationGroup:function()
+{return this.options['ValidationGroup'];},dispatch:function()
+{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;}
+if(this.options.HasPriority)
+return Prado.CallbackRequest.dispatchPriorityRequest(this);else
+return Prado.CallbackRequest.dispatchNormalRequest(this);},_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)
+{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();}}
+Prado.Callback=function(UniqueID,parameter,onSuccess,options)
+{var callback={'params':parameter||'','onSuccess':onSuccess||Prototype.emptyFunction};Object.extend(callback,options||{});request=new Prado.CallbackRequest(UniqueID,callback);request.dispatch();return false;}
+Array.prototype.______array='______array';Prado.JSON={org:'http://www.JSON.org',copyright:'(c)2005 JSON.org',license:'http://www.crockford.com/JSON/license.html',stringify:function(arg){var c,i,l,s='',v;switch(typeof arg){case'object':if(arg){if(arg.______array=='______array'){for(i=0;i<arg.length;++i){v=this.stringify(arg[i]);if(s){s+=',';}
s+=v;}
return'['+s+']';}else if(typeof arg.toString!='undefined'){for(i in arg){v=arg[i];if(typeof v!='undefined'&&typeof v!='function'){v=this.stringify(v);if(s){s+=',';}
s+=this.stringify(i)+':'+v;}}
@@ -182,118 +200,96 @@ Element.removeClassName(this.element,this.options.hoverClassName)
if(this.saving)return;this.effect=new Effect.Highlight(this.element,{startcolor:this.options.highlightcolor,endcolor:this.options.highlightendcolor,restorecolor:this.originalBackground});},leaveEditMode:function(){Element.removeClassName(this.element,this.options.savingClassName);this.removeForm();this.leaveHover();this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);if(this.options.externalControl){Element.show(this.options.externalControl);}
this.editing=false;this.saving=false;this.oldInnerHTML=null;this.onLeaveEditMode();},onComplete:function(transport){this.leaveEditMode();this.options.onComplete.bind(this)(transport,this.element);},onEnterEditMode:function(){},onLeaveEditMode:function(){},dispose:function(){if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;}
this.leaveEditMode();Event.stopObserving(this.element,'click',this.onclickListener);Event.stopObserving(this.element,'mouseover',this.mouseoverListener);Event.stopObserving(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.stopObserving(this.options.externalControl,'click',this.onclickListener);Event.stopObserving(this.options.externalControl,'mouseover',this.mouseoverListener);Event.stopObserving(this.options.externalControl,'mouseout',this.mouseoutListener);}}};Ajax.InPlaceCollectionEditor=Class.create();Object.extend(Ajax.InPlaceCollectionEditor.prototype,Ajax.InPlaceEditor.prototype);Object.extend(Ajax.InPlaceCollectionEditor.prototype,{createEditField:function(){if(!this.cached_selectTag){var selectTag=document.createElement("select");var collection=this.options.collection||[];var optionTag;collection.each(function(e,i){optionTag=document.createElement("option");optionTag.value=(e instanceof Array)?e[0]:e;if(this.options.value==optionTag.value)optionTag.selected=true;optionTag.appendChild(document.createTextNode((e instanceof Array)?e[1]:e));selectTag.appendChild(optionTag);}.bind(this));this.cached_selectTag=selectTag;}
-this.editField=this.cached_selectTag;if(this.options.loadTextURL)this.loadExternalText();this.form.appendChild(this.editField);this.options.callback=function(form,value){return"value="+encodeURIComponent(value);}}});Form.Element.DelayedObserver=Class.create();Form.Element.DelayedObserver.prototype={initialize:function(element,delay,callback){this.delay=delay||0.5;this.element=$(element);this.callback=callback;this.timer=null;this.lastValue=$F(this.element);Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));},delayedListener:function(event){if(this.lastValue==$F(this.element))return;if(this.timer)clearTimeout(this.timer);this.timer=setTimeout(this.onTimerEvent.bind(this),this.delay*1000);this.lastValue=$F(this.element);},onTimerEvent:function(){this.timer=null;this.callback(this.element,$F(this.element));}};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]||{});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);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();this.activeDraggable=draggable;},deactivate:function(){this.activeDraggable=null;},updateDrag:function(event){if(!this.activeDraggable)return;var pointer=[Event.pointerX(event),Event.pointerY(event)];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){this.observers=this.observers.reject(function(o){return o.element==element});this._cacheObserverCallbacks();},notify:function(eventName,draggable,event){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},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);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)){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);}
-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="";},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',dropOnEmpty:false,tree:false,treeTag:'ul',overlap:'vertical',constraint:'vertical',containment:element,handle:false,only:false,hoverclass:null,ghosting:false,scroll:false,scrollSensitivity:20,scrollSpeed:15,format:/^[^_]*_(.*)$/,onChange:Prototype.emptyFunction,onUpdate:Prototype.emptyFunction},arguments[1]||{});this.destroy(element);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;var options_for_droppable={overlap:options.overlap,containment:options.containment,tree:options.tree,hoverclass:options.hoverclass,onHover:Sortable.onHover}
-var options_for_tree={onHover:Sortable.onEmptyHover,overlap:options.overlap,containment:options.containment,hoverclass:options.hoverclass}
-Element.cleanWhitespace(element);options.draggables=[];options.droppables=[];if(options.dropOnEmpty||options.tree){Droppables.add(element,options_for_tree);options.droppables.push(element);}
-(this.findElements(element,options)||[]).each(function(e){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);});}
-this.sortables[element.id]=options;Draggables.addObserver(new SortableObserver(element,options.onUpdate));},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";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";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){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())}
-if(child.container)
-this._tree(child.container,options,child)
-parent.children.push(child);}
-return parent;},_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);},_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('&');}}}
-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;}
-if(!Control)var Control={};Control.Slider=Class.create();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;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;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();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);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);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];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{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);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;}}
-Prado.AutoCompleter=Class.create();Prado.AutoCompleter.Base=function(){};Prado.AutoCompleter.Base.prototype=Object.extend(Autocompleter.Base.prototype,{updateElement:function(selectedElement)
-{if(this.options.updateElement){this.options.updateElement(selectedElement);return;}
-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);}});Prado.AutoCompleter.prototype=Object.extend(new Autocompleter.Base(),{initialize:function(element,update,options)
-{this.baseInitialize(element,update,options);},onUpdateReturn:function(result)
-{if(isString(result)&&result.length>0)
-this.updateChoices(result);},getUpdatedChoices:function()
-{Prado.Callback(this.element.id,this.getToken(),this.onUpdateReturn.bind(this));}});Prado.ActivePanel={callbacks:{},register:function(id,options)
-{Prado.ActivePanel.callbacks[id]=options;},update:function(id,param)
-{var request=new Prado.ActivePanel.Request(id,Prado.ActivePanel.callbacks[id]);request.callback(param);}}
-Prado.ActivePanel.Request=Class.create();Prado.ActivePanel.Request.prototype={initialize:function(element,options)
-{this.element=element;this.setOptions(options);},setOptions:function(options)
-{this.options={onSuccess:this.onSuccess.bind(this)}
-Object.extend(this.options,options||{});},callback:function(param)
-{this.options.params=[param];new Prado.AJAX.Callback(this.element,this.options);},onSuccess:function(result,output)
-{if(this.options.update)
-{if(!this.options.evalScripts)
-output=output.stripScripts();Element.update(this.options.update,output);}}}
-Prado.DropContainer=Class.create();Prado.DropContainer.prototype=Object.extend(new Prado.ActivePanel.Request(),{initialize:function(element,options)
-{this.element=element;this.setOptions(options);Object.extend(this.options,{onDrop:this.onDrop.bind(this),evalScripts:true,onSuccess:options.onSuccess||this.onSuccess.bind(this)});Droppables.add(element,this.options);},onDrop:function(draggable,droppable)
-{this.callback(draggable.id)}});Prado.ActiveImageButton=Class.create();Prado.ActiveImageButton.prototype={initialize:function(element,options)
-{this.element=$(element);this.options=options;Event.observe(this.element,"click",this.click.bind(this));},click:function(e)
-{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);}} \ No newline at end of file
+this.editField=this.cached_selectTag;if(this.options.loadTextURL)this.loadExternalText();this.form.appendChild(this.editField);this.options.callback=function(form,value){return"value="+encodeURIComponent(value);}}});Form.Element.DelayedObserver=Class.create();Form.Element.DelayedObserver.prototype={initialize:function(element,delay,callback){this.delay=delay||0.5;this.element=$(element);this.callback=callback;this.timer=null;this.lastValue=$F(this.element);Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this));},delayedListener:function(event){if(this.lastValue==$F(this.element))return;if(this.timer)clearTimeout(this.timer);this.timer=setTimeout(this.onTimerEvent.bind(this),this.delay*1000);this.lastValue=$F(this.element);},onTimerEvent:function(){this.timer=null;this.callback(this.element,$F(this.element));}};Prado.WebUI.CallbackControl=Class.extend(Prado.WebUI.PostBackControl,{onPostBack:function(event,options)
+{request=new Prado.CallbackRequest(options.EventTarget,options);request.dispatch();Event.stop(event);}});Prado.WebUI.TActiveButton=Class.extend(Prado.WebUI.CallbackControl);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);}});Prado.WebUI.TActiveCheckBox=Class.extend(Prado.WebUI.CallbackControl,{onPostBack:function(event,options)
+{request=new Prado.CallbackRequest(options.EventTarget,options);request.dispatch();}});Prado.WebUI.TActiveRadioButton=Class.extend(Prado.WebUI.TActiveCheckBox);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);}});Prado.WebUI.TAutoComplete=Class.extend(Autocompleter.Base,Prado.WebUI.TActiveTextBox.prototype);Prado.WebUI.TAutoComplete=Class.extend(Prado.WebUI.TAutoComplete,{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)
+{if(!this.active)
+{request=new Prado.CallbackRequest(options.EventTarget,options);request.dispatch();Event.stop(event);}},onClick:function(event)
+{var element=Event.findElement(event,'LI');this.index=element.autocompleteIndex;this.selectEntry();this.hide();Event.fireEvent(this.element,"change");},getUpdatedChoices:function()
+{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.WebUI.TTimeTriggeredCallback=Base.extend({count:0,timeout:0,constructor:function(options)
+{this.options=Object.extend({Interval:1,DecayRate:0},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()
+{(this.onComplete||Prototype.emptyFunction).apply(this,arguments);this.options.onComplete=undefined;clearTimeout(this.timer);this.timer=undefined;this.count=0;},onTimerEvent:function()
+{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);}},{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;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);}});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();}},{timers:{},register:function(timer)
+{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();},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);},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()
+{Element.show(this.element);Element.hide(this.editField);},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();},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
+{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);}
+this.editField.style.display="none";this.element.parentNode.insertBefore(this.editField,this.element)
+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));},getText:function()
+{return this.element.innerHTML;},onEnterEditMode:function()
+{if(typeof(this.options.onEnterEditMode)=="function")
+this.options.onEnterEditMode(this,null);},onTextBoxBlur:function(e)
+{text=this.element.innerHTML;if(this.options.AutoPostBack&&text!=this.editField.value)
+this.onTextChanged(text);else
+{this.element.innerHTML=this.editField.value;this.isEditing=false;if(this.options.AutoHide)
+this.showLabel();}},onTextChanged:function(text)
+{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())
+{this.isSaving=true;this.editField.disabled=true;}},onLoadingText:function()
+{},onloadExternalTextSuccess:function(request,parameter)
+{this.isEditing=true;this.editField.disabled=false;this.editField.value=this.getText();Prado.Element.focus(this.editField);},onloadExternalTextFailure:function(request,parameter)
+{this.isSaving=false;this.isEditing=false;this.showLabel();},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;}}); \ No newline at end of file
diff --git a/framework/Web/Javascripts/js/compressed/prado.js b/framework/Web/Javascripts/js/compressed/prado.js
index 1ec69786..9744f6c0 100644
--- a/framework/Web/Javascripts/js/compressed/prado.js
+++ b/framework/Web/Javascripts/js/compressed/prado.js
@@ -15,7 +15,10 @@ Function.prototype.bindEvent=function()
Class.extend=function(base,definition)
{var component=Class.create();Object.extend(component.prototype,base.prototype);if(definition)
Object.extend(component.prototype,definition);return component;}
-Object.extend(String.prototype,{gsub:function(pattern,replacement){var result='',source=this,match;replacement=arguments.callee.prepareReplacement(replacement);while(source.length>0){if(match=source.match(pattern)){result+=source.slice(0,match.index);result+=(replacement(match)||'').toString();source=source.slice(match.index+match[0].length);}else{result+=source,source='';}}
+var Base=function(){if(arguments.length){if(this==window){Base.prototype.extend.call(arguments[0],arguments.callee.prototype);}else{this.extend(arguments[0]);}}};Base.version="1.0.2";Base.prototype={extend:function(source,value){var extend=Base.prototype.extend;if(arguments.length==2){var ancestor=this[source];if((ancestor instanceof Function)&&(value instanceof Function)&&ancestor.valueOf()!=value.valueOf()&&/\bbase\b/.test(value)){var method=value;value=function(){var previous=this.base;this.base=ancestor;var returnValue=method.apply(this,arguments);this.base=previous;return returnValue;};value.valueOf=function(){return method;};value.toString=function(){return String(method);};}
+return this[source]=value;}else if(source){var _prototype={toSource:null};var _protected=["toString","valueOf"];if(Base._prototyping)_protected[2]="constructor";for(var i=0;(name=_protected[i]);i++){if(source[name]!=_prototype[name]){extend.call(this,name,source[name]);}}
+for(var name in source){if(!_prototype[name]){extend.call(this,name,source[name]);}}}
+return this;},base:function(){}};Base.extend=function(_instance,_static){var extend=Base.prototype.extend;if(!_instance)_instance={};Base._prototyping=true;var _prototype=new this;extend.call(_prototype,_instance);var constructor=_prototype.constructor;_prototype.constructor=this;delete Base._prototyping;var klass=function(){if(!Base._prototyping)constructor.apply(this,arguments);this.constructor=klass;};klass.prototype=_prototype;klass.extend=this.extend;klass.implement=this.implement;klass.toString=function(){return String(constructor);};extend.call(klass,_static);var object=constructor?klass:_prototype;if(object.init instanceof Function)object.init();return object;};Base.implement=function(_interface){if(_interface instanceof Function)_interface=_interface.prototype;this.prototype.extend(_interface);};*/Object.extend(String.prototype,{gsub:function(pattern,replacement){var result='',source=this,match;replacement=arguments.callee.prepareReplacement(replacement);while(source.length>0){if(match=source.match(pattern)){result+=source.slice(0,match.index);result+=(replacement(match)||'').toString();source=source.slice(match.index+match[0].length);}else{result+=source,source='';}}
return result;},sub:function(pattern,replacement,count){replacement=this.gsub.prepareReplacement(replacement);count=count===undefined?1:count;return this.gsub(pattern,function(match){if(--count<0)return match[0];return replacement(match);});},scan:function(pattern,iterator){this.gsub(pattern,iterator);return this;},truncate:function(length,truncation){length=length||30;truncation=truncation===undefined?'...':truncation;return this.length>length?this.slice(0,length-truncation.length)+truncation:this;},strip:function(){return this.replace(/^\s+/,'').replace(/\s+$/,'');},stripTags:function(){return this.replace(/<\/?[^>]+>/gi,'');},stripScripts:function(){return this.replace(new RegExp(Prototype.ScriptFragment,'img'),'');},extractScripts:function(){var matchAll=new RegExp(Prototype.ScriptFragment,'img');var matchOne=new RegExp(Prototype.ScriptFragment,'im');return(this.match(matchAll)||[]).map(function(scriptTag){return(scriptTag.match(matchOne)||['',''])[1];});},evalScripts:function(){return this.extractScripts().map(function(script){return eval(script)});},escapeHTML:function(){var div=document.createElement('div');var text=document.createTextNode(this);div.appendChild(text);return div.innerHTML;},unescapeHTML:function(){var div=document.createElement('div');div.innerHTML=this.stripTags();return div.childNodes[0]?div.childNodes[0].nodeValue:'';},toQueryParams:function(){var pairs=this.match(/^\??(.*)$/)[1].split('&');return pairs.inject({},function(params,pairString){var pair=pairString.split('=');params[pair[0]]=pair[1];return params;});},toArray:function(){return this.split('');},camelize:function(){var oStringList=this.split('-');if(oStringList.length==1)return oStringList[0];var camelizedString=this.indexOf('-')==0?oStringList[0].charAt(0).toUpperCase()+oStringList[0].substring(1):oStringList[0];for(var i=1,len=oStringList.length;i<len;i++){var s=oStringList[i];camelizedString+=s.charAt(0).toUpperCase()+s.substring(1);}
return camelizedString;},inspect:function(){return"'"+this.replace(/\\/g,'\\\\').replace(/'/g,'\\\'')+"'";}});String.prototype.gsub.prepareReplacement=function(replacement){if(typeof replacement=='function')return replacement;var template=new Template(replacement);return function(match){return template.evaluate(match)};}
String.prototype.parseQuery=String.prototype.toQueryParams;var Template=Class.create();Template.Pattern=/(^|.|\r|\n)(#\{(.*?)\})/;Template.prototype={initialize:function(template,pattern){this.template=template.toString();this.pattern=pattern||Template.Pattern;},evaluate:function(object){return this.template.gsub(this.pattern,function(match){var before=match[1];if(before=='\\')return match[2];return before+(object[match[3]]||'').toString();});}}
@@ -49,7 +52,12 @@ results.push(iterable[i]);return results;}}
Object.extend(Array.prototype,Enumerable);if(!Array.prototype._reverse)
Array.prototype._reverse=Array.prototype.reverse;Object.extend(Array.prototype,{_each:function(iterator){for(var i=0;i<this.length;i++)
iterator(this[i]);},clear:function(){this.length=0;return this;},first:function(){return this[0];},last:function(){return this[this.length-1];},compact:function(){return this.select(function(value){return value!=undefined||value!=null;});},flatten:function(){return this.inject([],function(array,value){return array.concat(value&&value.constructor==Array?value.flatten():[value]);});},without:function(){var values=$A(arguments);return this.select(function(value){return!values.include(value);});},indexOf:function(object){for(var i=0;i<this.length;i++)
-if(this[i]==object)return i;return-1;},reverse:function(inline){return(inline!==false?this:this.toArray())._reverse();},inspect:function(){return'['+this.map(Object.inspect).join(', ')+']';}});var Hash={_each:function(iterator){for(var key in this){var value=this[key];if(typeof value=='function')continue;var pair=[key,value];pair.key=key;pair.value=value;iterator(pair);}},keys:function(){return this.pluck('key');},values:function(){return this.pluck('value');},merge:function(hash){return $H(hash).inject($H(this),function(mergedHash,pair){mergedHash[pair.key]=pair.value;return mergedHash;});},toQueryString:function(){return this.map(function(pair){return pair.map(encodeURIComponent).join('=');}).join('&');},inspect:function(){return'#<Hash:{'+this.map(function(pair){return pair.map(Object.inspect).join(': ');}).join(', ')+'}>';}}
+if(this[i]==object)return i;return-1;},reverse:function(inline){return(inline!==false?this:this.toArray())._reverse();},inspect:function(){return'['+this.map(Object.inspect).join(', ')+']';}});var Hash={_each:function(iterator){for(var key in this){var value=this[key];if(typeof value=='function')continue;var pair=[key,value];pair.key=key;pair.value=value;iterator(pair);}},keys:function(){return this.pluck('key');},values:function(){return this.pluck('value');},merge:function(hash){return $H(hash).inject($H(this),function(mergedHash,pair){mergedHash[pair.key]=pair.value;return mergedHash;});},toQueryString:function(){return this.map(function(pair)
+{if(typeof(pair[1])=='object'||typeof(pair[1])=='array')
+{return $A(pair[1]).collect(function(value)
+{return encodeURIComponent(pair[0])+'='+encodeURIComponent(value);}).join('&');}
+else
+return pair.map(encodeURIComponent).join('=');}).join('&');},inspect:function(){return'#<Hash:{'+this.map(function(pair){return pair.map(Object.inspect).join(': ');}).join(', ')+'}>';}}
function $H(object){var hash=Object.extend({},object||{});Object.extend(hash,Enumerable);Object.extend(hash,Hash);return hash;}
ObjectRange=Class.create();Object.extend(ObjectRange.prototype,Enumerable);Object.extend(ObjectRange.prototype,{initialize:function(start,end,exclusive){this.start=start;this.end=end;this.exclusive=exclusive;},_each:function(iterator){var value=this.start;do{iterator(value);value=value.succ();}while(this.include(value));},include:function(value){if(value<this.start)
return false;if(this.exclusive)
@@ -97,7 +105,8 @@ return matchingInputs;},disable:function(form){var elements=Form.getElements(for
Form.Element={serialize:function(element){element=$(element);var method=element.tagName.toLowerCase();var parameter=Form.Element.Serializers[method](element);if(parameter){var key=encodeURIComponent(parameter[0]);if(key.length==0)return;if(parameter[1].constructor!=Array)
parameter[1]=[parameter[1]];return parameter[1].map(function(value){return key+'='+encodeURIComponent(value);}).join('&');}},getValue:function(element){element=$(element);var method=element.tagName.toLowerCase();var parameter=Form.Element.Serializers[method](element);if(parameter)
return parameter[1];}}
-Form.Element.Serializers={input:function(element){switch(element.type.toLowerCase()){case'submit':case'hidden':case'password':case'text':return Form.Element.Serializers.textarea(element);case'checkbox':case'radio':return Form.Element.Serializers.inputSelector(element);}
+Form.Element.Serializers={input:function(element){if(typeof(element.type)=="undefined")
+return false;switch(element.type.toLowerCase()){case'submit':case'hidden':case'password':case'text':return Form.Element.Serializers.textarea(element);case'checkbox':case'radio':return Form.Element.Serializers.inputSelector(element);}
return false;},inputSelector:function(element){if(element.checked)
return[element.name,element.value];},textarea:function(element){return[element.name,element.value];},select:function(element){return Form.Element.Serializers[element.type=='select-one'?'selectOne':'selectMany'](element);},selectOne:function(element){var value='',opt,index=element.selectedIndex;if(index>=0){opt=element.options[index];value=opt.value||opt.text;}
return[element.name,value];},selectMany:function(element){var value=[];for(var i=0;i<element.length;i++){var opt=element.options[i];if(opt.selected)
@@ -246,51 +255,99 @@ lastFocus.value=options['EventTarget'];}}
$('PRADO_POSTBACK_TARGET').value=options['EventTarget'];$('PRADO_POSTBACK_PARAMETER').value=options['EventParameter'];Event.stop(event);Event.fireEvent(form,"submit");}
Prado.Element={setValue:function(element,value)
{var el=$(element);if(el&&typeof(el.value)!="undefined")
-el.value=value;},select:function(element,method,value)
-{var el=$(element);var isList=element.indexOf('[]')>-1;if(!el&&!isList)return;method=isList?'check'+method:el.tagName.toLowerCase()+method;var selection=Prado.Element.Selection;if(isFunction(selection[method]))
-selection[method](isList?element:el,value);},click:function(element)
+el.value=value;},select:function(element,method,value,total)
+{var el=$(element);var selection=Prado.Element.Selection;if(typeof(selection[method])=="function")
+{control=selection.isSelectable(el)?[el]:selection.getListElements(element,total);selection[method](control,value);}},click:function(element)
{var el=$(element);if(el)
Event.fireEvent(el,'click');},setAttribute:function(element,attribute,value)
-{var el=$(element);if(attribute=="disabled"&&value==false)
-el.removeAttribute(attribute);else
+{var el=$(element);if((attribute=="disabled"||attribute=="multiple")&&value==false)
+el.removeAttribute(attribute);else if(attribute.match(/^on/i))
+{try
+{eval("(func = function(event){"+value+"})");el[attribute]=func;}
+catch(e)
+{throw"Error in evaluating '"+value+"' for attribute "+attribute+" for element "+element.id;}}
+else
el.setAttribute(attribute,value);},setOptions:function(element,options)
{var el=$(element);if(el&&el.tagName.toLowerCase()=="select")
-{while(el.length>0)
-el.remove(0);for(var i=0;i<options.length;i++)
-el.options[el.options.length]=new Option(options[i][0],options[i][1]);}},focus:function(element)
+{el.options.length=options.length;for(var i=0;i<options.length;i++)
+el.options[i]=new Option(options[i][0],options[i][1]);}},focus:function(element)
{var obj=$(element);if(typeof(obj)!="undefined"&&typeof(obj.focus)!="undefined")
-setTimeout(function(){obj.focus();},100);return false;}}
-Prado.Element.Selection={inputValue:function(el,value)
+setTimeout(function(){obj.focus();},100);return false;},replace:function(element,method,content,boundary,transport)
+{if(boundary)
+{result=Prado.Element.extractContent(transport.responseText,boundary);if(result!=null)
+content=result;}
+if(typeof(element)=="string")
+{if($(element))
+method.toFunction().apply(this,[element,content]);}
+else
+{method.toFunction().apply(this,[content]);}},extractContent:function(text,boundary)
+{f=RegExp('(<!--'+boundary+'-->)([\\s\\S\\w\\W]*)(<!--//'+boundary+'-->)',"m");result=text.match(f);if(result&&result.length>=2)
+return result[2];else
+return null;},evaluateScript:function(content)
+{content.evalScripts();}}
+Prado.Element.Selection={isSelectable:function(el)
+{if(el&&el.type)
{switch(el.type.toLowerCase())
-{case'checkbox':case'radio':return el.checked=value;}},selectValue:function(el,value)
+{case'checkbox':case'radio':case'select':case'select-multiple':case'select-one':return true;}}
+return false;},inputValue:function(el,value)
+{switch(el.type.toLowerCase())
+{case'checkbox':case'radio':return el.checked=value;}},selectValue:function(elements,value)
+{elements.each(function(el)
{$A(el.options).each(function(option)
-{option.selected=option.value==value;});},selectIndex:function(el,index)
-{if(el.type=='select-one')
+{if(typeof(value)=="boolean")
+options.selected=value;else if(option.value==value)
+option.selected=true;});})},selectValues:function(elements,values)
+{selection=this;values.each(function(value)
+{selection.selectValue(elements,value);})},selectIndex:function(elements,index)
+{elements.each(function(el)
+{if(el.type.toLowerCase()=='select-one')
el.selectedIndex=index;else
{for(var i=0;i<el.length;i++)
{if(i==index)
-el.options[i].selected=true;}}},selectClear:function(el)
-{el.selectedIndex=-1;},selectAll:function(el)
+el.options[i].selected=true;}}})},selectAll:function(elements)
+{elements.each(function(el)
+{if(el.type.toLowerCase()!='select-one')
{$A(el.options).each(function(option)
-{option.selected=true;Logger.warn(option.value);});},selectInvert:function(el)
+{option.selected=true;})}})},selectInvert:function(elements)
+{elements.each(function(el)
+{if(el.type.toLowerCase()!='select-one')
{$A(el.options).each(function(option)
-{option.selected=!option.selected;});},checkValue:function(name,value)
-{$A(document.getElementsByName(name)).each(function(el)
-{el.checked=el.value==value});},checkIndex:function(name,index)
-{var elements=$A(document.getElementsByName(name));for(var i=0;i<elements.length;i++)
+{option.selected=!options.selected;})}})},selectIndices:function(elements,indices)
+{selection=this;indices.each(function(index)
+{selection.selectIndex(elements,index);})},selectClear:function(elements)
+{elements.each(function(el)
+{el.selectedIndex=-1;})},getListElements:function(element,total)
+{elements=new Array();for(i=0;i<total;i++)
+{el=$(element+"_c"+i);if(el)
+elements.push(el);}
+return elements;},checkValue:function(elements,value)
+{elements.each(function(el)
+{if(typeof(value)=="boolean")
+el.checked=value;else if(el.value==value)
+el.checked=true;});},checkValues:function(elements,values)
+{selection=this;values.each(function(value)
+{selection.checkValue(elements,value);})},checkIndex:function(elements,index)
+{for(var i=0;i<elements.length;i++)
{if(i==index)
-elements[i].checked=true;}},checkClear:function(name)
-{$A(document.getElementsByName(name)).each(function(el)
-{el.checked=false;});},checkAll:function(name)
-{$A(document.getElementsByName(name)).each(function(el)
-{el.checked=true;});},checkInvert:function(name)
-{$A(document.getElementsByName(name)).each(function(el)
-{el.checked=!el.checked;});}};Prado.WebUI=Class.create();Prado.WebUI.PostBackControl=Class.create();Prado.WebUI.PostBackControl.prototype={_elementOnClick:null,initialize:function(options)
+elements[i].checked=true;}},checkIndices:function(elements,indices)
+{selection=this;indices.each(function(index)
+{selection.checkIndex(elements,index);})},checkClear:function(elements)
+{elements.each(function(el)
+{el.checked=false;});},checkAll:function(elements)
+{elements.each(function(el)
+{el.checked=true;})},checkInvert:function(elements)
+{elements.each(function(el)
+{el.checked!=el.checked;})}};Prado.Element.Insert={append:function(element,content)
+{new Insertion.Bottom(element,content);},prepend:function(element,content)
+{new Insertion.Top(element,content);},after:function(element,content)
+{new Insertion.After(element,content);},before:function(element,content)
+{new Insertion.Before(element,content);}}
+Prado.WebUI=Class.create();Prado.WebUI.PostBackControl=Class.create();Prado.WebUI.PostBackControl.prototype={_elementOnClick:null,initialize:function(options)
{this.element=$(options.ID);if(this.onInit)
this.onInit(options);},onInit:function(options)
{if(typeof(this.element.onclick)=="function")
{this._elementOnClick=this.element.onclick;this.element.onclick=null;}
-Event.observe(this.element,"click",this.onClick.bindEvent(this,options));},onClick:function(event,options)
+Event.observe(this.element,"click",this.elementClicked.bindEvent(this,options));},elementClicked:function(event,options)
{var src=Event.element(event);var doPostBack=true;var onclicked=null;if(this._elementOnClick)
{var onclicked=this._elementOnClick(event);if(typeof(onclicked)=="boolean")
doPostBack=onclicked;}
@@ -301,7 +358,14 @@ Event.stop(event);},onPostBack:function(event,options)
{if(!this.hasXYInput)
{this.addXYInput(event,options);this.hasXYInput=true;}
Prado.PostBack(event,options);},addXYInput:function(event,options)
-{var imagePos=Position.cumulativeOffset(this.element);var clickedPos=[event.clientX,event.clientY];var x=clickedPos[0]-imagePos[0]+1;var y=clickedPos[1]-imagePos[1]+1;var id=options['EventTarget'];var x_input=INPUT({type:'hidden',name:id+'_x',value:x});var y_input=INPUT({type:'hidden',name:id+'_y',value:y});this.element.parentNode.appendChild(x_input);this.element.parentNode.appendChild(y_input);}});Prado.WebUI.TRadioButton=Class.extend(Prado.WebUI.PostBackControl);Prado.WebUI.TRadioButton.prototype.onRadioButtonInitialize=Prado.WebUI.TRadioButton.prototype.initialize;Object.extend(Prado.WebUI.TRadioButton.prototype,{initialize:function(options)
+{imagePos=Position.cumulativeOffset(this.element);clickedPos=[event.clientX,event.clientY];x=clickedPos[0]-imagePos[0]+1;y=clickedPos[1]-imagePos[1]+1;x=x<0?0:x;y=y<0?0:y;id=options['EventTarget'];x_input=$(id+"_x");y_input=$(id+"_y");if(x_input)
+{x_input.value=x;}
+else
+{x_input=INPUT({type:'hidden',name:id+'_x','id':id+'_x',value:x});this.element.parentNode.appendChild(x_input);}
+if(y_input)
+{y_input.value=y;}
+else
+{y_input=INPUT({type:'hidden',name:id+'_y','id':id+'_y',value:y});this.element.parentNode.appendChild(y_input);}}});Prado.WebUI.TRadioButton=Class.extend(Prado.WebUI.PostBackControl);Prado.WebUI.TRadioButton.prototype.onRadioButtonInitialize=Prado.WebUI.TRadioButton.prototype.initialize;Object.extend(Prado.WebUI.TRadioButton.prototype,{initialize:function(options)
{this.element=$(options['ID']);if(!this.element.checked)
this.onRadioButtonInitialize(options);}});Prado.WebUI.TTextBox=Class.extend(Prado.WebUI.PostBackControl,{onInit:function(options)
{if(options['TextMode']!='MultiLine')
diff --git a/framework/Web/Javascripts/js/compressed/validator.js b/framework/Web/Javascripts/js/compressed/validator.js
index d3d8c53e..037abfeb 100644
--- a/framework/Web/Javascripts/js/compressed/validator.js
+++ b/framework/Web/Javascripts/js/compressed/validator.js
@@ -3,7 +3,8 @@ Prado.Validation=Class.create();Object.extend(Prado.Validation,{managers:{},vali
{if(this.managers[formID])
{return this.managers[formID].validate(groupID,invoker);}
else
-{throw new Error("Form '"+form+"' is not registered with Prado.Validation");}},isValid:function(formID,groupID)
+{throw new Error("Form '"+form+"' is not registered with Prado.Validation");}},getForm:function()
+{var keys=$H(this.managers).keys();return keys[0];},isValid:function(formID,groupID)
{if(this.managers[formID])
return this.managers[formID].isValid(groupID);return true;},addValidator:function(formID,validator)
{if(this.managers[formID])
@@ -94,7 +95,10 @@ Prado.Element.focus(this.options.FocusElementID);this.visible=true;},updateContr
control.removeClassName(CssClass);else
control.addClassName(CssClass);}},hide:function()
{this.isValid=true;this.updateControl();this.visible=false;},validate:function(invoker)
-{if(typeof(this.options.OnValidate)=="function")
+{if(!this.control)
+this.control=$(this.options.ControlToValidate);if(!this.control)
+{this.isValid=true;return this.isValid;}
+if(typeof(this.options.OnValidate)=="function")
this.options.OnValidate(this,invoker);if(this.enabled)
this.isValid=this.evaluateIsValid();else
this.isValid=true;if(this.isValid)
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;
+ }
+});
diff --git a/framework/Web/Javascripts/js/debug/prado.js b/framework/Web/Javascripts/js/debug/prado.js
index 9a610de9..736a7f7e 100644
--- a/framework/Web/Javascripts/js/debug/prado.js
+++ b/framework/Web/Javascripts/js/debug/prado.js
@@ -131,10 +131,10 @@ PeriodicalExecuter.prototype = {
/**
* Similar to bindAsEventLister, but takes additional arguments.
*/
-Function.prototype.bindEvent = function()
+Function.prototype.bindEvent = function()
{
var __method = this, args = $A(arguments), object = args.shift();
- return function(event)
+ return function(event)
{
return __method.apply(object, [event || window.event].concat(args));
}
@@ -152,10 +152,315 @@ Class.extend = function(base, definition)
{
var component = Class.create();
Object.extend(component.prototype, base.prototype);
- if(definition)
+ if(definition)
Object.extend(component.prototype, definition);
return component;
-}
+}
+
+/*
+ Base, version 1.0.2
+ Copyright 2006, Dean Edwards
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+var Base = function() {
+ if (arguments.length) {
+ if (this == window) { // cast an object to this class
+ Base.prototype.extend.call(arguments[0], arguments.callee.prototype);
+ } else {
+ this.extend(arguments[0]);
+ }
+ }
+};
+
+Base.version = "1.0.2";
+
+Base.prototype = {
+ extend: function(source, value) {
+ var extend = Base.prototype.extend;
+ if (arguments.length == 2) {
+ var ancestor = this[source];
+ // overriding?
+ if ((ancestor instanceof Function) && (value instanceof Function) &&
+ ancestor.valueOf() != value.valueOf() && /\bbase\b/.test(value)) {
+ var method = value;
+ // var _prototype = this.constructor.prototype;
+ // var fromPrototype = !Base._prototyping && _prototype[source] == ancestor;
+ value = function() {
+ var previous = this.base;
+ // this.base = fromPrototype ? _prototype[source] : ancestor;
+ this.base = ancestor;
+ var returnValue = method.apply(this, arguments);
+ this.base = previous;
+ return returnValue;
+ };
+ // point to the underlying method
+ value.valueOf = function() {
+ return method;
+ };
+ value.toString = function() {
+ return String(method);
+ };
+ }
+ return this[source] = value;
+ } else if (source) {
+ var _prototype = {toSource: null};
+ // do the "toString" and other methods manually
+ var _protected = ["toString", "valueOf"];
+ // if we are prototyping then include the constructor
+ if (Base._prototyping) _protected[2] = "constructor";
+ for (var i = 0; (name = _protected[i]); i++) {
+ if (source[name] != _prototype[name]) {
+ extend.call(this, name, source[name]);
+ }
+ }
+ // copy each of the source object's properties to this object
+ for (var name in source) {
+ if (!_prototype[name]) {
+ extend.call(this, name, source[name]);
+ }
+ }
+ }
+ return this;
+ },
+
+ base: function() {
+ // call this method from any other method to invoke that method's ancestor
+ }
+};
+
+Base.extend = function(_instance, _static) {
+ var extend = Base.prototype.extend;
+ if (!_instance) _instance = {};
+ // build the prototype
+ Base._prototyping = true;
+ var _prototype = new this;
+ extend.call(_prototype, _instance);
+ var constructor = _prototype.constructor;
+ _prototype.constructor = this;
+ delete Base._prototyping;
+ // create the wrapper for the constructor function
+ var klass = function() {
+ if (!Base._prototyping) constructor.apply(this, arguments);
+ this.constructor = klass;
+ };
+ klass.prototype = _prototype;
+ // build the class interface
+ klass.extend = this.extend;
+ klass.implement = this.implement;
+ klass.toString = function() {
+ return String(constructor);
+ };
+ extend.call(klass, _static);
+ // single instance
+ var object = constructor ? klass : _prototype;
+ // class initialisation
+ if (object.init instanceof Function) object.init();
+ return object;
+};
+
+Base.implement = function(_interface) {
+ if (_interface instanceof Function) _interface = _interface.prototype;
+ this.prototype.extend(_interface);
+};
+
+/*
+ * Signals and Slots for Prototype: Easy custom javascript events
+ * http://tetlaw.id.au/view/blog/signals-and-slots-for-prototype-easy-custom-javascript-events
+ * Andrew Tetlaw
+ * Version 1.2 (2006-06-19)
+ *
+ * http://creativecommons.org/licenses/by-sa/2.5/
+ *
+Signal = {
+ throwErrors : true,
+ MT : function(){ return true },
+ connect : function(obj1, func1, obj2, func2, options) {
+ var options = Object.extend({
+ connectOnce : false,
+ before : false,
+ mutate : function() {return arguments;}
+ }, options || {});
+ if(typeof func1 != 'string' || typeof func2 != 'string') return;
+
+ var sigObj = obj1 || window;
+ var slotObj = obj2 || window;
+ var signame = func1+'__signal_';
+ var slotsname = func1+'__slots_';
+ if(!sigObj[signame]) {
+ // having the slotFunc in a var and setting it by using an anonymous function in this way
+ // is apparently a good way to prevent memory leaks in IE if the objects are DOM nodes.
+ var slotFunc = function() {
+ var args = [];
+ for(var x = 0; x < arguments.length; x++){
+ args.push(arguments[x]);
+ }
+ args = options.mutate.apply(null,args)
+ var result;
+ if(!options.before) result = sigObj[signame].apply(sigObj,arguments); //default: call sign before slot
+ sigObj[slotsname].each(function(slot){
+ try {
+ if(slot && slot[0]) { // testing for null, a disconnect may have nulled this slot
+ slot[0][slot[1]].apply(slot[0],args); //[0] = obj, [1] = func name
+ }
+ } catch(e) {
+ if(Signal.throwErrors) throw e;
+ }
+ });
+ if(options.before) result = sigObj[signame].apply(sigObj,arguments); //call slot before sig
+ return result; //return sig result
+ };
+ (function() {
+ sigObj[slotsname] = $A([]);
+ sigObj[signame] = sigObj[func1] || Signal.MT;
+ sigObj[func1] = slotFunc;
+ })();
+ }
+ var con = (sigObj[slotsname].length > 0) ?
+ (options.connectOnce ? !sigObj[slotsname].any(function(slot) { return (slot[0] == slotObj && slot[1] == func2) }) : true) :
+ true;
+ if(con) {
+ sigObj[slotsname].push([slotObj,func2]);
+ }
+ },
+ connectOnce : function(obj1, func1, obj2, func2, options) {
+ Signal.connect(obj1, func1, obj2, func2, Object.extend(options || {}, {connectOnce : true}))
+ },
+ disconnect : function(obj1, func1, obj2, func2, options) {
+ var options = Object.extend({
+ disconnectAll : false
+ }, options || {});
+ if(typeof func1 != 'string' || typeof func2 != 'string') return;
+
+ var sigObj = obj1 || window;
+ var slotObj = obj2 || window;
+ var signame = func1+'__signal_';
+ var slotsname = func1+'__slots_';
+
+ // I null them in this way so that any currectly active signal will read a null slot,
+ // otherwise the slot will be applied even though it's been disconnected
+ if(sigObj[slotsname]) {
+ if(options.disconnectAll) {
+ sigObj[slotsname] = sigObj[slotsname].collect(function(slot) {
+ if(slot[0] == slotObj && slot[1] == func2) {
+ slot[0] = null;
+ return null;
+ } else {
+ return slot;
+ }
+ }).compact();
+ } else {
+ var idx = -1;
+ sigObj[slotsname] = sigObj[slotsname].collect(function(slot, index) {
+ if(slot[0] == slotObj && slot[1] == func2 && idx < 0) { //disconnect first match
+ idx = index;
+ slot[0] = null;
+ return null;
+ } else {
+ return slot;
+ }
+ }).compact();
+ }
+ }
+ },
+ disconnectAll : function(obj1, func1, obj2, func2, options) {
+ Signal.disconnect(obj1, func1, obj2, func2, Object.extend(options || {}, {disconnectAll : true}))
+ }
+}
+*/
+
+/*
+ Tests
+
+// 1. Simple Test 1 "hello Fred" should trigger "Fred is a stupid head"
+
+
+ sayHello = function(n) {
+ alert("Hello! " + n);
+ }
+ moron = function(n) {
+ alert(n + " is a stupid head");
+ }
+ Signal.connect(null,'sayHello',null,'moron');
+
+ onclick="sayHello('Fred')"
+
+
+// 2. Simple Test 2 repeated insults about Fred
+
+
+ Signal.connect(null,'sayHello2',null,'moron2');
+ Signal.connect(null,'sayHello2',null,'moron2');
+ Signal.connect(null,'sayHello2',null,'moron2');
+
+
+// 3. Simple Test 3 multiple insults about Fred
+
+
+ Signal.connect(null,'sayHello3',null,'moron3');
+ Signal.connect(null,'sayHello3',null,'bonehead3');
+ Signal.connect(null,'sayHello3',null,'idiot3');
+
+
+// 4. Simple Test 4 3 insults about Fred first - 3 then none
+
+
+ Signal.connect(null,'sayHello4',null,'moron4');
+ Signal.connect(null,'sayHello4',null,'moron4');
+ Signal.connect(null,'sayHello4',null,'moron4');
+ Signal.disconnect(null,'sayHello4',null,'moron4');
+ Signal.disconnect(null,'sayHello4',null,'moron4');
+ Signal.disconnect(null,'sayHello4',null,'moron4');
+
+
+// 5. Simple Test 5 connect 3 insults about Fred first - only one, then none
+
+
+ Signal.connect(null,'sayHello5',null,'moron5');
+ Signal.connect(null,'sayHello5',null,'moron5');
+ Signal.connect(null,'sayHello5',null,'moron5');
+ Signal.disconnectAll(null,'sayHello5',null,'moron5');
+
+
+// 6. Simple Test 6 connect 3 insults but only one comes out
+
+
+ Signal.connectOnce(null,'sayHello6',null,'moron6');
+ Signal.connectOnce(null,'sayHello6',null,'moron6');
+ Signal.connectOnce(null,'sayHello6',null,'moron6');
+
+
+// 7. Simple Test 7 connect via objects
+
+
+ var o = {};
+ o.sayHello = function(n) {
+ alert("Hello! " + n + " (from object o)");
+ }
+ var m = {};
+ m.moron = function(n) {
+ alert(n + " is a stupid head (from object m)");
+ }
+
+ Signal.connect(o,'sayHello',m,'moron');
+
+ onclick="o.sayHello('Fred')"
+
+
+// 8. Simple Test 8 connect but the insult comes first using {before:true}
+
+
+ Signal.connect(null,'sayHello8',null,'moron8', {before:true});
+
+
+// 9. Simple Test 9 connect but the insult is mutated
+
+
+ Signal.connect(null,'sayHello9',null,'moron9', {mutate:function() { return ['smelly ' + arguments[0]] }});
+
+
+*/
+ */
Object.extend(String.prototype, {
gsub: function(pattern, replacement) {
@@ -726,35 +1031,45 @@ var Hash = {
for (var key in this) {
var value = this[key];
if (typeof value == 'function') continue;
-
+
var pair = [key, value];
pair.key = key;
pair.value = value;
iterator(pair);
}
},
-
+
keys: function() {
return this.pluck('key');
},
-
+
values: function() {
return this.pluck('value');
},
-
+
merge: function(hash) {
return $H(hash).inject($H(this), function(mergedHash, pair) {
mergedHash[pair.key] = pair.value;
return mergedHash;
});
},
-
+
toQueryString: function() {
- return this.map(function(pair) {
- return pair.map(encodeURIComponent).join('=');
+ return this.map(function(pair)
+ {
+ //special case for PHP, array post data.
+ if(typeof(pair[1]) == 'object' || typeof(pair[1]) == 'array')
+ {
+ return $A(pair[1]).collect(function(value)
+ {
+ return encodeURIComponent(pair[0])+'='+encodeURIComponent(value);
+ }).join('&');
+ }
+ else
+ return pair.map(encodeURIComponent).join('=');
}).join('&');
},
-
+
inspect: function() {
return '#<Hash:{' + this.map(function(pair) {
return pair.map(Object.inspect).join(': ');
@@ -1209,17 +1524,17 @@ var Field = {
focus: function(element) {
$(element).focus();
},
-
+
present: function() {
for (var i = 0; i < arguments.length; i++)
if ($(arguments[i]).value == '') return false;
return true;
},
-
+
select: function(element) {
$(element).select();
},
-
+
activate: function(element) {
element = $(element);
element.focus();
@@ -1234,16 +1549,16 @@ var Form = {
serialize: function(form) {
var elements = Form.getElements($(form));
var queryComponents = new Array();
-
+
for (var i = 0; i < elements.length; i++) {
var queryComponent = Form.Element.serialize(elements[i]);
if (queryComponent)
queryComponents.push(queryComponent);
}
-
+
return queryComponents.join('&');
},
-
+
getElements: function(form) {
form = $(form);
var elements = new Array();
@@ -1255,19 +1570,19 @@ var Form = {
}
return elements;
},
-
+
getInputs: function(form, typeName, name) {
form = $(form);
var inputs = form.getElementsByTagName('input');
-
+
if (!typeName && !name)
return inputs;
-
+
var matchingInputs = new Array();
for (var i = 0; i < inputs.length; i++) {
var input = inputs[i];
if ((typeName && input.type != typeName) ||
- (name && input.name != name))
+ (name && input.name != name))
continue;
matchingInputs.push(input);
}
@@ -1313,25 +1628,25 @@ Form.Element = {
element = $(element);
var method = element.tagName.toLowerCase();
var parameter = Form.Element.Serializers[method](element);
-
+
if (parameter) {
var key = encodeURIComponent(parameter[0]);
if (key.length == 0) return;
-
+
if (parameter[1].constructor != Array)
parameter[1] = [parameter[1]];
-
+
return parameter[1].map(function(value) {
return key + '=' + encodeURIComponent(value);
}).join('&');
}
},
-
+
getValue: function(element) {
element = $(element);
var method = element.tagName.toLowerCase();
var parameter = Form.Element.Serializers[method](element);
-
+
if (parameter)
return parameter[1];
}
@@ -1339,13 +1654,15 @@ Form.Element = {
Form.Element.Serializers = {
input: function(element) {
+ if(typeof(element.type) == "undefined")
+ return false;
switch (element.type.toLowerCase()) {
case 'submit':
case 'hidden':
case 'password':
case 'text':
return Form.Element.Serializers.textarea(element);
- case 'checkbox':
+ case 'checkbox':
case 'radio':
return Form.Element.Serializers.inputSelector(element);
}
@@ -1360,12 +1677,12 @@ Form.Element.Serializers = {
textarea: function(element) {
return [element.name, element.value];
},
-
+
select: function(element) {
- return Form.Element.Serializers[element.type == 'select-one' ?
+ return Form.Element.Serializers[element.type == 'select-one' ?
'selectOne' : 'selectMany'](element);
},
-
+
selectOne: function(element) {
var value = '', opt, index = element.selectedIndex;
if (index >= 0) {
@@ -1374,7 +1691,7 @@ Form.Element.Serializers = {
}
return [element.name, value];
},
-
+
selectMany: function(element) {
var value = [];
for (var i = 0; i < element.length; i++) {
@@ -1398,15 +1715,15 @@ Abstract.TimedObserver.prototype = {
this.frequency = frequency;
this.element = $(element);
this.callback = callback;
-
+
this.lastValue = this.getValue();
this.registerCallback();
},
-
+
registerCallback: function() {
setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
-
+
onTimerEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
@@ -1437,14 +1754,14 @@ Abstract.EventObserver.prototype = {
initialize: function(element, callback) {
this.element = $(element);
this.callback = callback;
-
+
this.lastValue = this.getValue();
if (this.element.tagName.toLowerCase() == 'form')
this.registerFormCallbacks();
else
this.registerCallback(this.element);
},
-
+
onElementEvent: function() {
var value = this.getValue();
if (this.lastValue != value) {
@@ -1452,17 +1769,17 @@ Abstract.EventObserver.prototype = {
this.lastValue = value;
}
},
-
+
registerFormCallbacks: function() {
var elements = Form.getElements(this.element);
for (var i = 0; i < elements.length; i++)
this.registerCallback(elements[i]);
},
-
+
registerCallback: function(element) {
if (element.type) {
switch (element.type.toLowerCase()) {
- case 'checkbox':
+ case 'checkbox':
case 'radio':
Event.observe(element, 'click', this.onElementEvent.bind(this));
break;
@@ -1474,7 +1791,7 @@ Abstract.EventObserver.prototype = {
Event.observe(element, 'change', this.onElementEvent.bind(this));
break;
}
- }
+ }
}
}
@@ -2600,7 +2917,7 @@ Prado.doPostBack = function(formID, eventTarget, eventParameter, performValidati
}
*/
-Prado.Element =
+Prado.Element =
{
/**
* Set the value of a particular element.
@@ -2614,29 +2931,41 @@ Prado.Element =
el.value = value;
},
- select : function(element, method, value)
+ select : function(element, method, value, total)
{
var el = $(element);
- var isList = element.indexOf('[]') > -1;
- if(!el && !isList) return;
- method = isList ? 'check'+method : el.tagName.toLowerCase()+method;
var selection = Prado.Element.Selection;
- if(isFunction(selection[method]))
- selection[method](isList ? element : el,value);
+ if(typeof(selection[method]) == "function")
+ {
+ control = selection.isSelectable(el) ? [el] : selection.getListElements(element,total);
+ selection[method](control, value);
+ }
},
click : function(element)
{
var el = $(element);
- if(el)
+ if(el)
Event.fireEvent(el,'click');
},
-
+
setAttribute : function(element, attribute, value)
{
var el = $(element);
- if(attribute == "disabled" && value==false)
+ if((attribute == "disabled" || attribute == "multiple") && value==false)
el.removeAttribute(attribute);
+ else if(attribute.match(/^on/i)) //event methods
+ {
+ try
+ {
+ eval("(func = function(event){"+value+"})");
+ el[attribute] = func;
+ }
+ catch(e)
+ {
+ throw "Error in evaluating '"+value+"' for attribute "+attribute+" for element "+element.id;
+ }
+ }
else
el.setAttribute(attribute, value);
},
@@ -2646,10 +2975,9 @@ Prado.Element =
var el = $(element);
if(el && el.tagName.toLowerCase() == "select")
{
- while(el.length > 0)
- el.remove(0);
+ el.options.length = options.length;
for(var i = 0; i<options.length; i++)
- el.options[el.options.length] = new Option(options[i][0],options[i][1]);
+ el.options[i] = new Option(options[i][0],options[i][1]);
}
},
@@ -2663,76 +2991,191 @@ Prado.Element =
if(typeof(obj) != "undefined" && typeof(obj.focus) != "undefined")
setTimeout(function(){ obj.focus(); }, 100);
return false;
+ },
+
+ replace : function(element, method, content, boundary, transport)
+ {
+ if(boundary)
+ {
+ result = Prado.Element.extractContent(transport.responseText, boundary);
+ if(result != null)
+ content = result;
+ }
+ if(typeof(element) == "string")
+ {
+ if($(element))
+ method.toFunction().apply(this,[element,content]);
+ }
+ else
+ {
+ method.toFunction().apply(this,[content]);
+ }
+ },
+
+ extractContent : function(text, boundary)
+ {
+ f = RegExp('(<!--'+boundary+'-->)([\\s\\S\\w\\W]*)(<!--//'+boundary+'-->)',"m");
+ result = text.match(f);
+ if(result && result.length >= 2)
+ return result[2];
+ else
+ return null;
+ },
+
+ evaluateScript : function(content)
+ {
+ content.evalScripts();
}
}
-Prado.Element.Selection =
+Prado.Element.Selection =
{
+ isSelectable : function(el)
+ {
+ if(el && el.type)
+ {
+ switch(el.type.toLowerCase())
+ {
+ case 'checkbox':
+ case 'radio':
+ case 'select':
+ case 'select-multiple':
+ case 'select-one':
+ return true;
+ }
+ }
+ return false;
+ },
+
inputValue : function(el, value)
{
- switch(el.type.toLowerCase())
+ switch(el.type.toLowerCase())
{
- case 'checkbox':
+ case 'checkbox':
case 'radio':
return el.checked = value;
}
},
- selectValue : function(el, value)
+ selectValue : function(elements, value)
{
- $A(el.options).each(function(option)
+ elements.each(function(el)
{
- option.selected = option.value == value;
- });
+ $A(el.options).each(function(option)
+ {
+ if(typeof(value) == "boolean")
+ options.selected = value;
+ else if(option.value == value)
+ option.selected = true;
+ });
+ })
},
- selectIndex : function(el, index)
+ selectValues : function(elements, values)
{
- if(el.type == 'select-one')
- el.selectedIndex = index;
- else
+ selection = this;
+ values.each(function(value)
+ {
+ selection.selectValue(elements,value);
+ })
+ },
+
+ selectIndex : function(elements, index)
+ {
+ elements.each(function(el)
{
- for(var i = 0; i<el.length; i++)
+ if(el.type.toLowerCase() == 'select-one')
+ el.selectedIndex = index;
+ else
{
- if(i == index)
- el.options[i].selected = true;
+ for(var i = 0; i<el.length; i++)
+ {
+ if(i == index)
+ el.options[i].selected = true;
+ }
}
- }
+ })
},
- selectClear : function(el)
+ selectAll : function(elements)
{
- el.selectedIndex = -1;
+ elements.each(function(el)
+ {
+ if(el.type.toLowerCase() != 'select-one')
+ {
+ $A(el.options).each(function(option)
+ {
+ option.selected = true;
+ })
+ }
+ })
},
- selectAll : function(el)
+ selectInvert : function(elements)
{
- $A(el.options).each(function(option)
+ elements.each(function(el)
{
- option.selected = true;
- Logger.warn(option.value);
- });
+ if(el.type.toLowerCase() != 'select-one')
+ {
+ $A(el.options).each(function(option)
+ {
+ option.selected = !options.selected;
+ })
+ }
+ })
},
- selectInvert : function(el)
+ selectIndices : function(elements, indices)
{
- $A(el.options).each(function(option)
+ selection = this;
+ indices.each(function(index)
{
- option.selected = !option.selected;
- });
+ selection.selectIndex(elements,index);
+ })
+ },
+
+ selectClear : function(elements)
+ {
+ elements.each(function(el)
+ {
+ el.selectedIndex = -1;
+ })
+ },
+
+ getListElements : function(element, total)
+ {
+ elements = new Array();
+ for(i = 0; i < total; i++)
+ {
+ el = $(element+"_c"+i);
+ if(el)
+ elements.push(el);
+ }
+ return elements;
},
- checkValue : function(name, value)
+ checkValue : function(elements, value)
{
- $A(document.getElementsByName(name)).each(function(el)
+ elements.each(function(el)
{
- el.checked = el.value == value
+ if(typeof(value) == "boolean")
+ el.checked = value;
+ else if(el.value == value)
+ el.checked = true;
});
},
- checkIndex : function(name, index)
+ checkValues : function(elements, values)
+ {
+ selection = this;
+ values.each(function(value)
+ {
+ selection.checkValue(elements, value);
+ })
+ },
+
+ checkIndex : function(elements, index)
{
- var elements = $A(document.getElementsByName(name));
for(var i = 0; i<elements.length; i++)
{
if(i == index)
@@ -2740,29 +3183,63 @@ Prado.Element.Selection =
}
},
- checkClear : function(name)
+ checkIndices : function(elements, indices)
+ {
+ selection = this;
+ indices.each(function(index)
+ {
+ selection.checkIndex(elements, index);
+ })
+ },
+
+ checkClear : function(elements)
{
- $A(document.getElementsByName(name)).each(function(el)
+ elements.each(function(el)
{
el.checked = false;
});
},
- checkAll : function(name)
+ checkAll : function(elements)
{
- $A(document.getElementsByName(name)).each(function(el)
+ elements.each(function(el)
{
el.checked = true;
- });
+ })
},
- checkInvert : function(name)
+
+ checkInvert : function(elements)
{
- $A(document.getElementsByName(name)).each(function(el)
+ elements.each(function(el)
{
- el.checked = !el.checked;
- });
+ el.checked != el.checked;
+ })
+ }
+};
+
+
+Prado.Element.Insert =
+{
+ append: function(element, content)
+ {
+ new Insertion.Bottom(element, content);
+ },
+
+ prepend: function(element, content)
+ {
+ new Insertion.Top(element, content);
+ },
+
+ after: function(element, content)
+ {
+ new Insertion.After(element, content);
+ },
+
+ before: function(element, content)
+ {
+ new Insertion.Before(element, content);
}
-};
+}
Prado.WebUI = Class.create();
@@ -2773,12 +3250,12 @@ Prado.WebUI.PostBackControl.prototype =
initialize : function(options)
{
this.element = $(options['ID']);
-
+
/* if(options.CausesValidation && typeof(Prado.Validation) != 'undefined')
{
Prado.Validation.registerTarget(options);
}
-
+
//TODO: what do the following options do?
//options['PostBackUrl']
//options['ClientSubmit']
@@ -2801,7 +3278,7 @@ Prado.WebUI.TButton = Prado.WebUI.createPostBackComponent();
*/
Prado.WebUI.PostBackControl = Class.create();
-Prado.WebUI.PostBackControl.prototype =
+Prado.WebUI.PostBackControl.prototype =
{
_elementOnClick : null, //capture the element's onclick function
@@ -2811,7 +3288,7 @@ Prado.WebUI.PostBackControl.prototype =
if(this.onInit)
this.onInit(options);
},
-
+
onInit : function(options)
{
if(typeof(this.element.onclick)=="function")
@@ -2819,10 +3296,10 @@ Prado.WebUI.PostBackControl.prototype =
this._elementOnClick = this.element.onclick;
this.element.onclick = null;
}
- Event.observe(this.element, "click", this.onClick.bindEvent(this,options));
+ Event.observe(this.element, "click", this.elementClicked.bindEvent(this,options));
},
- onClick : function(event, options)
+ elementClicked : function(event, options)
{
var src = Event.element(event);
var doPostBack = true;
@@ -2853,7 +3330,7 @@ Prado.WebUI.TBulletedList = Class.extend(Prado.WebUI.PostBackControl);
Prado.WebUI.TImageMap = Class.extend(Prado.WebUI.PostBackControl);
/**
- * TImageButton client-side behaviour. With validation, Firefox needs
+ * TImageButton client-side behaviour. With validation, Firefox needs
* to capture the x,y point of the clicked image in hidden form fields.
*/
Prado.WebUI.TImageButton = Class.extend(Prado.WebUI.PostBackControl);
@@ -2863,7 +3340,7 @@ Object.extend(Prado.WebUI.TImageButton.prototype,
* Only add the hidden inputs once.
*/
hasXYInput : false,
-
+
/**
* Override parent onPostBack function, tried to add hidden forms
* inputs to capture x,y clicked point.
@@ -2877,7 +3354,7 @@ Object.extend(Prado.WebUI.TImageButton.prototype,
}
Prado.PostBack(event, options);
},
-
+
/**
* Add hidden inputs to capture the x,y point clicked on the image.
* @param event DOM click event.
@@ -2885,15 +3362,33 @@ Object.extend(Prado.WebUI.TImageButton.prototype,
*/
addXYInput : function(event,options)
{
- var imagePos = Position.cumulativeOffset(this.element);
- var clickedPos = [event.clientX, event.clientY];
- var x = clickedPos[0]-imagePos[0]+1;
- var y = clickedPos[1]-imagePos[1]+1;
- var id = options['EventTarget'];
- var x_input = INPUT({type:'hidden',name:id+'_x',value:x});
- var y_input = INPUT({type:'hidden',name:id+'_y',value:y});
- this.element.parentNode.appendChild(x_input);
- this.element.parentNode.appendChild(y_input);
+ imagePos = Position.cumulativeOffset(this.element);
+ clickedPos = [event.clientX, event.clientY];
+ x = clickedPos[0]-imagePos[0]+1;
+ y = clickedPos[1]-imagePos[1]+1;
+ x = x < 0 ? 0 : x;
+ y = y < 0 ? 0 : y;
+ id = options['EventTarget'];
+ x_input = $(id+"_x");
+ y_input = $(id+"_y");
+ if(x_input)
+ {
+ x_input.value = x;
+ }
+ else
+ {
+ x_input = INPUT({type:'hidden',name:id+'_x','id':id+'_x',value:x});
+ this.element.parentNode.appendChild(x_input);
+ }
+ if(y_input)
+ {
+ y_input.value = y;
+ }
+ else
+ {
+ y_input = INPUT({type:'hidden',name:id+'_y','id':id+'_y',value:y});
+ this.element.parentNode.appendChild(y_input);
+ }
}
});
@@ -2949,7 +3444,7 @@ Prado.WebUI.TListBox = Class.extend(Prado.WebUI.TListControl);
Prado.WebUI.TDropDownList = Class.extend(Prado.WebUI.TListControl);
Prado.WebUI.DefaultButton = Class.create();
-Prado.WebUI.DefaultButton.prototype =
+Prado.WebUI.DefaultButton.prototype =
{
initialize : function(options)
{
diff --git a/framework/Web/Javascripts/js/debug/validator.js b/framework/Web/Javascripts/js/debug/validator.js
index 7a963f82..ec57e876 100644
--- a/framework/Web/Javascripts/js/debug/validator.js
+++ b/framework/Web/Javascripts/js/debug/validator.js
@@ -90,6 +90,15 @@ Object.extend(Prado.Validation,
},
/**
+ * @return string first form ID.
+ */
+ getForm : function()
+ {
+ var keys = $H(this.managers).keys();
+ return keys[0];
+ },
+
+ /**
* Check if the validators are valid for a particular form (and group).
* The validators states will not be changed.
* The <tt>validate</tt> function should be called first.
@@ -647,6 +656,16 @@ Prado.WebUI.TBaseValidator.prototype =
*/
validate : function(invoker)
{
+ //try to find the control.
+ if(!this.control)
+ this.control = $(this.options.ControlToValidate);
+
+ if(!this.control)
+ {
+ this.isValid = true;
+ return this.isValid;
+ }
+
if(typeof(this.options.OnValidate) == "function")
this.options.OnValidate(this, invoker);
diff --git a/framework/Web/Javascripts/prado/inlineeditor.js b/framework/Web/Javascripts/prado/inlineeditor.js
index 4eb33d5c..24cc9b70 100644
--- a/framework/Web/Javascripts/prado/inlineeditor.js
+++ b/framework/Web/Javascripts/prado/inlineeditor.js
@@ -90,10 +90,26 @@ Prado.WebUI.TInPlaceTextBox = Base.extend(
*/
createTextBox : function()
{
- cssClass= this.options.TextBoxCssClass || 'editor_field';
+ cssClass= this.element.className || '';
inputName = this.options.EventTarget;
options = {'className' : cssClass, name : inputName, id : this.options.TextBoxID};
- this.editField = this.options.TextMode == 'SingleLine' ? INPUT(options) : TEXTAREA(options);
+ if(this.options.TextMode == 'SingleLine')
+ {
+ if(this.options.MaxLength > 0)
+ options['maxlength'] = this.options.MaxLength;
+ this.editField = INPUT(options);
+ }
+ else
+ {
+ 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);
+ }
+
this.editField.style.display="none";
this.element.parentNode.insertBefore(this.editField,this.element)
@@ -137,12 +153,14 @@ Prado.WebUI.TInPlaceTextBox = Base.extend(
onTextBoxBlur : function(e)
{
text = this.element.innerHTML;
- if(text != this.editField.value)
+ if(this.options.AutoPostBack && text != this.editField.value)
this.onTextChanged(text);
else
{
+ this.element.innerHTML = this.editField.value;
this.isEditing = false;
- this.showLabel();
+ if(this.options.AutoHide)
+ this.showLabel();
}
},
@@ -195,8 +213,10 @@ Prado.WebUI.TInPlaceTextBox = Base.extend(
{
this.isSaving = false;
this.isEditing = false;
- this.showLabel();
+ if(this.options.AutoHide)
+ this.showLabel();
this.element.innerHTML = parameter == null ? this.editField.value : parameter;
+ this.editField.disabled = false;
},
onTextChangedFailure : function(sender, parameter)
diff --git a/framework/Web/Javascripts/prado/validation3.js b/framework/Web/Javascripts/prado/validation3.js
index c88aa661..8df3864c 100644
--- a/framework/Web/Javascripts/prado/validation3.js
+++ b/framework/Web/Javascripts/prado/validation3.js
@@ -660,6 +660,12 @@ Prado.WebUI.TBaseValidator.prototype =
if(!this.control)
this.control = $(this.options.ControlToValidate);
+ if(!this.control)
+ {
+ this.isValid = true;
+ return this.isValid;
+ }
+
if(typeof(this.options.OnValidate) == "function")
this.options.OnValidate(this, invoker);
diff --git a/framework/Web/UI/ActiveControls/TActiveRadioButton.php b/framework/Web/UI/ActiveControls/TActiveRadioButton.php
index cb4e7ef1..93f89148 100644
--- a/framework/Web/UI/ActiveControls/TActiveRadioButton.php
+++ b/framework/Web/UI/ActiveControls/TActiveRadioButton.php
@@ -10,7 +10,6 @@
* @package System.Web.UI.ActiveControls
*/
-
/**
* TActiveRadioButton class.
*
diff --git a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
index 21acfa74..5763fd5b 100644
--- a/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
+++ b/framework/Web/UI/ActiveControls/TInPlaceTextBox.php
@@ -1,32 +1,82 @@
<?php
-
-class TInPlaceTextBox extends TLabel implements
- IActiveControl, ICallbackEventHandler, IPostBackDataHandler, IValidatable
+/**
+ * TInPlaceTextBox class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.pradosoft.com/
+ * @copyright Copyright &copy; 2006 PradoSoft
+ * @license http://www.pradosoft.com/license/
+ * @version $Revision: 30/08/2006 $
+ * @package System.Web.UI.ActiveControls
+ */
+
+/**
+ * TInPlaceTextBox Class
+ * *
+ * TInPlaceTextBox is a component rendered as a label and allows its
+ * contents to be edited by changing the label to a textbox when
+ * the label is clicked or when another control or html element with
+ * ID given by {@link setEditTriggerControlID EditTriggerControlID} is clicked.
+ *
+ * If the {@link OnLoadingText} event is handled, a callback request is
+ * made when the label is clicked, while the request is being made the
+ * textbox is disabled from editing. The {@link OnLoadingText} event allows
+ * you to update the content of the textbox before the client is allowed
+ * to edit the content. After the callback request returns successfully,
+ * the textbox is enabled and the contents is then allowed to be edited.
+ *
+ * Once the textbox loses focus, if {@link setAutoPostBack AutoPostBack}
+ * is true and the textbox content has changed, a callback request is made and
+ * the {@link OnTextChanged} event is raised like that of the TActiveTextBox.
+ * During the request, the textbox is disabled.
+ *
+ * After the callback request returns sucessfully, the textbox is enabled.
+ * If the {@link setAutoHideTextBox AutoHideTextBox} property is true, then
+ * the textbox will be hidden and the label is then shown.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Revision: $ 30/08/2006 $
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
+ */
+class TInPlaceTextBox extends TActiveTextBox
{
/**
- * Creates a new callback control, sets the adapter to
- * TActiveControlAdapter. If you override this class, be sure to set the
- * adapter appropriately by, for example, by calling this constructor.
+ * Sets the auto post back to true by default.
*/
public function __construct()
{
parent::__construct();
- $this->setAdapter(new TActiveControlAdapter($this));
+ $this->setAutoPostBack(true);
+ }
+
+ /**
+ * @param boolean true to hide the textbox after losing focus.
+ */
+ public function setAutoHideTextBox($value)
+ {
+ $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true);
}
/**
- * @return TBaseActiveControl basic active control options.
+ * @return boolean true will hide the textbox after losing focus.
*/
- public function getActiveControl()
+ public function getAutoHideTextBox()
{
- return $this->getAdapter()->getBaseActiveControl();
+ return $this->getViewState('AutoHide', true);
}
+ /**
+ * @param string ID of the control that can trigger to edit the textbox
+ */
public function setEditTriggerControlID($value)
{
$this->setViewState('EditTriggerControlID', $value);
}
+ /**
+ * @return string ID of the control that can trigger to edit the textbox
+ */
public function getEditTriggerControlID()
{
return $this->getViewState('EditTriggerControlID');
@@ -45,53 +95,62 @@ class TInPlaceTextBox extends TLabel implements
}
/**
- * Adds attributes to renderer.
- * @param THtmlWriter the renderer
- * @throws TInvalidDataValueException if associated control cannot be found using the ID
+ * On callback response, the inner HTMl of the label and the
+ * value of the textbox is updated
+ * @param string the text value of the label
*/
- protected function addAttributesToRender($writer)
- {
- parent::addAttributesToRender($writer);
- $writer->addAttribute('id', $this->getLabelClientID());
- $this->renderClientControlScript($writer);
- }
-
- protected function getLabelClientID()
+ public function setText($value)
{
- return $this->getClientID().'__label';
+ TTextBox::setText($value);
+ if($this->getActiveControl()->canUpdateClientSide())
+ {
+ $client = $this->getPage()->getCallbackClient();
+ $client->update($this->getLabelClientID(), $value);
+ $client->setValue($this, $value);
+ }
}
/**
- * On callback response, the inner HTMl of the label is updated.
- * @param string the text value of the label
+ * @return string tag name of the label.
*/
- public function setText($value)
+ protected function getTagName()
{
- parent::setText($value);
- if($this->getActiveControl()->canUpdateClientSide())
- $this->getPage()->getCallbackClient()->update(
- $this->getLabelClientID(), $value);
+ return 'span';
}
/**
- * Raises the callback event. This method is required by {@link
- * ICallbackEventHandler} interface.
- * This method is mainly used by framework and control developers.
- * @param TCallbackEventParameter the event parameter
+ * Adds attributes to renderer.
+ * @param THtmlWriter the renderer
+ * @throws TInvalidDataValueException if associated control cannot be found using the ID
*/
- public function raiseCallbackEvent($param)
+ protected function addAttributesToRender($writer)
{
- $this->onCallback($param);
+ TWebControl::addAttributesToRender($writer);
+ $page=$this->getPage();
+ $page->ensureRenderInForm($this);
+ $writer->addAttribute('id', $this->getLabelClientID());
+ if(!$this->getReadOnly())
+ $this->renderClientControlScript($writer);
}
- public function setTextBoxCssClass($value)
+ /**
+ * Renders the body content of the label.
+ * @param THtmlWriter the writer for rendering
+ */
+ public function renderContents($writer)
{
- $this->setViewState('TextBoxCssClass', $value);
+ if(($text=$this->getText())==='')
+ parent::renderContents($writer);
+ else
+ $writer->write($text);
}
- public function getTextBoxCssClass()
+ /**
+ * @return string label client ID
+ */
+ protected function getLabelClientID()
{
- return $this->getViewState('TextBoxCssClass');
+ return $this->getClientID().'__label';
}
/**
@@ -115,123 +174,56 @@ class TInPlaceTextBox extends TLabel implements
/**
* @return array callback options.
*/
- protected function getTextBoxOptions()
+ protected function getPostBackOptions()
{
+ $options = parent::getPostBackOptions();
$options['ID'] = $this->getLabelClientID();
$options['TextBoxID'] = $this->getClientID();
- $options['EventTarget'] = $this->getUniqueID();
- $options['CausesValidation'] = $this->getCausesValidation();
- $options['ValidationGroup'] = $this->getValidationGroup();
- $options['TextMode'] = $this->getTextMode();
$options['ExternalControl'] = $this->getExternalControlID();
- $options['TextBoxCssClass'] = $this->getTextBoxCssClass();
+ $options['AutoHide'] = $this->getAutoHideTextBox() == false ? '' : true;
+ $options['AutoPostBack'] = $this->getAutoPostBack() == false ? '' : true;
+ if($this->getTextMode()==='MultiLine')
+ {
+ $options['Columns'] = $this->getColumns();
+ $options['Rows'] = $this->getRows();
+ $options['Wrap'] = $this->getWrap()== false ? '' : true;
+ }
+ else
+ {
+ $length = $this->getMaxLength();
+ $options['MaxLength'] = $length > 0 ? $length : '';
+ }
+
if($this->hasEventHandler('OnLoadingText'))
$options['LoadTextOnEdit'] = true;
return $options;
}
/**
- * @return string the behavior mode (SingleLine or MultiLine) of the TextBox component. Defaults to SingleLine.
- */
- public function getTextMode()
- {
- return $this->getViewState('TextMode','SingleLine');
- }
-
- /**
- * Sets the behavior mode (SingleLine or MultiLine) of the TextBox component.
- * @param string the text mode
- * @throws TInvalidDataValueException if the input value is not a valid text mode.
- */
- public function setTextMode($value)
- {
- $this->setViewState('TextMode',TPropertyValue::ensureEnum($value,array('SingleLine','MultiLine')),'SingleLine');
- }
- /**
- * Returns the value to be validated.
- * This methid is required by IValidatable interface.
- * @return mixed the value of the property to be validated.
- */
- public function getValidationPropertyValue()
- {
- return $this->getText();
- }
-
- /**
- * @return boolean whether postback event trigger by this text box will cause input validation, default is true.
- */
- public function getCausesValidation()
- {
- return $this->getViewState('CausesValidation',true);
- }
-
- /**
- * @param boolean whether postback event trigger by this text box will cause input validation.
- */
- public function setCausesValidation($value)
- {
- $this->setViewState('CausesValidation',TPropertyValue::ensureBoolean($value),true);
- }
-
-
- /**
- * @return string the group of validators which the text box causes validation upon postback
- */
- public function getValidationGroup()
- {
- return $this->getViewState('ValidationGroup','');
- }
-
- /**
- * @param string the group of validators which the text box causes validation upon postback
- */
- public function setValidationGroup($value)
- {
- $this->setViewState('ValidationGroup',$value,'');
- }
-
- /**
- * On text changed.
+ * Raised when editing the content is requsted to be loaded from the
+ * server side.
+ * @param TCallbackEventParameter event parameter to be passed to the event handlers
*/
- public function raisePostDataChangedEvent()
- {
- $this->onTextChanged(null);
- }
-
public function onLoadingText($param)
{
$this->raiseEvent('OnLoadingText',$this,$param);
}
/**
- * Raises <b>OnTextChanged</b> event.
- * This method is invoked when the value of the {@link getText Text}
- * property changes on postback.
- * If you override this method, be sure to call the parent implementation to ensure
- * the invocation of the attached event handlers.
- * @param TEventParameter event parameter to be passed to the event handlers
- */
- public function onTextChanged($param)
- {
- $this->raiseEvent('OnTextChanged',$this,$param);
- }
-
- /**
* Registers the javascript code for initializing the active control.
*/
protected function renderClientControlScript($writer)
{
$this->getActiveControl()->registerCallbackClientScript(
- $this->getClientClassName(), $this->getTextBoxOptions());
+ $this->getClientClassName(), $this->getPostBackOptions());
}
/**
- * @return string corresponding javascript class name for this TActiveLabelTextBox.
+ * @return string corresponding javascript class name for this TInPlaceTextBox
*/
protected function getClientClassName()
{
return 'Prado.WebUI.TInPlaceTextBox';
}
}
-
?> \ No newline at end of file
diff --git a/framework/Web/UI/ActiveControls/TTriggeredCallback.php b/framework/Web/UI/ActiveControls/TTriggeredCallback.php
index 2ccdda1a..9e0c14a4 100644
--- a/framework/Web/UI/ActiveControls/TTriggeredCallback.php
+++ b/framework/Web/UI/ActiveControls/TTriggeredCallback.php
@@ -18,8 +18,8 @@
*
* @author Wei Zhuo <weizhuo[at]gmail[dot]com>
* @version $Revision: $ 27/08/2006 $
- * @package System.package
- * @since version
+ * @package System.Web.UI.ActiveControls
+ * @since 3.1
*/
abstract class TTriggeredCallback extends TCallback
{
diff --git a/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.page b/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.page
index 54e38c2c..b6b2d040 100644
--- a/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.page
+++ b/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.page
@@ -1,7 +1,7 @@
<com:TForm ID="form1">
<style>
- .textbox, .editor
+ .textbox
{
font-family: Arial, Helvetica, sans-serif;
font-size: 1.2em;
@@ -16,7 +16,7 @@
}
- .editor
+ input.textbox
{
background-color: #ffc;
}
@@ -29,6 +29,11 @@
background-color:#900;
padding: 0.5em 1em;
}
+ input.required
+ {
+ border: 1px solid red;
+ background-color: pink;
+ }
</style>
<h1>TInPlaceTextBox Functional Test</h1>
@@ -36,16 +41,22 @@
<com:TInPlaceTextBox id="label1"
OnTextChanged="label1_changed"
EditTriggerControlID="link1"
- TextBoxCssClass="editor"
- ActiveControl.ClientSide.OnLoading="Element.show('loader')"
- ActiveControl.ClientSide.OnComplete="Element.hide('loader')"
- CssClass="textbox" Text="Label 1" />
-<span id="loader" style="display:none;" class="loader">Loading...</span>
- <a href="#" id="link1">Edit</a>
+ CssClass="textbox"
+ Text="Label 1">
+ <prop:ActiveControl.ClientSide
+ OnLoading="Element.show('loader')"
+ OnComplete="Element.hide('loader')" />
+ </com:TInPlaceTextBox>
+
<com:TRequiredFieldValidator
ControlToValidate="label1"
+ ControlCssClass="required"
ErrorMessage="*" />
+ <span id="loader" style="display:none;" class="loader">Loading...</span>
+
+ <a href="#" id="link1">Edit</a>
+
<com:TActiveLabel ID="status" Text="Status:" />
<com:TJavascriptLogger />
diff --git a/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.php b/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.php
index 3fa5c7e2..5607dea8 100644
--- a/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.php
+++ b/tests/FunctionalTests/active-controls/protected/pages/TInPlaceTextBoxTest.php
@@ -11,6 +11,11 @@ class TInPlaceTextBoxTest extends TPage
{
$this->status->Text = "Status: ". $sender->Text;
}
+
+ function button_clicked($sender, $param)
+ {
+ $this->label1->Text = "hahahaha";
+ }
}
?> \ No newline at end of file