diff options
Diffstat (limited to 'framework')
22 files changed, 1033 insertions, 284 deletions
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index cde4eae1..20bafba2 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -231,6 +231,8 @@ basevalidator_forcontrol_unsupported	= {0}.ForControl is not supported.  comparevalidator_controltocompare_invalid = TCompareValidator.ControlToCompare contains an invalid control ID path.
 +tlistcontrolvalidator_invalid_control	= {0}.ControlToValidate contains an invalid TListControl ID path, "{1}" is a {2}.
 +
  repeater_template_required				= TRepeater.{0} requires a template instance implementing ITemplate interface.
  datalist_template_required				= TDataList.{0} requires a template instance implementing ITemplate interface.
  templatecolumn_template_required		= TTemplateColumn.{0} requires a template instance implementing ITemplate interface.
 diff --git a/framework/Util/TSimpleDateFormatter.php b/framework/Util/TSimpleDateFormatter.php index 052e0074..2a3da63a 100644 --- a/framework/Util/TSimpleDateFormatter.php +++ b/framework/Util/TSimpleDateFormatter.php @@ -190,18 +190,20 @@ class TSimpleDateFormatter  	/**
  	 * Parse the string according to the pattern.
 -	 * @param string date string to parse
 +	 * @param string|int date string or integer to parse
  	 * @return int date time stamp
  	 * @throws TInvalidDataValueException if date string is malformed.
  	 */
  	public function parse($value,$defaultToCurrentTime=true)
  	{
 -		if(!is_string($value))
 +		if(is_int($value))
 +			return $value;
 +		else if(!is_string($value))
  			throw new TInvalidDataValueException('date_to_parse_must_be_string', $value);
  		if(empty($this->pattern)) return time();
 -		$date = $this->getDate(time());
 +		$date = time();
  		if($this->length(trim($value)) < 1)
  			return $defaultToCurrentTime ? $date : null;
 diff --git a/framework/Web/Javascripts/colorpicker/colorpicker.js b/framework/Web/Javascripts/colorpicker/colorpicker.js index cc4587ff..dc80f0c7 100644 --- a/framework/Web/Javascripts/colorpicker/colorpicker.js +++ b/framework/Web/Javascripts/colorpicker/colorpicker.js @@ -83,7 +83,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  			if(mode == "Full")
  				this.initializeFullPicker();
  		}
 -		this.show();
 +		this.show(mode);
  	},		
  	show : function(type)
 @@ -108,6 +108,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  			if(type == "Full")
  			{
 +				this.observeMouseMovement();
  				var color = Rico.Color.createFromHex(this.input.value);
  				this.inputs.oldColor.style.backgroundColor = color.asHex();
  				this.setColor(color,true);
 @@ -124,8 +125,14 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  			this.element.style.display = "none";
  			this.showing = false;
 -			Event.stopObserving(document.body, "click", this._documentClickEvent);	
 +			Event.stopObserving(document.body, "click", this._documentClickEvent);
  			Event.stopObserving(document,"keydown", this._documentKeyDownEvent); 
 +			
 +			if(this._observingMouseMove)
 +			{			
 +				Event.stopObserving(document.body, "mousemove", this._onMouseMove);	
 +				this._observingMouseMove = false;
 +			}
  		}
  	},
 @@ -208,7 +215,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  	{
  		this.input.value = color.toString().toUpperCase();
  		this.button.style.backgroundColor = color.toString();
 -		if(isFunction(this.onChange))
 +		if(typeof(this.onChange) == "function")
  			this.onChange(color);
  	},
 @@ -246,7 +253,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  				TR(null,
  					TD(null,'H:'),
 -					TD(null,this.inputs['H'], '°')),
 +					TD(null,this.inputs['H'], '??')),
  				TR(null,
  					TD(null,'S:'),
 @@ -333,34 +340,46 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  		this._onMouseMove = this.onMouseMove.bind(this);
  		Event.observe(this.inputs.background, "mousedown", this._onColorMouseDown);
 +		Event.observe(this.inputs.selector, "mousedown", this._onColorMouseDown);
  		Event.observe(this.inputs.hue, "mousedown", this._onHueMouseDown);
 +		Event.observe(this.inputs.slider, "mousedown", this._onHueMouseDown);
  		Event.observe(document.body, "mouseup", this._onMouseUp);
 -
 -		//Because of using the CSS filter, IE can't do colour change quickly
 -		//if(!Prado.Browser().ie)
 -		Event.observe(document.body, "mousemove", this._onMouseMove);			
 +		
 +		this.observeMouseMovement();
  		Event.observe(this.buttons.Cancel, "click", this.hide.bindEvent(this,this.options['Mode']));
  		Event.observe(this.buttons.OK, "click", this.onOKClicked.bind(this));
  	},
 +	observeMouseMovement : function()
 +	{
 +		if(!this._observingMouseMove)
 +		{
 +			Event.observe(document.body, "mousemove", this._onMouseMove);
 +			this._observingMouseMove = true;
 +		}		
 +	},
 +
  	onColorMouseDown : function(ev)
  	{
  		this.isMouseDownOnColor = true;
  		this.onMouseMove(ev);
 +		Event.stop(ev);
  	},
  	onHueMouseDown : function(ev)
  	{
  		this.isMouseDownOnHue = true;
  		this.onMouseMove(ev);
 +		Event.stop(ev);
  	},
  	onMouseUp : function(ev)
  	{
  		this.isMouseDownOnColor = false;
  		this.isMouseDownOnHue = false;
 +		Event.stop(ev);
  	},
  	onMouseMove : function(ev)
 @@ -369,6 +388,7 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  			this.changeSV(ev);
  		if(this.isMouseDownOnHue)
  			this.changeH(ev);
 +		Event.stop(ev);
  	},	
  	changeSV : function(ev)
 @@ -376,18 +396,25 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  		var px = Event.pointerX(ev);
  		var py = Event.pointerY(ev);
  		var pos = Position.cumulativeOffset(this.inputs.background);
 +		
  		var x = this.truncate(px - pos[0],0,255); 
  		var y = this.truncate(py - pos[1],0,255);
 -		var h = this.truncate(this.inputs.H.value,0,360)/360;
  		var s = x/255;
  		var b = (255-y)/255;
 +		var current_s = parseInt(this.inputs.S.value);
 +		var current_b = parseInt(this.inputs.V.value);
 +		
 +		if(current_s == parseInt(s*100) && current_b == parseInt(b*100)) return;
 +
 +		var h = this.truncate(this.inputs.H.value,0,360)/360;
  		var color = new Rico.Color();
  		color.rgb = Rico.Color.HSBtoRGB(h,s,b);
 +
  		this.inputs.selector.style.left = x+"px";
  		this.inputs.selector.style.top = y+"px";
 @@ -403,6 +430,10 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  		var y = this.truncate(py - pos[1],0,255);
  		var h = (255-y)/255;
 +		var current_h = this.truncate(this.inputs.H.value,0,360);
 +		current_h = current_h == 0 ? 360 : current_h;
 +		if(current_h == parseInt(h*360)) return;
 +
  		var s = parseInt(this.inputs.S.value)/100;
  		var b = parseInt(this.inputs.V.value)/100;
  		var color = new Rico.Color();
 @@ -472,14 +503,8 @@ Object.extend(Prado.WebUI.TColorPicker.prototype,  		var images = Prado.WebUI.TColorPicker.UIImages;
  		var changeCss = color.isBright() ? 'removeClassName' : 'addClassName';
 -		Element[changeCss](this.inputs.selector, 'target_white');	
 -/*		if(color.isBright())
 -			Element.removeCssClass(this.inputs.selector, 'target_white');
 -			//this.inputs.selector.src = images['target_black.gif'];
 -		else
 -			Element.addCssClass(this.inputs.selector, 'target_white');
 -			//this.inputs.selector.src = images['target_white.gif'];		
 -*/
 +		Element[changeCss](this.inputs.selector, 'target_white');
 +		
  		if(update)
  			this.updateSelectors(color);
  	},
 diff --git a/framework/Web/Javascripts/datepicker/datepicker.js b/framework/Web/Javascripts/datepicker/datepicker.js index e906120c..79763811 100644 --- a/framework/Web/Javascripts/datepicker/datepicker.js +++ b/framework/Web/Javascripts/datepicker/datepicker.js @@ -1,10 +1,51 @@  Prado.WebUI.TDatePicker = Class.create();
 +Object.extend(Prado.WebUI.TDatePicker,
 +{
 +	/**
 +	 * @return Date the date from drop down list options.
 +	 */
 +	getDropDownDate : function(control)
 +	{
 +		var now=new Date();
 +		var year=now.getFullYear();
 +		var month=now.getMonth();
 +		var day=1;
 +		
 +		var month_list = this.getMonthListControl(control);
 +	 	var day_list = this.getDayListControl(control);
 +	 	var year_list = this.getYearListControl(control);
 +		
 +		var day = day_list ? $F(day_list) : 1;
 +		var month = month_list ? $F(month_list) : now.getMonth();
 +		var year = year_list ? $F(year_list) : now.getFullYear();
 +		
 +		return new Date(year,month,day, 0, 0, 0);
 +	},
 +	
 +	getYearListControl : function(control)
 +	{
 +		return $(control.id+"_year");
 +	},
 +	
 +	getMonthListControl : function(control)
 +	{
 +		return $(control.id+"_month");
 +	},
 +	
 +	getDayListControl : function(control)
 +	{
 +		return $(control.id+"_day");
 +	}
 +});
 +
  Prado.WebUI.TDatePicker.prototype = 
  {
  	MonthNames : [	"January",		"February",		"March",	"April",
  		"May",			"June",			"July",		"August",
  		"September",	"October",		"November",	"December"
  	],
 +	AbbreviatedMonthNames : ["Jan", "Feb", "Mar", "Apr", "May", 
 +						"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
  	ShortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],
 @@ -188,7 +229,7 @@ Prado.WebUI.TDatePicker.prototype =  		var todayButton = document.createElement("button");
  		todayButton.className = "todayButton";
  		var today = this.newDate();
 -		var buttonText = today.SimpleFormat(this.Format);
 +		var buttonText = today.SimpleFormat(this.Format,this);
  		todayButton.appendChild(document.createTextNode(buttonText));
  		div.appendChild(todayButton);
 @@ -386,20 +427,27 @@ Prado.WebUI.TDatePicker.prototype =  		return false;
  	},
 -	onchange : function() 
 +	onChange : function() 
  	{
  		if(this.options.InputMode == "TextBox")
 +		{
  			this.control.value = this.formatDate();
 +			Event.fireEvent(this.control, "change");
 +		}
  		else
  		{
 -			var day = $(this.options.ID+"_day");
 -			var month = $(this.options.ID+"_month");
 -			var year = $(this.options.ID+"_year");
 +			var day = Prado.WebUI.TDatePicker.getDayListControl(this.control);
 +			var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control);
 +			var year = Prado.WebUI.TDatePicker.getYearListControl(this.control);
  			var date = this.selectedDate;
  			if(day)
 +			{
  				day.selectedIndex = date.getDate()-1;
 +			}
  			if(month)
 +			{
  				month.selectedIndex = date.getMonth();
 +			}
  			if(year)
  			{
  				var years = year.options;
 @@ -407,19 +455,20 @@ Prado.WebUI.TDatePicker.prototype =  				for(var i = 0; i < years.length; i++)
  					years[i].selected = years[i].value.toInteger() == currentYear;
  			}
 +			Event.fireEvent(day || month || year, "change");
  		}
  	},
  	formatDate : function()
  	{
 -		return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format) : '';
 +		return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format,this) : '';
  	},
  	newDate : function(date)
  	{
  		if(!date)
  			date = new Date();
 -		if(isString(date)  || isNumber(date))
 +		if(typeof(date) == "string" || typeof(date) == "number")
  			date = new Date(date);
  		return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0,0,0);
  	},
 @@ -432,8 +481,8 @@ Prado.WebUI.TDatePicker.prototype =  		this.updateHeader();
  		this.update();
 -		if (isFunction(this.onchange))
 -			this.onchange();
 +		if (typeof(this.onChange) == "function")
 +			this.onChange();
  	},
  	getElement : function() 
 @@ -443,7 +492,7 @@ Prado.WebUI.TDatePicker.prototype =  	getSelectedDate : function () 
  	{
 -		return isNull(this.selectedDate) ? null : this.newDate(this.selectedDate);
 +		return this.selectedDate == null ? null : this.newDate(this.selectedDate);
  	},
  	setYear : function(year) 
 @@ -480,8 +529,9 @@ Prado.WebUI.TDatePicker.prototype =  				pos[1] += this.control.offsetHeight;
  			else
  			{
 -				if($(this.options.ID+"_day"))
 -					pos[1] += $(this.options.ID+"_day").offsetHeight-1;
 +				var dayList = Prado.WebUI.TDatePicker.getDayListControl(this.control);
 +				if(dayList)
 +					pos[1] += dayList.offsetHeight-1;
  			}
  			this._calDiv.style.display = "block";
 @@ -493,7 +543,7 @@ Prado.WebUI.TDatePicker.prototype =  			this.documentKeyDownEvent = this.keyPressed.bindEvent(this);
  			Event.observe(document.body, "click", this.documentClickEvent);
  			var date = this.getDateFromInput();
 -			if(!isNull(date))
 +			if(date)
  			{
  				this.selectedDate = date;
  				this.setSelectedDate(date);
 @@ -508,20 +558,7 @@ Prado.WebUI.TDatePicker.prototype =  		if(this.options.InputMode == "TextBox")
  			return Date.SimpleParse($F(this.control), this.Format);
  		else
 -		{
 -			var now=new Date();
 -			var year=now.getFullYear();
 -			var month=now.getMonth();
 -			var date=1;
 -			if($(this.options.ID+"_day"))
 -				day = $F(this.options.ID+"_day");
 -			if($(this.options.ID+"_month"))
 -				month = $F(this.options.ID+"_month");
 -			if($(this.options.ID+"_year"))
 -				year = $F(this.options.ID+"_year");
 -			var newdate=new Date(year,month,day, 0, 0, 0);
 -			return newdate;
 -		}
 +			return Prado.WebUI.TDatePicker.getDropDownDate(this.control);
  	},
  	//hide the calendar when clicked outside any calendar
 @@ -610,7 +647,10 @@ Prado.WebUI.TDatePicker.prototype =  	hover : function(ev)
  	{
  		//conditionally add the hover class to the event target element.
 -		Element.condClassName(Event.element(ev), "hover", ev.type=="mouseover");	
 +		if(ev.type == "mouseover")
 +			Event.element(ev).addClassName("hover");
 +		else
 +			Event.element(ev).removeClassName("hover");
  	},
  	updateHeader : function () {
 diff --git a/framework/Web/Javascripts/extended/event.js b/framework/Web/Javascripts/extended/event.js index 40cf60a1..13e875da 100644 --- a/framework/Web/Javascripts/extended/event.js +++ b/framework/Web/Javascripts/extended/event.js @@ -95,9 +95,10 @@ Object.extend(Event,          else if(element.fireEvent)
          {
              element.fireEvent('on'+type);
 -            element[type]();
 +            if(element[type])
 +	            element[type]();
          }
 -        else
 +        else if(element[type])
              element[type]();
  	}
  });
\ No newline at end of file diff --git a/framework/Web/Javascripts/js/colorpicker.js b/framework/Web/Javascripts/js/colorpicker.js index 27e180b0..b926dc93 100644 --- a/framework/Web/Javascripts/js/colorpicker.js +++ b/framework/Web/Javascripts/js/colorpicker.js @@ -257,7 +257,7 @@ this.input.parentNode.appendChild(this.iePopUp);  if(mode == "Full")  this.initializeFullPicker();  } -this.show(); +this.show(mode);  },  show : function(type)  { @@ -276,6 +276,7 @@ Event.observe(document,"keydown", this._documentKeyDownEvent);  this.showing = true;  if(type == "Full")  { +this.observeMouseMovement();  var color = Rico.Color.createFromHex(this.input.value);  this.inputs.oldColor.style.backgroundColor = color.asHex();  this.setColor(color,true); @@ -292,6 +293,11 @@ this.element.style.display = "none";  this.showing = false;  Event.stopObserving(document.body, "click", this._documentClickEvent);  Event.stopObserving(document,"keydown", this._documentKeyDownEvent);  +if(this._observingMouseMove) +{ +Event.stopObserving(document.body, "mousemove", this._onMouseMove); +this._observingMouseMove = false; +}  }  },  keyPressed : function(event,type) @@ -367,7 +373,7 @@ updateColor : function(color)  {  this.input.value = color.toString().toUpperCase();  this.button.style.backgroundColor = color.toString(); -if(isFunction(this.onChange)) +if(typeof(this.onChange) == "function")  this.onChange(color);  },  getFullPickerContainer : function(pickerID) @@ -394,7 +400,7 @@ TD({className:'currentcolor',colSpan:2},  this.inputs['currentColor'], this.inputs['oldColor'])),  TR(null,  TD(null,'H:'), -TD(null,this.inputs['H'], '°')), +TD(null,this.inputs['H'], '??')),  TR(null,  TD(null,'S:'),  TD(null,this.inputs['S'], '%')), @@ -463,26 +469,39 @@ this._onHueMouseDown = this.onHueMouseDown.bind(this);  this._onMouseUp = this.onMouseUp.bind(this);  this._onMouseMove = this.onMouseMove.bind(this);  Event.observe(this.inputs.background, "mousedown", this._onColorMouseDown); +Event.observe(this.inputs.selector, "mousedown", this._onColorMouseDown);  Event.observe(this.inputs.hue, "mousedown", this._onHueMouseDown); +Event.observe(this.inputs.slider, "mousedown", this._onHueMouseDown);  Event.observe(document.body, "mouseup", this._onMouseUp); -Event.observe(document.body, "mousemove", this._onMouseMove); +this.observeMouseMovement();  Event.observe(this.buttons.Cancel, "click", this.hide.bindEvent(this,this.options['Mode']));  Event.observe(this.buttons.OK, "click", this.onOKClicked.bind(this));  }, +observeMouseMovement : function() +{ +if(!this._observingMouseMove) +{ +Event.observe(document.body, "mousemove", this._onMouseMove); +this._observingMouseMove = true; +} +},  onColorMouseDown : function(ev)  {  this.isMouseDownOnColor = true;  this.onMouseMove(ev); +Event.stop(ev);  },  onHueMouseDown : function(ev)  {  this.isMouseDownOnHue = true;  this.onMouseMove(ev); +Event.stop(ev);  },  onMouseUp : function(ev)  {  this.isMouseDownOnColor = false;  this.isMouseDownOnHue = false; +Event.stop(ev);  },  onMouseMove : function(ev)  { @@ -490,6 +509,7 @@ if(this.isMouseDownOnColor)  this.changeSV(ev);  if(this.isMouseDownOnHue)  this.changeH(ev); +Event.stop(ev);  },  changeSV : function(ev)  { @@ -498,9 +518,12 @@ var py = Event.pointerY(ev);  var pos = Position.cumulativeOffset(this.inputs.background);  var x = this.truncate(px - pos[0],0,255);   var y = this.truncate(py - pos[1],0,255); -var h = this.truncate(this.inputs.H.value,0,360)/360;  var s = x/255;  var b = (255-y)/255; +var current_s = parseInt(this.inputs.S.value); +var current_b = parseInt(this.inputs.V.value); +if(current_s == parseInt(s*100) && current_b == parseInt(b*100)) return; +var h = this.truncate(this.inputs.H.value,0,360)/360;  var color = new Rico.Color();  color.rgb = Rico.Color.HSBtoRGB(h,s,b);  this.inputs.selector.style.left = x+"px"; @@ -514,6 +537,9 @@ var py = Event.pointerY(ev);  var pos = Position.cumulativeOffset(this.inputs.background);  var y = this.truncate(py - pos[1],0,255);  var h = (255-y)/255; +var current_h = this.truncate(this.inputs.H.value,0,360); +current_h = current_h == 0 ? 360 : current_h; +if(current_h == parseInt(h*360)) return;  var s = parseInt(this.inputs.S.value)/100;  var b = parseInt(this.inputs.V.value)/100;  var color = new Rico.Color(); diff --git a/framework/Web/Javascripts/js/datepicker.js b/framework/Web/Javascripts/js/datepicker.js index e82507ea..19d39bbe 100644 --- a/framework/Web/Javascripts/js/datepicker.js +++ b/framework/Web/Javascripts/js/datepicker.js @@ -1,10 +1,41 @@  Prado.WebUI.TDatePicker = Class.create(); +Object.extend(Prado.WebUI.TDatePicker, +{ +getDropDownDate : function(control) +{ +var now=new Date(); +var year=now.getFullYear(); +var month=now.getMonth(); +var day=1; +var month_list = this.getMonthListControl(control); + var day_list = this.getDayListControl(control); + var year_list = this.getYearListControl(control); +var day = day_list ? $F(day_list) : 1; +var month = month_list ? $F(month_list) : now.getMonth(); +var year = year_list ? $F(year_list) : now.getFullYear(); +return new Date(year,month,day, 0, 0, 0); +}, +getYearListControl : function(control) +{ +return $(control.id+"_year"); +}, +getMonthListControl : function(control) +{ +return $(control.id+"_month"); +}, +getDayListControl : function(control) +{ +return $(control.id+"_day"); +} +});  Prado.WebUI.TDatePicker.prototype =   {  MonthNames : ["January","February","March","April",  "May","June","July","August",  "September","October","November","December"  ], +AbbreviatedMonthNames : ["Jan", "Feb", "Mar", "Apr", "May",  +"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],  ShortWeekDayNames : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ],  Format : "yyyy-MM-dd",  FirstDayOfWeek : 1, @@ -138,7 +169,7 @@ this._calDiv.appendChild(div);  var todayButton = document.createElement("button");  todayButton.className = "todayButton";  var today = this.newDate(); -var buttonText = today.SimpleFormat(this.Format); +var buttonText = today.SimpleFormat(this.Format,this);  todayButton.appendChild(document.createTextNode(buttonText));  div.appendChild(todayButton);  if(Prado.Browser().ie) @@ -292,20 +323,27 @@ var m = d.getMonth() + n;  this.setMonth(m);  return false;  }, -onchange : function()  +onChange : function()   {  if(this.options.InputMode == "TextBox") +{  this.control.value = this.formatDate(); +Event.fireEvent(this.control, "change"); +}  else  { -var day = $(this.options.ID+"_day"); -var month = $(this.options.ID+"_month"); -var year = $(this.options.ID+"_year"); +var day = Prado.WebUI.TDatePicker.getDayListControl(this.control); +var month = Prado.WebUI.TDatePicker.getMonthListControl(this.control); +var year = Prado.WebUI.TDatePicker.getYearListControl(this.control);  var date = this.selectedDate;  if(day) +{  day.selectedIndex = date.getDate()-1; +}  if(month) +{  month.selectedIndex = date.getMonth(); +}  if(year)  {  var years = year.options; @@ -313,17 +351,18 @@ var currentYear = date.getFullYear();  for(var i = 0; i < years.length; i++)  years[i].selected = years[i].value.toInteger() == currentYear;  } +Event.fireEvent(day || month || year, "change");  }  },  formatDate : function()  { -return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format) : ''; +return this.selectedDate ? this.selectedDate.SimpleFormat(this.Format,this) : '';  },  newDate : function(date)  {  if(!date)  date = new Date(); -if(isString(date)|| isNumber(date)) +if(typeof(date) == "string" || typeof(date) == "number")  date = new Date(date);  return new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0,0,0);  }, @@ -334,8 +373,8 @@ return;  this.selectedDate = this.newDate(date);  this.updateHeader();  this.update(); -if (isFunction(this.onchange)) -this.onchange(); +if (typeof(this.onChange) == "function") +this.onChange();  },  getElement : function()   { @@ -343,7 +382,7 @@ return this._calDiv;  },  getSelectedDate : function ()   { -return isNull(this.selectedDate) ? null : this.newDate(this.selectedDate); +return this.selectedDate == null ? null : this.newDate(this.selectedDate);  },  setYear : function(year)   { @@ -374,8 +413,9 @@ if(this.options.InputMode == "TextBox")  pos[1] += this.control.offsetHeight;  else  { -if($(this.options.ID+"_day")) -pos[1] += $(this.options.ID+"_day").offsetHeight-1; +var dayList = Prado.WebUI.TDatePicker.getDayListControl(this.control); +if(dayList) +pos[1] += dayList.offsetHeight-1;  }  this._calDiv.style.display = "block";  this._calDiv.style.top = (pos[1]-1) + "px"; @@ -385,7 +425,7 @@ this.documentClickEvent = this.hideOnClick.bindEvent(this);  this.documentKeyDownEvent = this.keyPressed.bindEvent(this);  Event.observe(document.body, "click", this.documentClickEvent);  var date = this.getDateFromInput(); -if(!isNull(date)) +if(date)  {  this.selectedDate = date;  this.setSelectedDate(date); @@ -399,20 +439,7 @@ getDateFromInput : function()  if(this.options.InputMode == "TextBox")  return Date.SimpleParse($F(this.control), this.Format);  else -{ -var now=new Date(); -var year=now.getFullYear(); -var month=now.getMonth(); -var date=1; -if($(this.options.ID+"_day")) -day = $F(this.options.ID+"_day"); -if($(this.options.ID+"_month")) -month = $F(this.options.ID+"_month"); -if($(this.options.ID+"_year")) -year = $F(this.options.ID+"_year"); -var newdate=new Date(year,month,day, 0, 0, 0); -return newdate; -} +return Prado.WebUI.TDatePicker.getDropDownDate(this.control);  },  hideOnClick : function(ev)  { @@ -484,7 +511,10 @@ this.dateSlot[index].data.parentNode.className = "empty";  },  hover : function(ev)  { -Element.condClassName(Event.element(ev), "hover", ev.type=="mouseover"); +if(ev.type == "mouseover") +Event.element(ev).addClassName("hover"); +else +Event.element(ev).removeClassName("hover");  },  updateHeader : function () {  var options = this._monthSelect.options; diff --git a/framework/Web/Javascripts/js/prado.js b/framework/Web/Javascripts/js/prado.js index 6737d4ce..c7145188 100644 --- a/framework/Web/Javascripts/js/prado.js +++ b/framework/Web/Javascripts/js/prado.js @@ -1299,9 +1299,10 @@ element.dispatchEvent(event);  else if(element.fireEvent)  {  element.fireEvent('on'+type); +if(element[type])  element[type]();  } -else +else if(element[type])  element[type]();  }  }); @@ -1868,9 +1869,9 @@ lastFocus.value = options['EventTarget'];  }  $('PRADO_POSTBACK_TARGET').value = options['EventTarget'];  $('PRADO_POSTBACK_PARAMETER').value = options['EventParameter']; -Event.fireEvent(form,"submit");  if(options['StopEvent'])   Event.stop(event); +Event.fireEvent(form,"submit");  }  Prado.Element =   { diff --git a/framework/Web/Javascripts/js/validator.js b/framework/Web/Javascripts/js/validator.js index 7d343d87..38d8a2a4 100644 --- a/framework/Web/Javascripts/js/validator.js +++ b/framework/Web/Javascripts/js/validator.js @@ -26,6 +26,7 @@ if(this.managers[formID])  this.managers[formID].addValidator(validator);  else  throw new Error("A validation manager for form '"+formID+"' needs to be created first."); +return this.managers[formID];  },  addSummary : function(formID, validator)  { @@ -33,9 +34,11 @@ if(this.managers[formID])  this.managers[formID].addSummary(validator);  else  throw new Error("A validation manager for form '"+formID+"' needs to be created first."); +return this.managers[formID];  }  }); -Prado.Validation.prototype = +Prado.ValidationManager = Class.create(); +Prado.ValidationManager.prototype =  {  validators : [],  summaries : [], @@ -56,13 +59,12 @@ return this._validateNonGroup();  _validateGroup: function(groupID)  {  var valid = true; -var manager = this;  if(this.groups.include(groupID))  {  this.validators.each(function(validator)  {  if(validator.group == groupID) -valid = valid & validator.validate(manager); +valid = valid & validator.validate();  else  validator.hide();  }); @@ -73,11 +75,10 @@ return valid;  _validateNonGroup : function()  {  var valid = true; -var manager = this;  this.validators.each(function(validator)  {  if(!validator.group) -valid = valid & validator.validate(manager); +valid = valid & validator.validate();  else  validator.hide();  }); @@ -271,8 +272,9 @@ enabled : true,  visible : false,  isValid : true,   options : {}, -_isObserving : false, +_isObserving : {},  group : null, +manager : null,  initialize : function(options)  {  options.OnValidate = options.OnValidate || Prototype.emptyFunction; @@ -282,7 +284,7 @@ this.options = options;  this.control = $(options.ControlToValidate);  this.message = $(options.ID);  this.group = options.ValidationGroup; -Prado.Validation.addValidator(options.FormID, this); +this.manager = Prado.Validation.addValidator(options.FormID, this);  },  getErrorMessage : function()  { @@ -296,6 +298,7 @@ if(this.options.Display == "Dynamic")  this.isValid ? this.message.hide() : this.message.show();  this.message.style.visibility = this.isValid ? "hidden" : "visible";  } +if(this.control)  this.updateControlCssClass(this.control, this.isValid);  if(this.options.FocusOnError && !this.isValid)  Prado.Element.focus(this.options.FocusElementID); @@ -318,33 +321,36 @@ this.isValid = true;  this.updateControl();  this.visible = false;  }, -validate : function(manager) +validate : function()  {  if(this.enabled) -this.isValid = this.evaluateIsValid(manager); -this.options.OnValidate(this, manager); +this.isValid = this.evaluateIsValid(); +this.options.OnValidate(this);  this.updateControl();  if(this.isValid) -this.options.OnSuccess(this, manager); +this.options.OnSuccess(this);  else -this.options.OnError(this, manager); -this.observeChanges(manager); +this.options.OnError(this); +this.observeChanges(this.control);  return this.isValid;  }, -observeChanges : function(manager) +observeChanges : function(control)  { -if(this.options.ObserveChanges != false && !this._isObserving) +if(!control) return; +var canObserveChanges = this.options.ObserveChanges != false; +var currentlyObserving = this._isObserving[control.id+this.options.ID]; +if(canObserveChanges && !currentlyObserving)  {  var validator = this; -Event.observe(this.control, 'change', function() +Event.observe(control, 'change', function()  {  if(validator.visible)  { -validator.validate(manager); -manager.updateSummary(validator.group); +validator.validate(); +validator.manager.updateSummary(validator.group);  }  }); -this._isObserving = true; +this._isObserving[control.id+this.options.ID] = true;  }  },  trim : function(value) @@ -354,7 +360,7 @@ return typeof(value) == "string" ? value.trim() : "";  convert : function(dataType, value)  {  if(typeof(value) == "undefined") -value = $F(this.control); +value = this.getValidationValue();  var string = new String(value);  switch(dataType)  { @@ -363,18 +369,116 @@ return string.toInteger();  case "Double" :  case "Float" :  return string.toDouble(this.options.DecimalChar); -case "Currency" : -return string.toCurrency(this.options.GroupChar, this.options.Digits, this.options.DecimalChar);  case "Date": +if(typeof(value) != "string") +return value; +else +{  var value = string.toDate(this.options.DateFormat);  if(value && typeof(value.getTime) == "function")  return value.getTime();  else  return null; +}  case "String":  return string.toString();  }  return value; +}, +getValidationValue : function(control) + { + if(!control) + control = this.control + switch(this.options.ControlType) + { + case 'TDatePicker': + if(control.type == "text") + return this.trim($F(control)); + else + { + this.observeDatePickerChanges(); +return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime(); + } + default: + if(this.isListControlType()) + return this.getFirstSelectedListValue();  + else + return this.trim($F(control)); + } + }, +observeDatePickerChanges : function() + { + if(Prado.Browser().ie) + { + var DatePicker = Prado.WebUI.TDatePicker; + this.observeChanges(DatePicker.getDayListControl(this.control)); +this.observeChanges(DatePicker.getMonthListControl(this.control)); +this.observeChanges(DatePicker.getYearListControl(this.control)); + } + }, +getSelectedValuesAndChecks : function(elements, initialValue) +{ +var checked = 0; +var values = []; +var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected'; +elements.each(function(element) +{ +if(element[isSelected] && element.value != initialValue) +{ +checked++; +values.push(element.value); +} +}); +return {'checks' : checked, 'values' : values}; +},  +getListElements : function() +{ +switch(this.options.ControlType) +{ +case 'TCheckBoxList': case 'TRadioButtonList': +var elements = []; +for(var i = 0; i < this.options.TotalItems; i++) +{ +var element = $(this.options.ControlToValidate+"_"+i); +if(this.isCheckBoxType(element)) +elements.push(element); +} +return elements; +case 'TListBox': +var elements = []; +var element = $(this.options.ControlToValidate); +if(element && (type = element.type.toLowerCase())) +{  +if(type == "select-one" || type == "select-multiple") +elements = $A(element.options); +} +return elements; +default: +return []; +} +}, +isCheckBoxType : function(element) +{ +if(element && element.type) +{ +var type = element.type.toLowerCase(); +return type == "checkbox" || type == "radio"; +} +return false; +}, +isListControlType : function() +{ +var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox']; +return list.include(this.options.ControlType); +}, +getFirstSelectedListValue : function() +{ +var initial = ""; +if(typeof(this.options.InitialValue) != "undefined") +initial = this.options.InitialValue; +var elements = this.getListElements(); +var selection = this.getSelectedValuesAndChecks(elements, initial); +return selection.values.length > 0 ? selection.values[0] : initial;  }  }  Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,  @@ -388,7 +492,7 @@ return true;  }  else  { -var a = this.trim($F(this.control)); +var a = this.getValidationValue();  var b = this.trim(this.options.InitialValue);  return(a != b);  } @@ -396,41 +500,24 @@ return(a != b);  });  Prado.WebUI.TCompareValidator = Class.extend(Prado.WebUI.TBaseValidator,  { -_observingComparee : false, -evaluateIsValid : function(manager) +evaluateIsValid : function()  { -var value = this.trim($F(this.control)); +var value = this.getValidationValue();  if (value.length <= 0)   return true;  var comparee = $(this.options.ControlToCompare);  if(comparee) -var compareTo = this.trim($F(comparee)); +var compareTo = this.getValidationValue(comparee);  else  var compareTo = this.options.ValueToCompare || "";  var isValid =this.compare(value, compareTo);  if(comparee)  {  this.updateControlCssClass(comparee, isValid); -this.observeComparee(comparee, manager); +this.observeChanges(comparee);  }  return isValid;  }, -observeComparee : function(comparee, manager) -{ -if(this.options.ObserveChanges != false && !this._observingComparee) -{ -var validator = this; -Event.observe(comparee, "change", function() -{ -if(validator.visible) -{ -validator.validate(manager); -manager.updateSummary(validator.group); -} -}); -this._observingComparee = true; -} -},  compare : function(operand1, operand2)  {  var op1, op2; @@ -457,9 +544,9 @@ return (op1 == op2);  });  Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,  { -evaluateIsValid : function(manager) +evaluateIsValid : function()  { -var value = $F(this.control); +var value = this.getValidationValue();  var clientFunction = this.options.ClientValidationFunction;  if(typeof(clientFunction) == "string" && clientFunction.length > 0)  { @@ -471,9 +558,9 @@ return true;  });  Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator,  { -evaluateIsValid : function(manager) +evaluateIsValid : function()  { -var value = this.trim($F(this.control)); +var value = this.getValidationValue();  if(value.length <= 0)  return true;  if(typeof(this.options.DataType) == "undefined") @@ -481,7 +568,6 @@ this.options.DataType = "String";  var min = this.convert(this.options.DataType, this.options.MinValue || null);  var max = this.convert(this.options.DataType, this.options.MaxValue || null);  value = this.convert(this.options.DataType, value); -Logger.warn(min+" <= "+value+" <= "+max);  if(value == null)  return false;  var valid = true; @@ -494,9 +580,9 @@ return valid;  });  Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidator,  { -evaluateIsValid : function(master) +evaluateIsValid : function()  { -var value = this.trim($F(this.control)); +var value = this.getValidationValue();  if (value.length <= 0)   return true;  var rx = new RegExp(this.options.ValidationExpression); @@ -505,3 +591,52 @@ return (matches != null && value == matches[0]);  }  });  Prado.WebUI.TEmailAddressValidator = Prado.WebUI.TRegularExpressionValidator; +Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator, +{ +evaluateIsValid : function() +{ +var elements = this.getListElements(); +if(elements && elements.length <= 0) +return true; +this.observeListElements(elements); +var selection = this.getSelectedValuesAndChecks(elements); +return this.isValidList(selection.checks, selection.values); +}, +observeListElements : function(elements) + { +if(Prado.Browser().ie && this.isCheckBoxType(elements[0])) +{ +var validator = this; +elements.each(function(element) +{ +validator.observeChanges(element); +}); +} + }, +isValidList : function(checked, values) +{ +var exists = true; +var required = this.getRequiredValues(); +if(required.length > 0) +{ +if(values.length < required.length) +return false; +required.each(function(requiredValue) +{ +exists = exists && values.include(requiredValue); +}); +} +var min = typeof(this.options.Min) == "undefined" ?  +Number.NEGATIVE_INFINITY : this.options.Min; +var max = typeof(this.options.Max) == "undefined" ?  +Number.POSITIVE_INFINITY : this.options.Max; +return exists && checked >= min && checked <= max; +}, +getRequiredValues : function() +{ +var required = []; +if(this.options.Required && this.options.Required.length > 0) +required = this.options.Required.split(/,\s*/); +return required; +} +}); diff --git a/framework/Web/Javascripts/prado/form.js b/framework/Web/Javascripts/prado/form.js index addad893..2beb945b 100644 --- a/framework/Web/Javascripts/prado/form.js +++ b/framework/Web/Javascripts/prado/form.js @@ -129,9 +129,9 @@ Prado.PostBack = function(event,options)  	$('PRADO_POSTBACK_TARGET').value = options['EventTarget'];
  	$('PRADO_POSTBACK_PARAMETER').value = options['EventParameter'];
 -	Event.fireEvent(form,"submit");
  	if(options['StopEvent']) 
  		Event.stop(event);
 +	Event.fireEvent(form,"submit");
  }
  /*
 diff --git a/framework/Web/Javascripts/prado/validation3.js b/framework/Web/Javascripts/prado/validation3.js index 10169aab..4c189532 100644 --- a/framework/Web/Javascripts/prado/validation3.js +++ b/framework/Web/Javascripts/prado/validation3.js @@ -1,6 +1,58 @@  /**
 - * Prado client-side javascript validation manager.
 + * Prado client-side javascript validation fascade.
 + * 
 + * There are 4 basic classes, Validation, ValidationManager, ValidationSummary
 + * and TBaseValidator, that interact together to perform validation.
 + * The <tt>Prado.Validation</tt> class co-ordinates together the 
 + * validation scheme and is responsible for maintaining references
 + * to ValidationManagers. 
 + * 
 + * The ValidationManager class is responsible for maintaining refereneces
 + * to individual validators, validation summaries and their associated
 + * groupings.
 + * 
 + * The ValidationSummary take cares of display the validator error messages
 + * as html output or an alert output. 
 + * 
 + * The TBaseValidator is the base class for all validators and contains
 + * methods to interact with the actual inputs, data type conversion.
 + * 
 + * An instance of ValidationManager must be instantiated first for a
 + * particular form before instantiating validators and summaries.
 + * 
 + * Usage example: adding a required field to a text box input with 
 + * ID "input1" in a form with ID "form1".
 + * <code>
 + * <script type="text/javascript" src="../prado.js"></script>
 + * <script type="text/javascript" src="../validator.js"></script>
 + * <form id="form1" action="...">
 + * <div>
 + * 	<input type="text" id="input1" />
 + *  <span id="validator1" style="display:none; color:red">*</span>
 + *  <input type="submit text="submit" />
 + * <script type="text/javascript">
 + * new Prado.ValidationManager({FormID : 'form1'});
 + * var options = 
 + * {
 + *		ID :				'validator1',
 + *		FormID :			'form1',
 + *		ErrorMessage :		'*', 
 + *		ControlToValidate : 'input1'
 + *	}
 + * new Prado.WebUI.TRequiredFieldValidator(options);
 + * new Prado.WebUI.TValidationSummary({ID:'summary1',FormID:'form1'});
 + * 
 + * //watch the form onsubmit event, check validators, stop if not valid.
 + * Event.observe("form1", "submit" function(ev)
 + * {
 + * 	 if(Prado.WebUI.Validation.isValid("form1") == false)
 + * 		Event.stop(ev);
 + * });
 + * </script>
 + * </div>
 + * </form>
 + * </code>
   */
  Prado.Validation =  Class.create();
 @@ -54,6 +106,7 @@ Object.extend(Prado.Validation,  	 * Add a new validator to a particular form.
  	 * @param string the form that the validator belongs.
  	 * @param object a validator
 +	 * @return object the manager
  	 */
  	addValidator : function(formID, validator)
  	{
 @@ -61,12 +114,14 @@ Object.extend(Prado.Validation,  			this.managers[formID].addValidator(validator);
  		else
  			throw new Error("A validation manager for form '"+formID+"' needs to be created first.");
 +		return this.managers[formID];
  	},
  	/**
  	 * Add a new validation summary.
  	 * @param string the form that the validation summary belongs.
  	 * @param object a validation summary
 +	 * @return object manager
  	 */
  	addSummary : function(formID, validator)
  	{
 @@ -74,14 +129,19 @@ Object.extend(Prado.Validation,  			this.managers[formID].addSummary(validator);
  		else
  			throw new Error("A validation manager for form '"+formID+"' needs to be created first.");		
 +		return this.managers[formID];
  	}
  });
 +Prado.ValidationManager = Class.create();
  /**
   * Validation manager instances. Manages validators for a particular 
 - * HTML form.
 + * HTML form. The manager contains references to all the validators
 + * summaries, and their groupings for a particular form.
 + * Generally, <tt>Prado.Validation</tt> methods should be called rather
 + * than calling directly the ValidationManager.
   */
 -Prado.Validation.prototype =
 +Prado.ValidationManager.prototype =
  {
  	validators : [], // list of validators
  	summaries : [], // validation summaries
 @@ -120,13 +180,12 @@ Prado.Validation.prototype =  	_validateGroup: function(groupID)
  	{
  		var valid = true;
 -		var manager = this;
  		if(this.groups.include(groupID))
  		{
  			this.validators.each(function(validator)
  			{
  				if(validator.group == groupID)
 -					valid = valid & validator.validate(manager);
 +					valid = valid & validator.validate();
  				else
  					validator.hide();
  			});
 @@ -142,11 +201,10 @@ Prado.Validation.prototype =  	_validateNonGroup : function()
  	{
  		var valid = true;
 -		var manager = this;
  		this.validators.each(function(validator)
  		{
  			if(!validator.group)
 -				valid = valid & validator.validate(manager);
 +				valid = valid & validator.validate();
  			else
  				validator.hide();
  		});
 @@ -462,8 +520,9 @@ Prado.WebUI.TBaseValidator.prototype =  	visible : false,
  	isValid : true, 
  	options : {},
 -	_isObserving : false,
 +	_isObserving : {},
  	group : null,
 +	manager : null,
  	/**
  	 * <code>
 @@ -493,7 +552,7 @@ Prado.WebUI.TBaseValidator.prototype =  		this.message = $(options.ID);
  		this.group = options.ValidationGroup;
 -		Prado.Validation.addValidator(options.FormID, this);
 +		this.manager = Prado.Validation.addValidator(options.FormID, this);
  	},
  	/**
 @@ -518,7 +577,8 @@ Prado.WebUI.TBaseValidator.prototype =  			this.message.style.visibility = this.isValid ? "hidden" : "visible";
  		}
 -		this.updateControlCssClass(this.control, this.isValid);	
 +		if(this.control)
 +			this.updateControlCssClass(this.control, this.isValid);	
  		if(this.options.FocusOnError && !this.isValid)
  			Prado.Element.focus(this.options.FocusElementID);
 @@ -557,24 +617,23 @@ Prado.WebUI.TBaseValidator.prototype =  	/**
  	 * Calls evaluateIsValid() function to set the value of isValid property.
  	 * Triggers onValidate event and onSuccess or onError event.
 -	 * @param Validation manager
  	 * @return boolean true if valid.
  	 */
 -	validate : function(manager)
 +	validate : function()
  	{
  		if(this.enabled)
 -			this.isValid = this.evaluateIsValid(manager);
 +			this.isValid = this.evaluateIsValid();
 -		this.options.OnValidate(this, manager);
 +		this.options.OnValidate(this);
  		this.updateControl();
  		if(this.isValid)
 -			this.options.OnSuccess(this, manager);
 +			this.options.OnSuccess(this);
  		else
 -			this.options.OnError(this, manager);
 -		
 -		this.observeChanges(manager);
 +			this.options.OnError(this);
 +	
 +		this.observeChanges(this.control);
  		return this.isValid;
  	},
 @@ -582,21 +641,28 @@ Prado.WebUI.TBaseValidator.prototype =  	/**
  	 * Observe changes to the control input, re-validate upon change. If
  	 * the validator is not visible, no updates are propagated.
 +	 * @param HTMLElement control to observe changes
  	 */
 -	observeChanges : function(manager)
 +	observeChanges : function(control)
  	{
 -		if(this.options.ObserveChanges != false && !this._isObserving)
 +		if(!control) return;
 +		
 +		var canObserveChanges = this.options.ObserveChanges != false;
 +		var currentlyObserving = this._isObserving[control.id+this.options.ID];
 +
 +		if(canObserveChanges && !currentlyObserving)
  		{
  			var validator = this;
 -			Event.observe(this.control, 'change', function()
 +			
 +			Event.observe(control, 'change', function()
  			{
  				if(validator.visible)
  				{
 -					validator.validate(manager);
 -					manager.updateSummary(validator.group);
 +					validator.validate();
 +					validator.manager.updateSummary(validator.group);
  				}
  			});
 -			this._isObserving = true;
 +			this._isObserving[control.id+this.options.ID] = true;
  		}
  	},
 @@ -610,14 +676,14 @@ Prado.WebUI.TBaseValidator.prototype =  	/**
  	 * Convert the value to a specific data type.
 -	 * @param {string} the data type, "Integer", "Double", "Currency", "Date" or "String"
 +	 * @param {string} the data type, "Integer", "Double", "Date" or "String"
  	 * @param {string} the value to convert.
  	 * @type {mixed|null} the converted data value.
  	 */
  	convert : function(dataType, value)
  	{
  		if(typeof(value) == "undefined")
 -			value = $F(this.control);
 +			value = this.getValidationValue();
  		var string = new String(value);
  		switch(dataType)
  		{
 @@ -626,18 +692,149 @@ Prado.WebUI.TBaseValidator.prototype =  			case "Double" :
  			case "Float" :
  				return string.toDouble(this.options.DecimalChar);
 -			case "Currency" :
 -				return string.toCurrency(this.options.GroupChar, this.options.Digits, this.options.DecimalChar);
  			case "Date":
 -				var value = string.toDate(this.options.DateFormat);	
 -				if(value && typeof(value.getTime) == "function")
 -					return value.getTime();
 +				if(typeof(value) != "string")
 +					return value;
  				else
 -					return null;
 +				{
 +					var value = string.toDate(this.options.DateFormat);	
 +					if(value && typeof(value.getTime) == "function")
 +						return value.getTime();
 +					else
 +						return null;
 +				}
  			case "String":
  				return string.toString();		
  		}
  		return value;
 +	},
 +	
 +	/**
 +	 * @return mixed control value to validate
 +	 */
 +	 getValidationValue : function(control)
 +	 {
 +	 	if(!control)
 +	 		control = this.control
 +	 	switch(this.options.ControlType)
 +	 	{
 +	 		case 'TDatePicker':
 +	 			if(control.type == "text")
 +	 				return this.trim($F(control));
 +	 			else
 +	 			{
 +	 				this.observeDatePickerChanges();
 +		
 +	 				return Prado.WebUI.TDatePicker.getDropDownDate(control).getTime();
 +	 			}
 +	 		default:
 +	 			if(this.isListControlType())
 +	 				return this.getFirstSelectedListValue();	 			
 +	 			else
 +		 			return this.trim($F(control));
 +	 	}
 +	 },
 +	 
 +	 /**
 +	  * Observe changes in the drop down list date picker, IE only.
 +	  */
 +	 observeDatePickerChanges : function()
 +	 {
 +	 	if(Prado.Browser().ie)
 +	 	{
 +	 		var DatePicker = Prado.WebUI.TDatePicker;
 +	 		this.observeChanges(DatePicker.getDayListControl(this.control));
 +			this.observeChanges(DatePicker.getMonthListControl(this.control));
 +			this.observeChanges(DatePicker.getYearListControl(this.control));
 +	 	}
 +	 },
 +	 
 +	/**
 +	 * Gets numeber selections and their values.
 +	 * @return object returns selected values in <tt>values</tt> property
 +	 * and number of selections in <tt>checks</tt> property.
 +	 */
 +	getSelectedValuesAndChecks : function(elements, initialValue)
 +	{
 +		var checked = 0;
 +		var values = [];
 +		var isSelected = this.isCheckBoxType(elements[0]) ? 'checked' : 'selected';
 +		elements.each(function(element)
 +		{
 +			if(element[isSelected] && element.value != initialValue)
 +			{
 +				checked++;
 +				values.push(element.value);
 +			}
 +		});
 +		return {'checks' : checked, 'values' : values};
 +	},	 
 +	
 +	/**
 +	 * Gets an array of the list control item input elements, for TCheckBoxList
 +	 * checkbox inputs are returned, for TListBox HTML option elements are returned.
 +	 * @return array list control option elements.
 +	 */
 +	getListElements : function()
 +	{
 +		switch(this.options.ControlType)
 +		{
 +			case 'TCheckBoxList': case 'TRadioButtonList':
 +				var elements = [];
 +				for(var i = 0; i < this.options.TotalItems; i++)
 +				{
 +					var element = $(this.options.ControlToValidate+"_"+i);
 +					if(this.isCheckBoxType(element))
 +						elements.push(element);
 +				}
 +				return elements;
 +			case 'TListBox':
 +				var elements = [];
 +				var element = $(this.options.ControlToValidate);
 +				if(element && (type = element.type.toLowerCase()))
 +				{ 
 +					if(type == "select-one" || type == "select-multiple")
 +						elements = $A(element.options);
 +				}
 +				return elements;
 +			default:
 +				return [];
 +		}
 +	},
 +	
 +	/**
 +	 * @return boolean true if element is of checkbox or radio type.
 +	 */
 +	isCheckBoxType : function(element)
 +	{
 +		if(element && element.type)
 +		{
 +			var type = element.type.toLowerCase();
 +			return type == "checkbox" || type == "radio";
 +		}
 +		return false;
 +	},
 +	
 +	/**
 +	 * @return boolean true if control to validate is of some of the TListControl type.
 +	 */
 +	isListControlType : function()
 +	{
 +		var list = ['TCheckBoxList', 'TRadioButtonList', 'TListBox'];
 +		return list.include(this.options.ControlType);
 +	},
 +	
 +	/**
 +	 * @return string gets the first selected list value, initial value if none found.
 +	 */
 +	getFirstSelectedListValue : function()
 +	{
 +		var initial = "";
 +		if(typeof(this.options.InitialValue) != "undefined")
 +			initial = this.options.InitialValue;			
 +		var elements = this.getListElements();		
 +		var selection = this.getSelectedValuesAndChecks(elements, initial);
 +		return selection.values.length > 0 ? selection.values[0] : initial;
  	}
  }
 @@ -664,7 +861,7 @@ Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,      	}
  	    else
  	    {
 -        	var a = this.trim($F(this.control));
 +        	var a = this.getValidationValue();
          	var b = this.trim(this.options.InitialValue);
          	return(a != b);
      	}
 @@ -686,7 +883,6 @@ Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,   * type before the comparison operation is performed. The following value types are supported:
   * - <b>Integer</b> A 32-bit signed integer data type.
   * - <b>Float</b> A double-precision floating point number data type.
 - * - <b>Currency</b> A decimal data type that can contain currency symbols.
   * - <b>Date</b> A date data type. The format can be by the <tt>DateFormat</tt> option.
   * - <b>String</b> A string data type.
   *
 @@ -703,57 +899,35 @@ Prado.WebUI.TRequiredFieldValidator = Class.extend(Prado.WebUI.TBaseValidator,   */
  Prado.WebUI.TCompareValidator = Class.extend(Prado.WebUI.TBaseValidator,
  {
 -	_observingComparee : false,
 +	//_observingComparee : false,
  	/**
  	 * Compares the input to another input or a given value.
  	 */
 -	evaluateIsValid : function(manager)
 +	evaluateIsValid : function()
  	{
 -		var value = this.trim($F(this.control));
 +		var value = this.getValidationValue();
  	    if (value.length <= 0) 
  	    	return true;
      	var comparee = $(this.options.ControlToCompare);
  		if(comparee)
 -			var compareTo = this.trim($F(comparee));
 +			var compareTo = this.getValidationValue(comparee);
  		else
 -			var compareTo = this.options.ValueToCompare || "";
 +			var compareTo = this.options.ValueToCompare || "";		
  	    var isValid =  this.compare(value, compareTo);
  		if(comparee)
  		{
  			this.updateControlCssClass(comparee, isValid);				
 -			this.observeComparee(comparee, manager);
 +			this.observeChanges(comparee);
  		}	
  		return isValid;		
  	},
  	/**
 -	 * Observe the comparee input element for changes. 
 -	 * @param object HTML input element to observe
 -	 * @param object Validation manager.
 -	 */
 -	observeComparee : function(comparee, manager)
 -	{
 -		if(this.options.ObserveChanges != false && !this._observingComparee)
 -		{
 -			var validator = this;	
 -			Event.observe(comparee, "change", function()
 -			{
 -				if(validator.visible)
 -				{
 -					validator.validate(manager);
 -					manager.updateSummary(validator.group);
 -				}
 -			});
 -			this._observingComparee = true;
 -		}
 -	},
 -	
 -	/**
  	 * Compares two values, their values are casted to type defined
  	 * by <tt>DataType</tt> option. False is returned if the first 
  	 * operand converts to null. Returns true if the second operand
 @@ -816,9 +990,9 @@ Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,  	/**
  	 * Calls custom validation function.
  	 */
 -	evaluateIsValid : function(manager)
 +	evaluateIsValid : function()
  	{
 -		var value = $F(this.control);
 +		var value = this.getValidationValue();
  		var clientFunction = this.options.ClientValidationFunction;
  		if(typeof(clientFunction) == "string" && clientFunction.length > 0)
  		{
 @@ -840,7 +1014,6 @@ Prado.WebUI.TCustomValidator = Class.extend(Prado.WebUI.TBaseValidator,   * operation is performed. The following value types are supported:
   * - <b>Integer</b> A 32-bit signed integer data type.
   * - <b>Float</b> A double-precision floating point number data type.
 - * - <b>Currency</b> A decimal data type that can contain currency symbols.
   * - <b>Date</b> A date data type. The date format can be specified by
   *   setting <tt>DateFormat</tt> option, which must be recognizable
   *   by <tt>Date.SimpleParse</tt> javascript function. 
 @@ -856,11 +1029,11 @@ Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator,  {
  	/**
  	 * Compares the input value with a minimum and/or maximum value.
 -	 * Returns true if the value is empty, returns false if conversion fails.
 +	 * @return boolean true if the value is empty, returns false if conversion fails.
  	 */
 -	evaluateIsValid : function(manager)
 +	evaluateIsValid : function()
  	{
 -		var value = this.trim($F(this.control));
 +		var value = this.getValidationValue();
  		if(value.length <= 0)
  			return true;		
  		if(typeof(this.options.DataType) == "undefined")
 @@ -870,8 +1043,6 @@ Prado.WebUI.TRangeValidator = Class.extend(Prado.WebUI.TBaseValidator,  		var max = this.convert(this.options.DataType, this.options.MaxValue || null);
  		value = this.convert(this.options.DataType, value);
 -		Logger.warn(min+" <= "+value+" <= "+max);
 -		
  		if(value == null)
  			return false;
 @@ -897,9 +1068,9 @@ Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidato  	/**
  	 * Compare the control input against a regular expression.
  	 */
 -	evaluateIsValid : function(master)
 +	evaluateIsValid : function()
  	{
 -		var value = this.trim($F(this.control));
 +		var value = this.getValidationValue();
  	    if (value.length <= 0) 
  	    	return true;
 @@ -916,3 +1087,84 @@ Prado.WebUI.TRegularExpressionValidator = Class.extend(Prado.WebUI.TBaseValidato  Prado.WebUI.TEmailAddressValidator = Prado.WebUI.TRegularExpressionValidator;
 +/**
 + * TListControlValidator checks the number of selection and their values
 + * for a TListControl that allows multiple selections. 
 + */
 +Prado.WebUI.TListControlValidator = Class.extend(Prado.WebUI.TBaseValidator,
 +{
 +	/**
 +	 * @return true if the number of selections and/or their values
 +	 * match the requirements.
 +	 */
 +	evaluateIsValid : function()
 +	{
 +		var elements = this.getListElements();
 +		if(elements && elements.length <= 0)
 +			return true;
 +		
 +		this.observeListElements(elements);
 +		
 +		var selection = this.getSelectedValuesAndChecks(elements);
 +		return this.isValidList(selection.checks, selection.values);
 +	},
 +	
 +	/**
 +	 * Observe list elements for IE browsers of changes
 +	 */
 +	 observeListElements : function(elements)
 +	 {
 +		if(Prado.Browser().ie && this.isCheckBoxType(elements[0]))
 +		{
 +			var validator = this;
 +			elements.each(function(element)
 +			{
 +				validator.observeChanges(element);
 +			});
 +		}		
 +	 },
 +	
 +	/**
 +	 * Determine if the number of checked and the checked values
 +	 * satisfy the required number of checks and/or the checked values 
 +	 * equal to the required values.
 +	 * @return boolean true if checked values and number of checks are satisfied.
 +	 */
 +	isValidList : function(checked, values)
 +	{	
 +		var exists = true;
 +		
 +		//check the required values
 +		var required = this.getRequiredValues();
 +		if(required.length > 0)
 +		{
 +			if(values.length < required.length)
 +				return false;
 +			required.each(function(requiredValue)
 +			{
 +				exists = exists && values.include(requiredValue);			
 +			});
 +		}
 +		
 +		var min = typeof(this.options.Min) == "undefined" ? 
 +					Number.NEGATIVE_INFINITY : this.options.Min;
 +		var max = typeof(this.options.Max) == "undefined" ? 
 +					Number.POSITIVE_INFINITY : this.options.Max;
 +		return exists && checked >= min && checked <= max;
 +	},
 +	
 +	/**
 +	 * @return array list of required options that must be selected.
 +	 */
 +	getRequiredValues : function()
 +	{
 +		var required = [];
 +		if(this.options.Required && this.options.Required.length > 0)
 +			required = this.options.Required.split(/,\s*/);
 +		return required;
 +	}
 +});
 +
 +
 +
 +
 diff --git a/framework/Web/UI/WebControls/TBaseValidator.php b/framework/Web/UI/WebControls/TBaseValidator.php index c5b5e7a5..adbc85ae 100644 --- a/framework/Web/UI/WebControls/TBaseValidator.php +++ b/framework/Web/UI/WebControls/TBaseValidator.php @@ -131,6 +131,7 @@ abstract class TBaseValidator extends TLabel implements IValidator  	 */  	protected function getClientScriptOptions()  	{ +		$control = $this->getValidationTarget();  		$options['ID'] = $this->getClientID();  		$options['FormID'] = $this->getPage()->getForm()->getClientID();  		$options['Display'] = $this->getDisplay(); @@ -141,8 +142,9 @@ abstract class TBaseValidator extends TLabel implements IValidator  			$options['FocusElementID'] = $this->getFocusElementID();  		}  		$options['ValidationGroup'] = $this->getValidationGroup(); -		$options['ControlToValidate'] = $this->getValidationTarget()->getClientID(); +		$options['ControlToValidate'] = $control->getClientID();  		$options['ControlCssClass'] = $this->getControlCssClass(); +		$options['ControlType'] = get_class($control);  		return $options;  	} @@ -163,7 +165,7 @@ abstract class TBaseValidator extends TLabel implements IValidator  			$manager['FormID'] = $formID;  			$options = TJavaScript::encode($manager);   			$scripts->registerPradoScript('validator'); -			$scripts->registerEndScript($scriptKey, "new Prado.Validation({$options});"); +			$scripts->registerEndScript($scriptKey, "new Prado.ValidationManager({$options});");  		}  		if($this->getEnableClientScript())  			$this->registerClientScriptValidator(); diff --git a/framework/Web/UI/WebControls/TCheckBox.php b/framework/Web/UI/WebControls/TCheckBox.php index ff7f57f7..681c8748 100644 --- a/framework/Web/UI/WebControls/TCheckBox.php +++ b/framework/Web/UI/WebControls/TCheckBox.php @@ -340,7 +340,7 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl  		if($clientID!=='')
  			$writer->addAttribute('id',$clientID);
  		$writer->addAttribute('type','checkbox');
 -		if(($value=$this->getValueAttribute())!=='')
 +		if(($value = $this->getValueAttribute()) !== '')
  			$writer->addAttribute('value',$value);
  		if(($uniqueID=$this->getUniqueID())!=='')
  			$writer->addAttribute('name',$uniqueID);
 @@ -378,4 +378,4 @@ class TCheckBox extends TWebControl implements IPostBackDataHandler, IValidatabl  }
 -?>
\ No newline at end of file +?>
 diff --git a/framework/Web/UI/WebControls/TCheckBoxList.php b/framework/Web/UI/WebControls/TCheckBoxList.php index 2f0cce7c..de332897 100644 --- a/framework/Web/UI/WebControls/TCheckBoxList.php +++ b/framework/Web/UI/WebControls/TCheckBoxList.php @@ -47,7 +47,7 @@ Prado::using('System.Web.UI.WebControls.TCheckBox');   * @package System.Web.UI.WebControls
   * @since 3.0
   */
 -class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler
 +class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingContainer, IPostBackDataHandler,  IValidatable
  {
  	private $_repeatedControl;
  	private $_isEnabled;
 @@ -381,6 +381,16 @@ class TCheckBoxList extends TListControl implements IRepeatInfoUser, INamingCont  			$this->setTabIndex($tabIndex);
  		}
  	}
 +	
 +	/**
 +	 * 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->getSelectedValue();
 +	}	
  }
  ?>
\ No newline at end of file diff --git a/framework/Web/UI/WebControls/TCompareValidator.php b/framework/Web/UI/WebControls/TCompareValidator.php index 172e472f..b5ebd3ab 100644 --- a/framework/Web/UI/WebControls/TCompareValidator.php +++ b/framework/Web/UI/WebControls/TCompareValidator.php @@ -31,7 +31,6 @@ Prado::using('System.Web.UI.WebControls.TBaseValidator');   * type before the comparison operation is performed. The following value types are supported:
   * - <b>Integer</b> A 32-bit signed integer data type.
   * - <b>Float</b> A double-precision floating point number data type.
 - * - <b>Currency</b> A decimal data type that can contain currency symbols.
   * - <b>Date</b> A date data type. The format can be specified by the 
   * {@link setDateFormat DateFormat} property 
   * - <b>String</b> A string data type.
 @@ -56,12 +55,13 @@ class TCompareValidator extends TBaseValidator  	}
  	/**
 -	 * Sets the data type (Integer, Float, Currency, Date, String) that the values being compared are converted to before the comparison is made.
 +	 * Sets the data type (Integer, Float, Date, String) that the values being
 +	 * compared are converted to before the comparison is made.
  	 * @param string the data type
  	 */
  	public function setDataType($value)
  	{
 -		$this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','Currency','String'),'String');
 +		$this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','String'),'String');
  	}
  	/**
 @@ -188,16 +188,6 @@ class TCompareValidator extends TBaseValidator  				return array(intval($value1), intval($value2));
  			case 'Float':
  				return array(floatval($value1), floatval($value2));
 -			case 'Currency':
 -				if(preg_match('/[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?/',$value1,$matches))
 -					$value1=floatval($matches[0]);
 -				else
 -					$value1=0;
 -				if(preg_match('/[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?/',$value2,$matches))
 -					$value2=floatval($matches[0]);
 -				else
 -					$value2=0;
 -				return array($value1, $value2);
  			case 'Date':
  				$dateFormat = $this->getDateFormat();
  				if($dateFormat!=='')
 diff --git a/framework/Web/UI/WebControls/TDataTypeValidator.php b/framework/Web/UI/WebControls/TDataTypeValidator.php index 81c23ce4..d78be7bf 100644 --- a/framework/Web/UI/WebControls/TDataTypeValidator.php +++ b/framework/Web/UI/WebControls/TDataTypeValidator.php @@ -23,7 +23,6 @@ Prado::using('System.Web.UI.WebControls.TBaseValidator');   * The following data types are supported:
   * - <b>Integer</b> A 32-bit signed integer data type.
   * - <b>Float</b> A double-precision floating point number data type.
 - * - <b>Currency</b> A decimal data type that can contain currency symbols.
   * - <b>Date</b> A date data type.
   * - <b>String</b> A string data type.
   * For <b>Date</b> type, the property {@link setDateFormat DateFormat}
 @@ -46,12 +45,13 @@ class TDataTypeValidator extends TBaseValidator  	}
  	/**
 -	 * Sets the data type (Integer, Float, Currency, Date, String) that the values being compared are converted to before the comparison is made.
 +	 * Sets the data type (Integer, Float, Date, String) that the values being
 +	 * compared are converted to before the comparison is made.
  	 * @param string the data type
  	 */
  	public function setDataType($value)
  	{
 -		$this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','Currency','String'),'String');
 +		$this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','String'),'String');
  	}
  	/**
 @@ -85,8 +85,6 @@ class TDataTypeValidator extends TBaseValidator  				return preg_match('/^[-+]?[0-9]+$/',trim($value));
  			case 'Float':
  				return preg_match('/^[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
 -			case 'Currency':
 -				return preg_match('/[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?$/',trim($value));
  			case 'Date':
  				$dateFormat = $this->getDateFormat();
  				if(strlen($dateFormat))
 diff --git a/framework/Web/UI/WebControls/TDatePicker.php b/framework/Web/UI/WebControls/TDatePicker.php index c6a2345b..02386515 100644 --- a/framework/Web/UI/WebControls/TDatePicker.php +++ b/framework/Web/UI/WebControls/TDatePicker.php @@ -245,17 +245,16 @@ class TDatePicker extends TTextBox  	/**
  	 * @return integer current selected date from the date picker as timestamp.
  	 */
 -	public function getDate()
 +	public function getTimeStamp()
  	{
 -		$date = $this->getDateFromText();
 -		return $date[0];
 +		return $this->getTimeStampFromText();
  	}
  	/**
  	 * Sets the date for the date picker using timestamp.
  	 * @param integer time stamp for the date picker
  	 */
 -	public function setDate($value)
 +	public function setTimeStamp($value)
  	{
  		$date = TPropertyValue::ensureInteger($value);
  		$formatter = Prado::createComponent('System.Util.TSimpleDateFormatter',
 @@ -264,6 +263,34 @@ class TDatePicker extends TTextBox  	}
  	/**
 +	 * @return string the date string.
 +	 */
 +	public function getDate()
 +	{
 +		return $this->getText();
 +	}
 +	
 +	/**
 +	 * @param string date string
 +	 */
 +	public function setDate($value)
 +	{
 +		$this->setText($value);
 +	}
 +
 +	/**
 +	 * Returns the value to be validated.
 +	 * This methid is required by IValidatable interface.
 +	 * @return integer the value of the property to be validated.
 +	 */
 +	public function getValidationPropertyValue()
 +	{
 +		if($this->getText() === '')
 +			return '';
 +		return $this->getTimeStamp();
 +	}
 +
 +	/**
  	 * Publish the date picker Css asset files.
  	 */
  	public function onPreRender($param)
 @@ -396,6 +423,7 @@ class TDatePicker extends TTextBox  		$date = $this->getLocalizedCalendarInfo();
  		$options['MonthNames'] = TJavaScript::encode($date->getMonthNames(),false);
 +		$options['AbbreviatedMonthNames'] = TJavaScript::encode($date->getAbbreviatedMonthNames(),false);
  		$options['ShortWeekDayNames'] = TJavaScript::encode($date->getAbbreviatedDayNames(),false);
  		return $options;
 @@ -439,7 +467,8 @@ class TDatePicker extends TTextBox  			$writer->addAttribute('class', $class);
  		$writer->renderBeginTag('span');
 -		$date = $this->getDateFromText();
 +		$date = @getdate($this->getTimeStampFromText());
 +
  		$this->renderCalendarSelections($writer, $date);
  		//render a hidden input field
 @@ -481,9 +510,9 @@ class TDatePicker extends TTextBox  	/**
  	 * Gets the date from the text input using TSimpleDateFormatter
 -	 * @return array current selected date
 +	 * @return integer current selected date timestamp
  	 */
 -	protected function getDateFromText()
 +	protected function getTimeStampFromText()
  	{
  		$pattern = $this->getDateFormat();
  		$pattern = str_replace(array('MMMM', 'MMM'), array('MM','MM'), $pattern);
 @@ -559,7 +588,7 @@ class TDatePicker extends TTextBox  			case 'MMM':
  			case 'MM': return $info->getAbbreviatedMonthNames();
  			case 'M':
 -				$array = array(); for($i=1;$i<=12;$i++) $array[$i] = $i;
 +				$array = array(); for($i=1;$i<=12;$i++) $array[$i-1] = $i;
  				return $array;
  			default :	return $info->getMonthNames();
  		}
 diff --git a/framework/Web/UI/WebControls/THtmlArea.php b/framework/Web/UI/WebControls/THtmlArea.php index 7e47d638..8e5fcd16 100644 --- a/framework/Web/UI/WebControls/THtmlArea.php +++ b/framework/Web/UI/WebControls/THtmlArea.php @@ -315,7 +315,7 @@ class THtmlArea extends TTextBox  		//default the variant to "en"
  		if(count($variants) == 0)
  		{
 -			if($empty($culture))
 +			if(empty($culture))
  				return 'en';
  			$variants[] = strtolower($culture);
  		}
 diff --git a/framework/Web/UI/WebControls/TListControlValidator.php b/framework/Web/UI/WebControls/TListControlValidator.php new file mode 100644 index 00000000..9264e891 --- /dev/null +++ b/framework/Web/UI/WebControls/TListControlValidator.php @@ -0,0 +1,214 @@ +<?php
 +
 +/**
 + * TListControlValidator class file
 + *
 + * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2005 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Revision: $  $Date: $
 + * @package System.Web.UI.WebControls
 + */
 + 
 +/**
 + * Using TBaseValidator class
 + */
 +Prado::using('System.Web.UI.WebControls.TBaseValidator');
 +
 +/**
 + * TListControlValidator class.
 + * 
 + * TListControlValidator checks the number of selection and their values
 + * for a <b>TListControl that allows multiple selection</b>. 
 + *
 + * You can specify the minimum or maximum (or both) number of selections
 + * required using the {@link setMinSelection MinSelection} and
 + * {@link setMaxSelection MaxSelection} properties, respectively. In addition,
 + * you can specify a comma separated list of required selected values via the
 + * {@link setRequiredSelections RequiredSelections} property.
 + *
 + * Examples
 + * - At least two selections
 + * <code>
 + *	<com:TListBox ID="listbox" SelectionMode="Multiple">
 + *		<com:TListItem Text="item1" Value="value1" />
 + *		<com:TListItem Text="item2" Value="value2" />
 + *		<com:TListItem Text="item3" Value="value3" />
 + *	</com:TListBox>
 + *
 + *	<com:TRequiredListValidator 
 + *		ControlToValidate="listbox"
 + *		MinSelection="2" 
 + *		ErrorMessage="Please select at least 2" />
 + * </code>
 + * - "value1" must be selected <b>and</b> at least 1 other
 + * <code>
 + *	<com:TCheckBoxList ID="checkboxes">
 + *		<com:TListItem Text="item1" Value="value1" />
 + *		<com:TListItem Text="item2" Value="value2" />
 + *		<com:TListItem Text="item3" Value="value3" />		
 + *	</com:TCheckBoxList>
 + *
 + *	<com:TRequiredListValidator 
 + *		ControlToValidate="checkboxes"
 + *		RequiredSelections="value1"
 + *		MinSelection="2"
 + *		ErrorMessage="Please select 'item1' and at least 1 other" /> 
 + * </code>
 + *
 + * @author Xiang Wei Zhuo <weizhuo[at]gmail.com>
 + * @version $Revision: $  $Date: $
 + * @package System.Web.UI.WebControls
 + * @since 3.0
 + */
 +class TListControlValidator extends TBaseValidator
 +{	
 +	/**
 +	 * @return int min number of selections 
 +	 */
 +	function getMinSelection()
 +	{
 +		return $this->getViewState('MinSelection','');
 +	}
 +	
 +	/**
 +	 * @param int minimum number of selections.
 +	 */
 +	function setMinSelection($value)
 +	{
 +		$this->setViewState('MinSelection',$value,'');
 +	}
 +	
 +	/**
 +	 * @return int max number of selections 
 +	 */
 +	function getMaxSelection()
 +	{
 +		return $this->getViewState('MaxSelection','');
 +	}
 +	
 +	/**
 +	 * @param int max number of selections.
 +	 */	
 +	function setMaxSelection($value)
 +	{
 +		$this->setViewState('MaxSelection',$value,'');
 +	}
 +
 +	/**
 +	 * Get a comma separated list of required selected values.
 +	 * @return string comma separated list of required values. 
 +	 */
 +	function getRequiredSelections()
 +	{
 +		return $this->getViewState('RequiredSelections','');
 +	}
 +		
 +	/**
 +	 * Set the list of required values, using aa comma separated list.
 +	 * @param string comma separated list of required values. 
 +	 */
 +	function setRequiredSelections($value)
 +	{
 +		$this->setViewState('RequiredSelections',$value,'');
 +	}	
 +	
 +	/**
 +	 * This method overrides the parent's implementation.
 +	 * The validation succeeds if the input component changes its data
 +	 * from the InitialValue or the input component is not given.
 +	 * @return boolean whether the validation succeeds
 +	 */
 +	public function evaluateIsValid()
 +	{		
 +		$control=$this->getValidationTarget();
 +		
 +		$exists = true;
 +		list($count, $values) = $this->getSelection($control);
 +		$required = $this->getRequiredValues();
 +		
 +		//if required, check the values
 +		if(!empty($required))
 +		{
 +			if(count($values) < count($required) ) 
 +				return false;
 +			foreach($required as $require)
 +				$exists = $exists && in_array($require, $values);
 +		}
 +		
 +		$min = $this->getMinSelection();
 +		$max = $this->getMaxSelection();
 +		
 +		if($min !== '' && $max !=- '')
 +			return $exists && $count >= intval($min) && $count <= intval($max);
 +		else if($min === '' && $max !== '')
 +			return $exists && $count <= intval($max);
 +		else if($min !== '' && $max === '')
 +			return $exists && $count >= intval($min);		
 +	}	
 +	
 +	/**
 +	 * @param TListControl control to validate
 +	 * @return array number of selected values and its values.
 +	 */
 +	protected function getSelection($control)
 +	{
 +		$count = 0;
 +		$values = array();
 +
 +		//get the data
 +		foreach($control->getItems() as $item)
 +		{
 +			if($item->getSelected()) 
 +			{
 +				$count++;
 +				$values[] = $item->getValue();
 +			}
 +		}
 +		return array($count, $values);		
 +	}
 +	
 +	/**
 +	 * @return array list of required values.
 +	 */
 +	protected function getRequiredValues()
 +	{
 +		$required = array();
 +		$string = $this->getRequiredSelections();
 +		if(!empty($string))
 +			$required = preg_split('/,\s*/', $string);
 +		return $required;
 +	}
 +	
 +	/**
 +	 * Returns an array of javascript validator options.
 +	 * @return array javascript validator options.
 +	 */
 +	protected function getClientScriptOptions()
 +	{
 +		$options = parent::getClientScriptOptions();
 +		$control = $this->getValidationTarget();
 +		
 +		if(!$control instanceof TListControl)
 +		{
 +			throw new TConfigurationException(
 +				'tlistcontrolvalidator_invalid_control', 
 +				$this->getID(),$this->getControlToValidate(), get_class($control));
 +		}
 +		
 +		$min = $this->getMinSelection();
 +		$max = $this->getMaxSelection();
 +		if($min !== '')
 +			$options['Min']= intval($min);
 +		if($max !== '')
 +			$options['Max']= intval($max);
 +		$required = $this->getRequiredSelections();
 +		if(strlen($required) > 0)
 +			$options['Required']= $required;
 +		$options['TotalItems'] = $control->getItemCount();
 +
 +		return $options;
 +	}	
 +}
 +?>
\ No newline at end of file diff --git a/framework/Web/UI/WebControls/TRadioButton.php b/framework/Web/UI/WebControls/TRadioButton.php index 9a523b55..fd13e88c 100644 --- a/framework/Web/UI/WebControls/TRadioButton.php +++ b/framework/Web/UI/WebControls/TRadioButton.php @@ -101,14 +101,14 @@ class TRadioButton extends TCheckBox  		$this->setViewState('GroupName',$value,'');
  	}
 -	protected function getValueAttribute()
 +/*	protected function getValueAttribute()
  	{
  		if(($value=parent::getValueAttribute())==='')
  			return $this->getUniqueID();
  		else
  			return $value;
  	}
 -
 +*/
  	/**
  	 * @return string the name used to fetch radiobutton post data
  	 */
 @@ -146,7 +146,8 @@ class TRadioButton extends TCheckBox  			$writer->addAttribute('id',$clientID);
  		$writer->addAttribute('type','radio');
  		$writer->addAttribute('name',$this->getUniqueGroupName());
 -		$writer->addAttribute('value',$this->getValueAttribute());
 +		if(($value =  $this->getValueAttribute()) !== '')
 +			$writer->addAttribute('value',$value);
  		if($this->getChecked())
  			$writer->addAttribute('checked','checked');
  		if(!$this->getEnabled(true))
 diff --git a/framework/Web/UI/WebControls/TRangeValidator.php b/framework/Web/UI/WebControls/TRangeValidator.php index 56cc16bc..b7387522 100644 --- a/framework/Web/UI/WebControls/TRangeValidator.php +++ b/framework/Web/UI/WebControls/TRangeValidator.php @@ -29,7 +29,6 @@ Prado::using('System.Web.UI.WebControls.TBaseValidator');   * operation is performed. The following value types are supported:
   * - <b>Integer</b> A 32-bit signed integer data type.
   * - <b>Float</b> A double-precision floating point number data type.
 - * - <b>Currency</b> A decimal data type that can contain currency symbols.
   * - <b>Date</b> A date data type. The date format can be specified by
   *   setting {@link setDateFormat DateFormat} property, which must be recognizable
   *   by {@link TSimpleDateFormatter}. If the property is not set,
 @@ -87,13 +86,13 @@ class TRangeValidator extends TBaseValidator  	}
  	/**
 -	 * Sets the data type (Integer, Float, Currency, Date, String) that the values
 -	 * being compared are converted to before the comparison is made.
 +	 * Sets the data type (Integer, Float, Date, String) that the values being
 +	 * compared are converted to before the comparison is made.
  	 * @param string the data type
  	 */
  	public function setDataType($value)
  	{
 -		$this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','Currency','String'),'String');
 +		$this->setViewState('DataType',TPropertyValue::ensureEnum($value,'Integer','Float','Date','String'),'String');
  	}
  	/**
 @@ -131,8 +130,6 @@ class TRangeValidator extends TBaseValidator  				return $this->isValidInteger($value);
  			case 'Float':
  				return $this->isValidFloat($value);
 -			case 'Currency':
 -				return $this->isValidCurrency($value);
  			case 'Date':
  				return $this->isValidDate($value);
  			default:
 @@ -179,38 +176,6 @@ class TRangeValidator extends TBaseValidator  	}
  	/**
 -	 * Determine if the value is a valid currency range,
 -	 * @param string currency value
 -	 * @return boolean true if within range.
 -	 */
 -	protected function isValidCurrency($value)
 -	{
 -		$minValue=$this->getMinValue();
 -		$maxValue=$this->getMaxValue();
 -
 -		$valid=true;
 -		$value = $this->getCurrencyValue($value);
 -		if($minValue!=='')
 -			$valid=$valid && ($value>= $this->getCurrencyValue($minValue));
 -		if($maxValue!=='')
 -			$valid=$valid && ($value<= $this->getCurrencyValue($minValue));
 -		return $valid;
 -	}
 -
 -	/**
 -	 * Parse the string into a currency value, return the float value of the currency.
 -	 * @param string currency as string
 -	 * @return float currency value.
 -	 */
 -	protected function getCurrencyValue($value)
 -	{
 -		if(preg_match('/[-+]?([0-9]*\.)?[0-9]+([eE][-+]?[0-9]+)?/',$value,$matches))
 -			return floatval($matches[0]);
 -		else
 -			return 0.0;
 -	}
 -
 -	/**
  	 * Determine if the date is within the specified range.
  	 * Uses pradoParseDate and strtotime to get the date from string.
  	 * @param string date as string to validate
 diff --git a/framework/Web/UI/WebControls/TRequiredFieldValidator.php b/framework/Web/UI/WebControls/TRequiredFieldValidator.php index ddbb12c8..04e333eb 100644 --- a/framework/Web/UI/WebControls/TRequiredFieldValidator.php +++ b/framework/Web/UI/WebControls/TRequiredFieldValidator.php @@ -21,6 +21,9 @@ Prado::using('System.Web.UI.WebControls.TBaseValidator');   * TRequiredFieldValidator makes the associated input control a required field.
   * The input control fails validation if its value does not change from
   * the {@link setInitialValue InitialValue} property upon losing focus.
 + * 
 + * Validation will also succeed if input is of TListControl type and the number
 + * of selected values different from the initial value is greater than zero.
   *
   * @author Qiang Xue <qiang.xue@gmail.com>
   * @version $Revision: $  $Date: $
 @@ -53,12 +56,32 @@ class TRequiredFieldValidator extends TBaseValidator  	 * This method overrides the parent's implementation.
  	 * The validation succeeds if the input component changes its data
  	 * from the {@link getInitialValue InitialValue} or the input control is not given.
 +	 * 
 +	 * Validation will also succeed if input is of TListControl type and the
 +	 * number of selected values different from the initial value is greater
 +	 * than zero.
 +	 * 
  	 * @return boolean whether the validation succeeds
  	 */
  	protected function evaluateIsValid()
  	{
 -		$value=$this->getValidationValue($this->getValidationTarget());
 -		return trim($value)!==trim($this->getInitialValue()) || (is_bool($value) && $value);
 +		$control = $this->getValidationTarget();
 +		$initial = trim($this->getInitialValue());
 +		if($control instanceof TListControl)
 +		{
 +			$count = 0;
 +			foreach($control->getItems() as $item)
 +			{
 +				if($item->getSelected() && $item->getValue() != $initial)
 +					$count++;
 +			}
 +			return $count > 0;
 +		}
 +		else
 +		{
 +			$value=$this->getValidationValue($control);
 +			return trim($value)!==$initial || (is_bool($value) && $value);
 +		}
  	}
  	/**
 @@ -69,6 +92,9 @@ class TRequiredFieldValidator extends TBaseValidator  	{
  		$options = parent::getClientScriptOptions();
  		$options['InitialValue']=$this->getInitialValue();
 +		$control = $this->getValidationTarget();
 +		if($control instanceof TListControl)
 +			$options['TotalItems'] = $control->getItemCount();
  		return $options;
  	}
  }
  | 
