diff options
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'&¶meters.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 © 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 |