From 12c16fb3c7314b51d74dcaffdca4d311c6fad8c0 Mon Sep 17 00:00:00 2001 From: wei <> Date: Sun, 7 May 2006 09:47:15 +0000 Subject: Adding TAutoComplete --- .gitattributes | 4 + buildscripts/jsbuilder/build.php | 8 +- framework/Web/Javascripts/js/ajax.js | 63 ++++++- framework/Web/Javascripts/js/prado.js | 9 +- framework/Web/Javascripts/prado/activecontrols3.js | 43 +++++ framework/Web/Javascripts/prado/element.js | 17 +- .../UI/ActiveControls/TActiveControlAdapter.php | 4 +- .../Web/UI/ActiveControls/TActivePageAdapter.php | 2 +- framework/Web/UI/ActiveControls/TAutoComplete.php | 186 +++++++++++++++++++++ .../Web/UI/ActiveControls/TCallbackResponse.php | 13 +- .../pages/ActiveControls/AutoComplete.page | 26 +++ .../pages/ActiveControls/AutoComplete.php | 17 ++ .../protected/pages/ActiveControls/Calculator.php | 1 + .../protected/pages/ActiveControls/config.xml | 6 +- 14 files changed, 378 insertions(+), 21 deletions(-) create mode 100644 framework/Web/Javascripts/prado/activecontrols3.js create mode 100644 framework/Web/UI/ActiveControls/TAutoComplete.php create mode 100644 tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.page create mode 100644 tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.php diff --git a/.gitattributes b/.gitattributes index 329e6e51..81846ece 100644 --- a/.gitattributes +++ b/.gitattributes @@ -879,6 +879,7 @@ framework/Web/Javascripts/js/prado.js -text framework/Web/Javascripts/js/rico.js -text framework/Web/Javascripts/js/validator.js -text framework/Web/Javascripts/prado/activecontrols.js -text +framework/Web/Javascripts/prado/activecontrols3.js -text framework/Web/Javascripts/prado/ajax.js -text framework/Web/Javascripts/prado/ajax3.js -text framework/Web/Javascripts/prado/controls.js -text @@ -931,6 +932,7 @@ framework/Web/UI/ActiveControls/TActiveLabel.php -text framework/Web/UI/ActiveControls/TActivePageAdapter.php -text framework/Web/UI/ActiveControls/TActivePanel.php -text framework/Web/UI/ActiveControls/TActiveTextBox.php -text +framework/Web/UI/ActiveControls/TAutoComplete.php -text framework/Web/UI/ActiveControls/TCallback.php -text framework/Web/UI/ActiveControls/TCallbackClientScript.php -text framework/Web/UI/ActiveControls/TCallbackClientSideOptions.php -text @@ -1041,6 +1043,8 @@ tests/FunctionalTests/features/protected/controls/Layout.php -text tests/FunctionalTests/features/protected/controls/Layout.tpl -text tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.page -text tests/FunctionalTests/features/protected/pages/ActiveControls/ActiveControl.php -text +tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.page -text +tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.php -text tests/FunctionalTests/features/protected/pages/ActiveControls/Calculator.page -text tests/FunctionalTests/features/protected/pages/ActiveControls/Calculator.php -text tests/FunctionalTests/features/protected/pages/ActiveControls/config.xml -text diff --git a/buildscripts/jsbuilder/build.php b/buildscripts/jsbuilder/build.php index 9cd1da74..33e5d133 100644 --- a/buildscripts/jsbuilder/build.php +++ b/buildscripts/jsbuilder/build.php @@ -102,11 +102,11 @@ $libraries = array( 'prototype/ajax.js', 'prado/ajax3.js', 'extra/json.js', + 'effects/controls.js', 'prado/activecontrols3.js' -/* 'effects/controls.js', - 'effects/dragdrop.js', - 'effects/slider.js', - 'prado/activecontrols.js'*/ +// 'effects/dragdrop.js', +// 'effects/slider.js', +// 'prado/activecontrols.js' ), //logging 'logger.js' => array( diff --git a/framework/Web/Javascripts/js/ajax.js b/framework/Web/Javascripts/js/ajax.js index e082c7bb..48b4689a 100644 --- a/framework/Web/Javascripts/js/ajax.js +++ b/framework/Web/Javascripts/js/ajax.js @@ -132,5 +132,64 @@ break;case'n':if(next()=='u'&&next()=='l'&&next()=='l'){next();return null;} break;} error("Syntax error");} function value(){white();switch(ch){case'{':return object();case'[':return array();case'"':return string();case'-':return number();default:return ch>='0'&&ch<='9'?number():word();}} -return value();}};Prado.WebUI.CallbackControl=Class.extend(Prado.WebUI.PostBackControl,{onPostBack:function(event,options) -{new Prado.CallbackRequest(options.EventTarget,options);Event.stop(event);}});Prado.WebUI.TActiveButton=Class.extend(Prado.WebUI.CallbackControl); \ No newline at end of file +return value();}};var Autocompleter={} +Autocompleter.Base=function(){};Autocompleter.Base.prototype={baseInitialize:function(element,update,options){this.element=$(element);this.update=$(update);this.hasFocus=false;this.changed=false;this.active=false;this.index=0;this.entryCount=0;if(this.setOptions) +this.setOptions(options);else +this.options=options||{};this.options.paramName=this.options.paramName||this.element.name;this.options.tokens=this.options.tokens||[];this.options.frequency=this.options.frequency||0.4;this.options.minChars=this.options.minChars||1;this.options.onShow=this.options.onShow||function(element,update){if(!update.style.position||update.style.position=='absolute'){update.style.position='absolute';Position.clone(element,update,{setHeight:false,offsetTop:element.offsetHeight});} +Effect.Appear(update,{duration:0.15});};this.options.onHide=this.options.onHide||function(element,update){new Effect.Fade(update,{duration:0.15})};if(typeof(this.options.tokens)=='string') +this.options.tokens=new Array(this.options.tokens);this.observer=null;this.element.setAttribute('autocomplete','off');Element.hide(this.update);Event.observe(this.element,"blur",this.onBlur.bindAsEventListener(this));Event.observe(this.element,"keypress",this.onKeyPress.bindAsEventListener(this));},show:function(){if(Element.getStyle(this.update,'display')=='none')this.options.onShow(this.element,this.update);if(!this.iefix&&(navigator.appVersion.indexOf('MSIE')>0)&&(navigator.userAgent.indexOf('Opera')<0)&&(Element.getStyle(this.update,'position')=='absolute')){new Insertion.After(this.update,'');this.iefix=$(this.update.id+'_iefix');} +if(this.iefix)setTimeout(this.fixIEOverlapping.bind(this),50);},fixIEOverlapping:function(){Position.clone(this.update,this.iefix);this.iefix.style.zIndex=1;this.update.style.zIndex=2;Element.show(this.iefix);},hide:function(){this.stopIndicator();if(Element.getStyle(this.update,'display')!='none')this.options.onHide(this.element,this.update);if(this.iefix)Element.hide(this.iefix);},startIndicator:function(){if(this.options.indicator)Element.show(this.options.indicator);},stopIndicator:function(){if(this.options.indicator)Element.hide(this.options.indicator);},onKeyPress:function(event){if(this.active) +switch(event.keyCode){case Event.KEY_TAB:case Event.KEY_RETURN:this.selectEntry();Event.stop(event);case Event.KEY_ESC:this.hide();this.active=false;Event.stop(event);return;case Event.KEY_LEFT:case Event.KEY_RIGHT:return;case Event.KEY_UP:this.markPrevious();this.render();if(navigator.appVersion.indexOf('AppleWebKit')>0)Event.stop(event);return;case Event.KEY_DOWN:this.markNext();this.render();if(navigator.appVersion.indexOf('AppleWebKit')>0)Event.stop(event);return;} +else +if(event.keyCode==Event.KEY_TAB||event.keyCode==Event.KEY_RETURN||(navigator.appVersion.indexOf('AppleWebKit')>0&&event.keyCode==0))return;this.changed=true;this.hasFocus=true;if(this.observer)clearTimeout(this.observer);this.observer=setTimeout(this.onObserverEvent.bind(this),this.options.frequency*1000);},activate:function(){this.changed=false;this.hasFocus=true;this.getUpdatedChoices();},onHover:function(event){var element=Event.findElement(event,'LI');if(this.index!=element.autocompleteIndex) +{this.index=element.autocompleteIndex;this.render();} +Event.stop(event);},onClick:function(event){var element=Event.findElement(event,'LI');this.index=element.autocompleteIndex;this.selectEntry();this.hide();},onBlur:function(event){setTimeout(this.hide.bind(this),250);this.hasFocus=false;this.active=false;},render:function(){if(this.entryCount>0){for(var i=0;i0)this.index-- +else this.index=this.entryCount-1;},markNext:function(){if(this.index0)value=Element.collectTextNodes(nodes[0],this.options.select);}else +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;}else{this.element.value=value;} +this.element.focus();if(this.options.afterUpdateElement) +this.options.afterUpdateElement(this.element,selectedElement);},updateChoices:function(choices){if(!this.changed&&this.hasFocus){this.update.innerHTML=choices;Element.cleanWhitespace(this.update);Element.cleanWhitespace(this.update.firstChild);if(this.update.firstChild&&this.update.firstChild.childNodes){this.entryCount=this.update.firstChild.childNodes.length;for(var i=0;i=this.options.minChars){this.startIndicator();this.getUpdatedChoices();}else{this.active=false;this.hide();}},getToken:function(){var tokenPos=this.findLastToken();if(tokenPos!=-1) +var ret=this.element.value.substr(tokenPos+1).replace(/^\s+/,'').replace(/\s+$/,'');else +var ret=this.element.value;return/\n/.test(ret)?'':ret;},findLastToken:function(){var lastTokenPos=-1;for(var i=0;ilastTokenPos) +lastTokenPos=thisTokenPos;} +return lastTokenPos;}} +Ajax.Autocompleter=Class.create();Object.extend(Object.extend(Ajax.Autocompleter.prototype,Autocompleter.Base.prototype),{initialize:function(element,update,url,options){this.baseInitialize(element,update,options);this.options.asynchronous=true;this.options.onComplete=this.onComplete.bind(this);this.options.defaultParams=this.options.parameters||null;this.url=url;},getUpdatedChoices:function(){entry=encodeURIComponent(this.options.paramName)+'='+ +encodeURIComponent(this.getToken());this.options.parameters=this.options.callback?this.options.callback(this.element,entry):entry;if(this.options.defaultParams) +this.options.parameters+='&'+this.options.defaultParams;new Ajax.Request(this.url,this.options);},onComplete:function(request){this.updateChoices(request.responseText);}});Autocompleter.Local=Class.create();Autocompleter.Local.prototype=Object.extend(new Autocompleter.Base(),{initialize:function(element,update,array,options){this.baseInitialize(element,update,options);this.options.array=array;},getUpdatedChoices:function(){this.updateChoices(this.options.selector(this));},setOptions:function(options){this.options=Object.extend({choices:10,partialSearch:true,partialChars:2,ignoreCase:true,fullSearch:false,selector:function(instance){var ret=[];var partial=[];var entry=instance.getToken();var count=0;for(var i=0;i"+elem.substr(0,entry.length)+""+ +elem.substr(entry.length)+"");break;}else if(entry.length>=instance.options.partialChars&&instance.options.partialSearch&&foundPos!=-1){if(instance.options.fullSearch||/\s/.test(elem.substr(foundPos-1,1))){partial.push("
  • "+elem.substr(0,foundPos)+""+ +elem.substr(foundPos,entry.length)+""+elem.substr(foundPos+entry.length)+"
  • ");break;}} +foundPos=instance.options.ignoreCase?elem.toLowerCase().indexOf(entry.toLowerCase(),foundPos+1):elem.indexOf(entry,foundPos+1);}} +if(partial.length) +ret=ret.concat(partial.slice(0,instance.options.choices-ret.length)) +return"
      "+ret.join('')+"
    ";}},options||{});}});Field.scrollFreeActivate=function(field){setTimeout(function(){Field.activate(field);},1);} +Ajax.InPlaceEditor=Class.create();Ajax.InPlaceEditor.defaultHighlightColor="#FFFF99";Ajax.InPlaceEditor.prototype={initialize:function(element,url,options){this.url=url;this.element=$(element);this.options=Object.extend({okButton:true,okText:"ok",cancelLink:true,cancelText:"cancel",savingText:"Saving...",clickToEditText:"Click to edit",okText:"ok",rows:1,onComplete:function(transport,element){new Effect.Highlight(element,{startcolor:this.options.highlightcolor});},onFailure:function(transport){alert("Error communicating with the server: "+transport.responseText.stripTags());},callback:function(form){return Form.serialize(form);},handleLineBreaks:true,loadingText:'Loading...',savingClassName:'inplaceeditor-saving',loadingClassName:'inplaceeditor-loading',formClassName:'inplaceeditor-form',highlightcolor:Ajax.InPlaceEditor.defaultHighlightColor,highlightendcolor:"#FFFFFF",externalControl:null,submitOnBlur:false,ajaxOptions:{},evalScripts:false},options||{});if(!this.options.formId&&this.element.id){this.options.formId=this.element.id+"-inplaceeditor";if($(this.options.formId)){this.options.formId=null;}} +if(this.options.externalControl){this.options.externalControl=$(this.options.externalControl);} +this.originalBackground=Element.getStyle(this.element,'background-color');if(!this.originalBackground){this.originalBackground="transparent";} +this.element.title=this.options.clickToEditText;this.onclickListener=this.enterEditMode.bindAsEventListener(this);this.mouseoverListener=this.enterHover.bindAsEventListener(this);this.mouseoutListener=this.leaveHover.bindAsEventListener(this);Event.observe(this.element,'click',this.onclickListener);Event.observe(this.element,'mouseover',this.mouseoverListener);Event.observe(this.element,'mouseout',this.mouseoutListener);if(this.options.externalControl){Event.observe(this.options.externalControl,'click',this.onclickListener);Event.observe(this.options.externalControl,'mouseover',this.mouseoverListener);Event.observe(this.options.externalControl,'mouseout',this.mouseoutListener);}},enterEditMode:function(evt){if(this.saving)return;if(this.editing)return;this.editing=true;this.onEnterEditMode();if(this.options.externalControl){Element.hide(this.options.externalControl);} +Element.hide(this.element);this.createForm();this.element.parentNode.insertBefore(this.form,this.element);Field.scrollFreeActivate(this.editField);if(evt){Event.stop(evt);} +return false;},createForm:function(){this.form=document.createElement("form");this.form.id=this.options.formId;Element.addClassName(this.form,this.options.formClassName) +this.form.onsubmit=this.onSubmit.bind(this);this.createEditField();if(this.options.textarea){var br=document.createElement("br");this.form.appendChild(br);} +if(this.options.okButton){okButton=document.createElement("input");okButton.type="submit";okButton.value=this.options.okText;okButton.className='editor_ok_button';this.form.appendChild(okButton);} +if(this.options.cancelLink){cancelLink=document.createElement("a");cancelLink.href="#";cancelLink.appendChild(document.createTextNode(this.options.cancelText));cancelLink.onclick=this.onclickCancel.bind(this);cancelLink.className='editor_cancel';this.form.appendChild(cancelLink);}},hasHTMLLineBreaks:function(string){if(!this.options.handleLineBreaks)return false;return string.match(/
    /i);},convertHTMLLineBreaks:function(string){return string.replace(/
    /gi,"\n").replace(//gi,"\n").replace(/<\/p>/gi,"\n").replace(/

    /gi,"");},createEditField:function(){var text;if(this.options.loadTextURL){text=this.options.loadingText;}else{text=this.getText();} +var obj=this;if(this.options.rows==1&&!this.hasHTMLLineBreaks(text)){this.options.textarea=false;var textField=document.createElement("input");textField.obj=this;textField.type="text";textField.name="value";textField.value=text;textField.style.backgroundColor=this.options.highlightcolor;textField.className='editor_field';var size=this.options.size||this.options.cols||0;if(size!=0)textField.size=size;if(this.options.submitOnBlur) +textField.onblur=this.onSubmit.bind(this);this.editField=textField;}else{this.options.textarea=true;var textArea=document.createElement("textarea");textArea.obj=this;textArea.name="value";textArea.value=this.convertHTMLLineBreaks(text);textArea.rows=this.options.rows;textArea.cols=this.options.cols||40;textArea.className='editor_field';if(this.options.submitOnBlur) +textArea.onblur=this.onSubmit.bind(this);this.editField=textArea;} +if(this.options.loadTextURL){this.loadExternalText();} +this.form.appendChild(this.editField);},getText:function(){return this.element.innerHTML;},loadExternalText:function(){Element.addClassName(this.form,this.options.loadingClassName);this.editField.disabled=true;new Ajax.Request(this.options.loadTextURL,Object.extend({asynchronous:true,onComplete:this.onLoadedExternalText.bind(this)},this.options.ajaxOptions));},onLoadedExternalText:function(transport){Element.removeClassName(this.form,this.options.loadingClassName);this.editField.disabled=false;this.editField.value=transport.responseText.stripTags();},onclickCancel:function(){this.onComplete();this.leaveEditMode();return false;},onFailure:function(transport){this.options.onFailure(transport);if(this.oldInnerHTML){this.element.innerHTML=this.oldInnerHTML;this.oldInnerHTML=null;} +return false;},onSubmit:function(){var form=this.form;var value=this.editField.value;this.onLoading();if(this.options.evalScripts){new Ajax.Request(this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this),asynchronous:true,evalScripts:true},this.options.ajaxOptions));}else{new Ajax.Updater({success:this.element,failure:null},this.url,Object.extend({parameters:this.options.callback(form,value),onComplete:this.onComplete.bind(this),onFailure:this.onFailure.bind(this)},this.options.ajaxOptions));} +if(arguments.length>1){Event.stop(arguments[0]);} +return false;},onLoading:function(){this.saving=true;this.removeForm();this.leaveHover();this.showSaving();},showSaving:function(){this.oldInnerHTML=this.element.innerHTML;this.element.innerHTML=this.options.savingText;Element.addClassName(this.element,this.options.savingClassName);this.element.style.backgroundColor=this.originalBackground;Element.show(this.element);},removeForm:function(){if(this.form){if(this.form.parentNode)Element.remove(this.form);this.form=null;}},enterHover:function(){if(this.saving)return;this.element.style.backgroundColor=this.options.highlightcolor;if(this.effect){this.effect.cancel();} +Element.addClassName(this.element,this.options.hoverClassName)},leaveHover:function(){if(this.options.backgroundColor){this.element.style.backgroundColor=this.oldBackground;} +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));}};Prado.WebUI.CallbackControl=Class.extend(Prado.WebUI.PostBackControl,{onPostBack:function(event,options) +{new Prado.CallbackRequest(options.EventTarget,options);Event.stop(event);}});Prado.WebUI.TActiveButton=Class.extend(Prado.WebUI.CallbackControl);Prado.WebUI.TAutoComplete=Class.extend(Autocompleter.Base,{initialize:function(options) +{this.options=options;this.baseInitialize(options.ID,options.ResultPanel,options);Object.extend(this.options,{onSuccess:this.onComplete.bind(this)});},getUpdatedChoices:function() +{Prado.Callback(this.options.EventTarget,this.getToken(),null,this.options);},onComplete:function(request,boundary) +{result=Prado.Element.extractContent(request.responseText,boundary);this.updateChoices(result);}}); \ No newline at end of file diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js index 9442ed26..c09cf64c 100644 --- a/framework/Web/Javascripts/js/prado.js +++ b/framework/Web/Javascripts/js/prado.js @@ -265,9 +265,12 @@ el.options[el.options.length]=new Option(options[i][0],options[i][1]);}},focus:f {var obj=$(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) -{var f=RegExp('()([\\s\\S\\w\\W]*)()',"m");var result=transport.responseText.match(f);if(result&&result.length>=2) -content=result[2];} -method.toFunction().apply(this,[element,content]);}} +{result=Prado.Element.extractContent(transport.responseText,boundary);if(result!=null) +content=result;} +method.toFunction().apply(this,[element,content]);},extractContent:function(text,boundary) +{f=RegExp('()([\\s\\S\\w\\W]*)()',"m");result=text.match(f);if(result&&result.length>=2) +return result[2];else +return null;}} Prado.Element.Selection={inputValue:function(el,value) {switch(el.type.toLowerCase()) {case'checkbox':case'radio':return el.checked=value;}},selectValue:function(el,value) diff --git a/framework/Web/Javascripts/prado/activecontrols3.js b/framework/Web/Javascripts/prado/activecontrols3.js new file mode 100644 index 00000000..c22af98c --- /dev/null +++ b/framework/Web/Javascripts/prado/activecontrols3.js @@ -0,0 +1,43 @@ +/** + * Generic postback control. + */ +Prado.WebUI.CallbackControl = Class.extend(Prado.WebUI.PostBackControl, +{ + onPostBack : function(event, options) + { + new Prado.CallbackRequest(options.EventTarget, options); + Event.stop(event); + } +}); + +/** + * TActiveButton control. + */ +Prado.WebUI.TActiveButton = Class.extend(Prado.WebUI.CallbackControl); + +/** + * TAutoComplete control. + */ +Prado.WebUI.TAutoComplete = Class.extend(Autocompleter.Base, +{ + initialize : function(options) + { + this.options = options; + this.baseInitialize(options.ID, options.ResultPanel, options); + Object.extend(this.options, + { + onSuccess : this.onComplete.bind(this) + }); + }, + + getUpdatedChoices : function() + { + Prado.Callback(this.options.EventTarget, this.getToken(), null, this.options); + }, + + onComplete : function(request, boundary) + { + result = Prado.Element.extractContent(request.responseText, boundary); + this.updateChoices(result); + } +}); \ No newline at end of file diff --git a/framework/Web/Javascripts/prado/element.js b/framework/Web/Javascripts/prado/element.js index eec7fb92..0ff0e8fa 100644 --- a/framework/Web/Javascripts/prado/element.js +++ b/framework/Web/Javascripts/prado/element.js @@ -67,12 +67,21 @@ Prado.Element = { if(boundary) { - var f = RegExp('()([\\s\\S\\w\\W]*)()',"m"); - var result = transport.responseText.match(f); - if(result && result.length >= 2) - content = result[2]; + result = Prado.Element.extractContent(transport.responseText, boundary); + if(result != null) + content = result; } method.toFunction().apply(this,[element,content]); + }, + + extractContent : function(text, boundary) + { + f = RegExp('()([\\s\\S\\w\\W]*)()',"m"); + result = text.match(f); + if(result && result.length >= 2) + return result[2]; + else + return null; } } diff --git a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php index 2409d9fe..1cdd5d73 100644 --- a/framework/Web/UI/ActiveControls/TActiveControlAdapter.php +++ b/framework/Web/UI/ActiveControls/TActiveControlAdapter.php @@ -14,9 +14,11 @@ class TActiveControlAdapter extends TControlAdapter { if(!self::$_renderedPosts) { + $cs = $this->getPage()->getClientScript(); + $cs->registerPradoScript('ajax'); $options = TJavascript::encode($this->getPage()->getPostDataLoaders(),false); $script = "Prado.CallbackRequest.PostDataLoaders = {$options};"; - $this->getPage()->getClientScript()->registerEndScript(get_class($this), $script); + $cs->registerEndScript(get_class($this), $script); self::$_renderedPosts = true; } parent::render($writer); diff --git a/framework/Web/UI/ActiveControls/TActivePageAdapter.php b/framework/Web/UI/ActiveControls/TActivePageAdapter.php index 11c3303e..e92c9cdc 100644 --- a/framework/Web/UI/ActiveControls/TActivePageAdapter.php +++ b/framework/Web/UI/ActiveControls/TActivePageAdapter.php @@ -257,7 +257,7 @@ class TCallbackEventParameter extends TEventParameter */ public function getOutput() { - return $this->_response->createHtmlWriter(); + return $this->_response->createHtmlWriter(null,$this); } /** diff --git a/framework/Web/UI/ActiveControls/TAutoComplete.php b/framework/Web/UI/ActiveControls/TAutoComplete.php new file mode 100644 index 00000000..2ebba495 --- /dev/null +++ b/framework/Web/UI/ActiveControls/TAutoComplete.php @@ -0,0 +1,186 @@ +getSuggestions()->setDataSource($data); + } + + public function getResultPanel() + { + if(is_null($this->_resultPanel)) + $this->_resultPanel = $this->createResultPanel(); + return $this->_resultPanel; + } + + protected function createResultPanel() + { + $panel = Prado::createComponent('System.Web.UI.WebControls.TPanel'); + $this->getControls()->add($panel); + $panel->setID('result'); + return $panel; + } + + /** + * @return TRepeater suggestion list repeater + */ + public function getSuggestions() + { + if(is_null($this->_repeater)) + $this->_repeater = $this->createRepeater(); + return $this->_repeater; + } + + /** + * + */ + protected function createRepeater() + { + $repeater = Prado::createComponent('System.Web.UI.WebControls.TRepeater'); + $repeater->setHeaderTemplate(new TAutoCompleteTemplate('

      ')); + $repeater->setFooterTemplate(new TAutoCompleteTemplate('
    ')); + $repeater->setItemTemplate(new TTemplate('
  • <%# $this->DataItem %>
  • ',null)); + $this->getControls()->add($repeater); + return $repeater; + } + + /** + * @return TCallbackClientSideOptions callback client-side options. + */ + protected function createClientSideOptions() + { + $options = new TAutoCompleteClientSideOptions; + $options->setEnablePageStateUpdate(false); + return $options; + } + + public function renderEndTag($writer) + { + $this->getPage()->getClientScript()->registerPradoScript('effects'); + parent::renderEndTag($writer); + $this->renderResultPanel($writer); + } + + public function renderResultPanel($writer) + { + $this->getResultPanel()->render($writer); + } + + public function render($writer) + { + if($this->canUpdateClientSide()) + { + $this->getSuggestions()->render($writer); + $boundary = $writer->getWriter()->getBoundary(); + $writer->getWriter()->getResponse()->setData($boundary); + } + else + parent::render($writer); + } + + /** + * @return array list of callback options. + */ + protected function getCallbackOptions() + { + $options = $this->getClientSide()->getOptions()->toArray(); + if($this->getAutoPostBack()) + $options = array_merge($options,$this->getPostBackOptions()); + $options['ResultPanel'] = $this->getResultPanel()->getClientID(); + $options['ID'] = $this->getClientID(); + $options['EventTarget'] = $this->getUniqueID(); + return $options; + } + + /** + * Adds attribute name-value pairs to renderer. + * This method overrides the parent implementation with additional textbox specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + $this->renderClientControlScript($writer); + } + +} + +/** + * Client-side options for TAutoComplete. + * + * @author Wei Zhuo + * @version $Revision: $ $Date: $ + * @package System.Web.UI.ActiveControls + * @since 3.0 + */ +class TAutoCompleteClientSideOptions extends TCallbackClientSideOptions +{ + public function getSeparator() + { + return $this->getOption('tokens'); + } + + public function setSeparator($value) + { + $this->setOption('tokens', $chars = preg_split('//', $value, -1, PREG_SPLIT_NO_EMPTY)); + } + + public function getFrequency() + { + return $this->getOption('frequency'); + } + + public function setFrequency($value) + { + $this->setOption('frequency', TPropertyValue::ensureFloat($value)); + } + + public function getMinChars() + { + return $this->getOption('minChars'); + } + + public function setMinChars($value) + { + $this->setOption('minChars', TPropertyValue::ensureInteger($value)); + } +} + +/** + * TWizardSideBarTemplate class. + * TWizardSideBarTemplate is the default template for wizard sidebar. + * @author Qiang Xue + * @version $Revision: $ $Date: $ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class TAutoCompleteTemplate extends TComponent implements ITemplate +{ + private $_template; + + public function __construct($template) + { + $this->_template = $template; + } + /** + * Instantiates the template. + * It creates a {@link TDataList} control. + * @param TControl parent to hold the content within the template + */ + public function instantiateIn($parent) + { + $parent->getControls()->add($this->_template); + } +} + +?> \ No newline at end of file diff --git a/framework/Web/UI/ActiveControls/TCallbackResponse.php b/framework/Web/UI/ActiveControls/TCallbackResponse.php index 024ad6ef..b28d817b 100644 --- a/framework/Web/UI/ActiveControls/TCallbackResponse.php +++ b/framework/Web/UI/ActiveControls/TCallbackResponse.php @@ -7,9 +7,9 @@ class TCallbackResponse extends THttpResponse { private $_writers=array(); - public function createHtmlWriter($type=null) + public function createHtmlWriter($type=null,$parameter=null) { - $writer = new TCallbackResponseWriter(); + $writer = new TCallbackResponseWriter($parameter); $this->_writers[] = $writer; if($type===null) $type=$this->getHtmlWriterType(); @@ -27,12 +27,19 @@ class TCallbackResponse extends THttpResponse class TCallbackResponseWriter extends TTextWriter { private $_boundary; + private $_response; - public function __construct() + public function __construct($response) { + $this->_response = $response; $this->_boundary = sprintf('%x',crc32((string)$this)); } + public function getResponse() + { + return $this->_response; + } + public function getBoundary() { return $this->_boundary; diff --git a/tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.page b/tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.page new file mode 100644 index 00000000..f0d78267 --- /dev/null +++ b/tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.page @@ -0,0 +1,26 @@ + + + + +


    +


    +


    +


    +


    +


    +


    +


    +


    +


    + +
    \ No newline at end of file diff --git a/tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.php b/tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.php new file mode 100644 index 00000000..81508000 --- /dev/null +++ b/tests/FunctionalTests/features/protected/pages/ActiveControls/AutoComplete.php @@ -0,0 +1,17 @@ +setDataSource($words); + $sender->dataBind(); + $sender->render($param->getOutput()); + } +} + +?> \ No newline at end of file diff --git a/tests/FunctionalTests/features/protected/pages/ActiveControls/Calculator.php b/tests/FunctionalTests/features/protected/pages/ActiveControls/Calculator.php index bcf0f9cd..9821d8c9 100644 --- a/tests/FunctionalTests/features/protected/pages/ActiveControls/Calculator.php +++ b/tests/FunctionalTests/features/protected/pages/ActiveControls/Calculator.php @@ -2,6 +2,7 @@ /* * Created on 6/05/2006 */ +Prado::using('System.Web.UI.ActiveControls.*'); class Calculator extends TPage { diff --git a/tests/FunctionalTests/features/protected/pages/ActiveControls/config.xml b/tests/FunctionalTests/features/protected/pages/ActiveControls/config.xml index 1bbc0acf..37988c44 100644 --- a/tests/FunctionalTests/features/protected/pages/ActiveControls/config.xml +++ b/tests/FunctionalTests/features/protected/pages/ActiveControls/config.xml @@ -1,7 +1,7 @@ - - - + + + -- cgit v1.2.3