From 407aa2ff5d56859fcd1f47b85b4c4180d035c428 Mon Sep 17 00:00:00 2001 From: wei <> Date: Sat, 21 Jan 2006 02:07:59 +0000 Subject: Fixed DefaultButton and TLinkButton --- framework/Web/Javascripts/extended/base.js | 2 +- framework/Web/Javascripts/extended/event.js | 33 +++++++- framework/Web/Javascripts/js/prado.js | 59 ++++++++++--- framework/Web/Javascripts/prado/controls.js | 66 +++++---------- framework/Web/UI/TClientScriptManager.php | 31 ++++++- framework/Web/UI/WebControls/TButton.php | 3 + framework/Web/UI/WebControls/TDatePicker.php | 98 ++++++++++++++++++++-- framework/Web/UI/WebControls/TPanel.php | 9 +- .../pages/UI/TestTPanelDefaultButton.page | 4 +- .../protected/pages/UI/TestTPanelDefaultButton.php | 22 +++++ 10 files changed, 246 insertions(+), 81 deletions(-) diff --git a/framework/Web/Javascripts/extended/base.js b/framework/Web/Javascripts/extended/base.js index e3ca729b..48927b75 100644 --- a/framework/Web/Javascripts/extended/base.js +++ b/framework/Web/Javascripts/extended/base.js @@ -29,6 +29,6 @@ function $(n,d) { Function.prototype.bindEvent = function() { var __method = this, args = $A(arguments), object = args.shift(); return function(event) { - return __method.call(object, event || window.event, args); + return __method.apply(object, [event || window.event].concat(args)); } } diff --git a/framework/Web/Javascripts/extended/event.js b/framework/Web/Javascripts/extended/event.js index a7514cda..b6dccf3b 100644 --- a/framework/Web/Javascripts/extended/event.js +++ b/framework/Web/Javascripts/extended/event.js @@ -26,12 +26,39 @@ Object.extend(Event, { return e.keyCode != null ? e.keyCode : e.charCode }, + isHTMLEvent : function(type) + { + var events = ['abort', 'blur', 'change', 'error', 'focus', 'load', 'reset', 'resize', 'scroll', 'select', 'submit', 'unload']; + return events.include(type); + }, + + isMouseEvent : function(type) + { + var events = ['click', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup']; + return events.include(type); + }, + fireEvent : function(element,type) { if(document.createEvent) - { - var event = document.createEvent('HTMLEvents'); - event.initEvent(type, true, true); + { + if(Event.isHTMLEvent(type)) + { + var event = document.createEvent('HTMLEvents'); + event.initEvent(type, true, true); + } + else if(Event.isMouseEvent(type)) + { + var event = document.createEvent('MouseEvents'); + event.initMouseEvent(type,true,true, + document.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null); + } + else + { + if(Logger) + Logger.error("undefined event", type); + return; + } element.dispatchEvent(event); } else if(element.fireEvent) diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js index 590882fa..f411cbcf 100644 --- a/framework/Web/Javascripts/js/prado.js +++ b/framework/Web/Javascripts/js/prado.js @@ -193,7 +193,7 @@ return x; Function.prototype.bindEvent=function(){ var _6=this,args=$A(arguments),object=args.shift(); return function(_7){ -return _6.call(object,_7||window.event,args); +return _6.apply(object,[_7||window.event].concat(args)); }; }; @@ -1140,17 +1140,35 @@ _9="keydown"; this._observeAndCache(_8,_9,_10,_11); },keyCode:function(e){ return e.keyCode!=null?e.keyCode:e.charCode; -},fireEvent:function(_13,_14){ +},isHTMLEvent:function(_13){ +var _14=["abort","blur","change","error","focus","load","reset","resize","scroll","select","submit","unload"]; +return _14.include(_13); +},isMouseEvent:function(_15){ +var _16=["click","mousedown","mousemove","mouseout","mouseover","mouseup"]; +return _16.include(_15); +},fireEvent:function(_17,_18){ if(document.createEvent){ -var _15=document.createEvent("HTMLEvents"); -_15.initEvent(_14,true,true); -_13.dispatchEvent(_15); +if(Event.isHTMLEvent(_18)){ +var _19=document.createEvent("HTMLEvents"); +_19.initEvent(_18,true,true); }else{ -if(_13.fireEvent){ -_13.fireEvent("on"+_14); -_13[_14](); +if(Event.isMouseEvent(_18)){ +var _19=document.createEvent("MouseEvents"); +_19.initMouseEvent(_18,true,true,document.defaultView,1,0,0,0,0,false,false,false,false,0,null); }else{ -_13[_14](); +if(Logger){ +Logger.error("undefined event",_18); +} +return; +} +} +_17.dispatchEvent(_19); +}else{ +if(_17.fireEvent){ +_17.fireEvent("on"+_18); +_17[_18](); +}else{ +_17[_18](); } } }}); @@ -2372,7 +2390,7 @@ _41.set(_42); Prado.WebUI=Class.create(); Prado.WebUI.PostBackControl=Class.create(); Object.extend(Prado.WebUI.PostBackControl.prototype,{initialize:function(_1){ -this.element=$(_1["ID"]); +this.control=$(_1["ID"]); if(_1["CausesValidation"]&&Prado.Validation){ Prado.Validation.AddTarget(_1["ID"],_1["ValidationGroup"]); } @@ -2390,7 +2408,7 @@ return _3; }; Prado.WebUI.TButton=Prado.WebUI.createPostBackComponent(); Prado.WebUI.ClickableComponent=Prado.WebUI.createPostBackComponent({onInit:function(_4){ -Event.observe(this.element,"click",Prado.PostBack.bindEvent(this,_4)); +Event.observe(this.control,"click",Prado.PostBack.bindEvent(this,_4)); }}); Prado.WebUI.TLinkButton=Prado.WebUI.ClickableComponent; Prado.WebUI.TCheckBox=Prado.WebUI.ClickableComponent; @@ -2407,14 +2425,29 @@ var _7=Event.element(e); if(_7){ Event.fireEvent(_7,"change"); Event.stop(e); -return false; } } -return true; }}); Prado.WebUI.TListControl=Prado.WebUI.createPostBackComponent({onInit:function(_8){ Event.observe(this.element.id,"change",Prado.PostBack.bindEvent(this,_8)); }}); Prado.WebUI.TListBox=Prado.WebUI.TListControl; Prado.WebUI.TDropDownList=Prado.WebUI.TListControl; +Prado.WebUI.DefaultButton=Class.create(); +Object.extend(Prado.WebUI.DefaultButton.prototype,{initialize:function(_9){ +this.options=_9; +this._event=this.triggerEvent.bindEvent(this); +Event.observe(_9["Panel"],"keydown",this._event); +},triggerEvent:function(ev,_11){ +var _12=Event.keyCode(ev)==Event.KEY_RETURN; +var _13=Event.element(ev).tagName.toLowerCase()=="textarea"; +if(_12&&!_13){ +var _14=$(this.options["Target"]); +if(_14){ +this.triggered=true; +Event.fireEvent(_14,this.options["Event"]); +Event.stop(ev); +} +} +}}); diff --git a/framework/Web/Javascripts/prado/controls.js b/framework/Web/Javascripts/prado/controls.js index 34c734f9..d1720dfe 100644 --- a/framework/Web/Javascripts/prado/controls.js +++ b/framework/Web/Javascripts/prado/controls.js @@ -6,7 +6,7 @@ Object.extend(Prado.WebUI.PostBackControl.prototype, { initialize : function(options) { - this.element = $(options['ID']); + this.control = $(options['ID']); if(options['CausesValidation'] && Prado.Validation) Prado.Validation.AddTarget(options['ID'], options['ValidationGroup']); @@ -34,7 +34,7 @@ Prado.WebUI.ClickableComponent = Prado.WebUI.createPostBackComponent( { onInit : function(options) { - Event.observe(this.element, "click", Prado.PostBack.bindEvent(this,options)); + Event.observe(this.control, "click", Prado.PostBack.bindEvent(this,options)); } }); @@ -61,10 +61,8 @@ Prado.WebUI.TTextBox = Prado.WebUI.createPostBackComponent( { Event.fireEvent(target, "change"); Event.stop(e); - return false; } } - return true; } }); @@ -79,53 +77,29 @@ Prado.WebUI.TListControl = Prado.WebUI.createPostBackComponent( Prado.WebUI.TListBox = Prado.WebUI.TListControl; Prado.WebUI.TDropDownList = Prado.WebUI.TListControl; - -//Prado.Button = Class.create(); - -/** - * Usage: Event.observe("panelID", "keypress", Prado.fireButton.bindEvent($("panelID"), "targetButtonID")); - */ -/*Object.extend(Prado.Button, +Prado.WebUI.DefaultButton = Class.create(); +Object.extend(Prado.WebUI.DefaultButton.prototype, { - buttonFired : false, - fireButton : function(e, target) + initialize : function(options) { - var eventFired = !this.buttonFired && Event.keyCode(e) == Event.KEY_RETURN; - var isTextArea = Event.element(e).tagName.toLowerCase() == "textarea"; - if (eventFired && !isTextArea) - { - var defaultButton = $(target); - if (defaultButton) - { - Prado.Button.buttonFired = true; - Event.fireEvent(defaultButton,"click"); - Event.stop(e); - return false; - } - } - return true; - } -}); + this.options = options; + this._event = this.triggerEvent.bindEvent(this); + Event.observe(options['Panel'], 'keydown', this._event); + }, -Prado.TextBox = Class.create(); -*/ -/** - * Usage: Event.observe("textboxID", "keypress", Prado.fireButton.bindEvent($("textboxID"))); - */ -/*Object.extend(Prado.TextBox, -{ - handleReturnKey : function(e) + triggerEvent : function(ev, target) { - if(Event.keyCode(e) == Event.KEY_RETURN) - { - var target = Event.element(e); - if(target) + var enterPressed = Event.keyCode(ev) == Event.KEY_RETURN; + var isTextArea = Event.element(ev).tagName.toLowerCase() == "textarea"; + if(enterPressed && !isTextArea) + { + var defaultButton = $(this.options['Target']); + if(defaultButton) { - Event.fireEvent(target, "change"); - Event.stop(e); - return false; + this.triggered = true; + Event.fireEvent(defaultButton, this.options['Event']); + Event.stop(ev); } } - return true; } -});*/ +}); \ No newline at end of file diff --git a/framework/Web/UI/TClientScriptManager.php b/framework/Web/UI/TClientScriptManager.php index 535e85b2..be6611cd 100644 --- a/framework/Web/UI/TClientScriptManager.php +++ b/framework/Web/UI/TClientScriptManager.php @@ -1,6 +1,6 @@ _trackFocus=$value; } } - +*/ Prado::using('System.Web.Javascripts.*'); class TClientScriptManager extends TComponent @@ -133,6 +133,33 @@ class TClientScriptManager extends TComponent return $options->toJavascript(); } + /** + * Register a default button to panel. When the $panel is in focus and + * the 'enter' key is pressed, the $button will be clicked. + * @param TControl panel to register the default button action + * @param TControl button to trigger a postback + */ + public function registerDefaultButton($panel, $button) + { + $serializer = new TJavascriptSerializer( + $this->getDefaultButtonOptions($panel, $button)); + $options = $serializer->toJavascript(); + $code = "new Prado.WebUI.DefaultButton($options);"; + $scripts = $this->_page->getClientScript(); + $scripts->registerEndScript("prado:".$panel->getClientID(), $code); + } + + /** + * @return array default button options. + */ + protected function getDefaultButtonOptions($panel, $button) + { + $options['Panel'] = $panel->getClientID(); + $options['Target'] = $button->getClientID(); + $options['Event'] = 'click'; + return $options; + } + /** * Register client scripts. diff --git a/framework/Web/UI/WebControls/TButton.php b/framework/Web/UI/WebControls/TButton.php index 9c364af8..85473349 100644 --- a/framework/Web/UI/WebControls/TButton.php +++ b/framework/Web/UI/WebControls/TButton.php @@ -86,6 +86,9 @@ class TButton extends TWebControl implements IPostBackEventHandler parent::addAttributesToRender($writer); } + /** + * @return boolean true if validators are active and can cause validation. + */ protected function canCauseValidation() { $group = $this->getValidationGroup(); diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php index 10d3248e..60cf882d 100644 --- a/framework/Web/UI/WebControls/TDatePicker.php +++ b/framework/Web/UI/WebControls/TDatePicker.php @@ -1,13 +1,58 @@ + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Revision: $ $Date: $ + * @package System.Web.UI.WebControls + */ /** - * ${classname} * - * ${description} + * TDatePicker class. + * + * TDatePicker displays a text box for date input purpose. + * When the text box receives focus, a calendar will pop up and users can + * pick up from it a date that will be automatically entered into the text box. + * The format of the date string displayed in the text box is determined by + * the DateFormat property. Valid formats are the combination of the + * following tokens, + * + * + * Character Format Pattern (en-US) + * ----------------------------------------- + * d day digit + * dd padded day digit e.g. 01, 02 + * M month digit + * MM padded month digit + * MMMM localized month name, e.g. March, April + * yy 2 digit year + * yyyy 4 digit year + * ----------------------------------------- + * + * + * TDatePicker has three Mode to show the date picker popup. + * + * # Basic -- Only shows a text input, focusing on the input shows the + * date picker. + * # Button -- Shows a button next to the text input, clicking on the + * button shows the date, button text can be by the + * ButtonText property + * # ImageButton -- Shows an image next to the text input, clicking on + * the image shows the date picker, image source can be + * change through the ImageUrl property. + * + * The CssClass property can be used to override the css class name + * for the date picker panel. CalendarStyle property sets the packages + * styles available. E.g. default. * - * @author Wei Zhuo - * @version $Revision: 1.66 $ $Date: ${DATE} ${TIME} $ - * @package ${package} + * @author Wei Zhuo + * @version $Revision: $ $Date: $ + * @package System.Web.UI.WebControls + * @since 3.0 */ class TDatePicker extends TTextBox { @@ -175,6 +220,10 @@ class TDatePicker extends TTextBox return $this->getViewState('UpToYear', intval(@date('Y'))+10); } + /** + * Get javascript date picker options. + * @return array date picker client-side options + */ protected function getDatePickerOptions() { $options['Format'] = $this->getDateFormat(); @@ -189,6 +238,10 @@ class TDatePicker extends TTextBox return $options; } + /** + * Get javascript localization options, e.g. month and weekday names. + * @return array localization options. + */ protected function getCulturalOptions() { $app = $this->getApplication()->getGlobalization(); @@ -206,6 +259,9 @@ class TDatePicker extends TTextBox return $options; } + /** + * Publish the date picker Css asset files. + */ protected function OnPreRender($param) { parent::onPreRender($param); @@ -214,8 +270,8 @@ class TDatePicker extends TTextBox /** * Renders body content. - * This method overrides parent implementation by replacing - * the body content with syntax highlighted result. + * This method overrides parent implementation by adding + * additional date picker button if Mode is "Button" or "ImageButton". * @param THtmlWriter writer */ protected function render($writer) @@ -229,11 +285,19 @@ class TDatePicker extends TTextBox } } + /** + * Gets the ID for the date picker trigger button. + * @return string unique button ID + */ protected function getDatePickerButtonID() { return $this->getClientID().'button'; } + /** + * Adds an additional button such that when clicked it shows the date picker. + * @return THtmlWriter writer + */ protected function renderButtonDatePicker($writer) { $writer->addAttribute('id', $this->getDatePickerButtonID()); @@ -243,7 +307,11 @@ class TDatePicker extends TTextBox $writer->renderBeginTag("input"); } - protected function renderImageButtonDatePicker($writer) + /** + * Adds an additional image button such that when clicked it shows the date picker. + * @return THtmlWriter writer + */ + protected function renderImageButtonDatePicker($writer) { $url = $this->getButtonImageUrl(); $url = empty($url) ? $this->publishDefaultButtonImage() : $url; @@ -253,6 +321,10 @@ class TDatePicker extends TTextBox $writer->renderBeginTag('img'); } + /** + * Publish the default button image asset file. + * @return string image file url. + */ protected function publishDefaultButtonImage() { $cs = $this->getPage()->getClientScript(); @@ -261,6 +333,10 @@ class TDatePicker extends TTextBox return $this->getService()->getAsset($file); } + /** + * Publish the calendar style Css asset file. + * @return string Css file url. + */ protected function publishCalendarStyle() { $cs = $this->getPage()->getClientScript(); @@ -272,6 +348,12 @@ class TDatePicker extends TTextBox return $url; } + /** + * Registers the javascript code to initialize the date picker. + * Must use "Event.OnLoad" to initialize the date picker when the + * full page is loaded, otherwise IE will throw an error. + * @param THtmlWriter writer + */ protected function addAttributesToRender($writer) { parent::addAttributesToRender($writer); diff --git a/framework/Web/UI/WebControls/TPanel.php b/framework/Web/UI/WebControls/TPanel.php index 9eab135e..33ae7cd2 100644 --- a/framework/Web/UI/WebControls/TPanel.php +++ b/framework/Web/UI/WebControls/TPanel.php @@ -72,13 +72,8 @@ class TPanel extends TWebControl throw new TInvalidDataValueException('panel_defaultbutton_invalid',$butt); else { - //TODO - /*$scripts = $this->getPage()->getClientScript(); - $js = $scripts->registerDefaultButtonScript($this,$button); - $clientID=$this->getClientID(); - $scripts->registerEndScript($clientID.'defaultButton', $js); - $writer->addAttribute('id',$clientID); - $writer->addAttribute('onkeypress', "return false;");*/ + $writer->addAttribute('id',$this->getClientID()); + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); } } } diff --git a/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.page b/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.page index 7585bdbc..753550d8 100644 --- a/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.page +++ b/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.page @@ -3,13 +3,15 @@ This is panel content with a and two buttons:
- + +
When you change focus to the panel and hit 'enter' key, button2 will be clicked because it is set as the default button of the panel.
+ \ No newline at end of file diff --git a/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.php b/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.php index bc88dc00..2b0ba466 100644 --- a/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.php +++ b/tests/FunctionalTests/protected/pages/UI/TestTPanelDefaultButton.php @@ -8,4 +8,26 @@ class TestTPanelDefaultButton extends TPage } } +/** + * + * + * @author Wei Zhuo + * @version $Revision: $ $Date: $ + * @package System.Web.UI.WebControls + * @since 3.0 + */ +class DefaultButtonTest extends SeleniumTestCase +{ + function setup() + { + $page = Prado::getApplication()->getTestPage(__FILE__); + $this->open($page); + } + + function testClick() + { + $this->clickAndWait("ctl0_Content_Button2"); + $this->assertTextPresent("You have clicked on 'button2'."); + } +} ?> \ No newline at end of file -- cgit v1.2.3