diff --git a/core/control/Controller.php b/core/control/Controller.php index a7a550465..2e7cfe12a 100644 --- a/core/control/Controller.php +++ b/core/control/Controller.php @@ -119,12 +119,22 @@ class Controller extends ViewableData { if($form){ $form->loadDataFrom($this->requestParams, true); // disregard validation if a single field is called + + if(!isset($_REQUEST['action_callfieldmethod'])) { $valid = $form->beforeProcessing(); if(!$valid) { $this->popCurrent(); return $this->response; } + }else{ + $fieldcaller = $form->dataFieldByName($requestParams['fieldName']); + if(is_a($fieldcaller, "TableListField")){ + if($fieldcaller->hasMethod('php')){ + $valid = $fieldcaller->php($requestParams); + if(!$valid) exit(); + } + } } // If the action wasnt' set, choose the default on the form. diff --git a/core/model/DataObject.php b/core/model/DataObject.php index bff4cff67..65b28beea 100644 --- a/core/model/DataObject.php +++ b/core/model/DataObject.php @@ -202,6 +202,18 @@ class DataObject extends Controller { return ($this->record && $this->record['ID'] > 0); } + public function isEmpty(){ + $isEmpty = true; + if($this->record){ + foreach($this->record as $k=>$v){ + if($k != "ID"){ + $isEmpty = $isEmpty && !$v; + } + } + } + return $isEmpty; + } + /** * Get the user friendly singular name of this DataObject. * If the name is not defined (by redefining $singular_name in the subclass), diff --git a/forms/CompositeField.php b/forms/CompositeField.php index 1ff2782c1..fc3229da7 100755 --- a/forms/CompositeField.php +++ b/forms/CompositeField.php @@ -164,6 +164,16 @@ class CompositeField extends FormField { $result .= ""; return $result; } + + function validate($validator){ + + $valid = true; + foreach($this->children as $idx => $child){ + $valid = ($child->validate($validator) && $valid); + } + + return $valid; + } } ?> \ No newline at end of file diff --git a/forms/DateField.php b/forms/DateField.php index 46e37a1de..21ccd5b30 100755 --- a/forms/DateField.php +++ b/forms/DateField.php @@ -20,9 +20,9 @@ class DateField extends TextField { return $field; } - function jsValidation() + function jsValidation($formID = null) { - $formID = $this->form->FormName(); + if(!$formID)$formID = $this->form->FormName(); $jsFunc =<<name');"; +// return "\$('$formID').validateDate('$this->name');"; + return <<name') + $('$formID').validateDate('$this->name'); +}else{ + $('$formID').validateDate('$this->name'); +} +JS; } - function validate() + function validate($validator) { if(!empty ($this->value) && !preg_match('/^[0-9]{1,2}\/[0-9]{1,2}\/[0-90-9]{2,4}$/', $this->value)) { diff --git a/forms/EmailField.php b/forms/EmailField.php index e80b283c3..edb71bc48 100755 --- a/forms/EmailField.php +++ b/forms/EmailField.php @@ -28,7 +28,15 @@ JS; Requirements::customScript($jsFunc, 'func_validateEmailField'); - return "\$('$formID').validateEmailField('$this->name');"; + //return "\$('$formID').validateEmailField('$this->name');"; + return <<name') + $('$formID').validateEmailField('$this->name'); +}else{ + $('$formID').validateEmailField('$this->name'); +} +JS; } function validate($validator){ diff --git a/forms/Form.php b/forms/Form.php index c2353b7b1..c87dc28aa 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -317,6 +317,10 @@ class Form extends ViewableData { return $this->class . '_' . str_replace('.','',$this->name); } + function PureName(){ + return $this->name; + } + /** * Returns the field referenced by $_GET[fieldName]. * Used for embedding entire extra helper forms inside complex field types (such as ComplexTableField) diff --git a/forms/NumericField.php b/forms/NumericField.php index a3b921fdf..c61be9b61 100755 --- a/forms/NumericField.php +++ b/forms/NumericField.php @@ -15,7 +15,7 @@ Behaviour.register({ el = _CURRENT_FORM.elements[fieldName]; if(!el || !el.value) return true; - if(el.value.match(/^([0-9]*$)/)) { + if(el.value.match(/^([0-9]+(\.[0-9]+)?$)/)) { return true; } else { validationError(el, "'" + el.value + "' is not a number, only numbers can be accepted for this field","validation"); @@ -28,7 +28,15 @@ JS; Requirements::customScript($jsFunc, 'func_validateNumericField'); - return "\$('$formID').validateNumericField('$this->name');"; + //return "\$('$formID').validateNumericField('$this->name');"; + return <<name') + $('$formID').validateNumericField('$this->name'); +}else{ + $('$formID').validateNumericField('$this->name'); +} +JS; } /** PHP Validation **/ diff --git a/forms/RequiredFields.php b/forms/RequiredFields.php index e8efcbe04..94cf63c94 100755 --- a/forms/RequiredFields.php +++ b/forms/RequiredFields.php @@ -64,7 +64,15 @@ class RequiredFields extends Validator{ if($this->required) { foreach($this->required as $field) { if($fields->dataFieldByName($field)) { - $js .= "\t\t\t\t\trequire('$field', false, $useLabels);\n"; + //$js .= "\t\t\t\t\trequire('$field', false, $useLabels);\n"; + $js .= <<loadDataFrom($item); $row = new TableField_Item($item, $this, $form, $this->fieldTypes); $fields = array_merge($fields, $row->Fields()->toArray()); } @@ -205,6 +206,42 @@ class TableField extends TableListField { return $fields; } + function SubmittedFieldSet(&$sourceItems){ + $fields = array (); + if($rows = $_POST[$this->name]){ + if(count($rows)){ + foreach($rows as $idx => $row){ + if($idx == 'new'){ + $newitems = ArrayLib::invert($row); + if(count($newitems)){ + $sourceItems = new DataObjectSet(); + foreach($newitems as $k => $newitem){ + $fieldset = $this->FieldSetForRow(); + if($fieldset){ + $newitem[ID] = "new".$k; + foreach($newitem as $k => $v){ + if(array_key_exists($k, $this->extraData)){ + unset($newitem[$k]); + } + } + $sourceItem = new DataObject($newitem); + if(!$sourceItem->isEmpty()){ + $sourceItems->push($sourceItem); + $form = new Form($this, "EditForm", $fieldset, new FieldSet()); + $form->loadDataFrom($sourceItem); + $item = new TableField_Item($sourceItem, $this, $form, $this->fieldTypes); + $fields = array_merge($fields, $item->Fields()->toArray()); + } + } + } + } + } + } + } + } + return $fields; + } + /** * @return array */ @@ -460,17 +497,33 @@ class TableField extends TableListField { $js = ""; $fields = $this->FieldSet(); + $fields = new FieldSet($fields); // TODO doesn't automatically update validation when adding a row foreach($fields as $field) { //if the field type has some special specific specification for validation of itself - $js .= $field->jsValidation(); + $js .= $field->jsValidation($this->form->class."_".$this->form->PureName()); } // TODO Implement custom requiredFields - if($this->requiredFields) { + $items = $this->sourceItems(); + if($this->requiredFields&&$items->count()) { foreach ($this->requiredFields as $field) { - if($fields->dataFieldByName($field)) { + /*if($fields->dataFieldByName($field)) { $js .= "\t\t\t\t\trequire('$field');\n"; + }*/ + foreach($items as $item){ + $cellName = $this->Name().'['.$item->ID.']['.$field.']'; + $js .= "\n"; + if($fields->dataFieldByName($cellName)) { + $js .= <<sourceItems()) { - foreach($items as $item) { - // Load the data in to a temporary form (for correct field types) - $fieldset = $this->FieldSetForRow(); - if ($fieldset) - { - $form = new Form(null, null, $fieldset, new FieldSet()); - $row = new TableField_Item($item, $this, $form, $this->fieldTypes); - $fields = array_merge($fields, $row->Fields()->toArray()); - } - } - } - $fields = new FieldSet($fields); - - foreach($fields as $field) { - $valid = ($field->validate($this) && $valid); - } - - if($this->requiredFields) { - foreach($this->requiredFields as $field) { - if($fields->dataFieldByName($field) && !$data[$field]) { - $this->validationError($field,'"' . strip_tags($field) . '" is required',"required"); - } - } - } + if($data['methodName'] != 'delete'){ + $fields = $this->FieldSet(); + $fields = new FieldSet($fields); + + }else{ + return $valid; + } + } + + function validate($validator){ + $valid = true; + $fields = $this->SubmittedFieldSet($sourceItemsNew); + $fields = new FieldSet($fields); + foreach($fields as $field){ + $valid = $field->validate($validator)&&$valid; + } + + //debug::show($this->form->Message()); + if($this->requiredFields&&$sourceItemsNew&&$sourceItemsNew->count()) { + foreach ($this->requiredFields as $field) { + foreach($sourceItemsNew as $item){ + $cellName = $this->Name().'['.$item->ID.']['.$field.']'; + $cName = $this->Name().'[new]['.$field.'][]'; + + if($fieldObj = $fields->dataFieldByName($cellName)) { + if(!trim($fieldObj->value)){ + $title = $fieldObj->Title(); + $errorMessage .= "In $this->name '$title' is required.
"; + } + } + } + } + } + + if($errorMessage){ + $messageType .= "validation"; + $message .= "
".$errorMessage; + + $validator->validationError($this->name, $message, $messageType); + } + + return $valid; } function setRequiredFields($fields) { @@ -634,7 +704,6 @@ class TableField_Item extends TableListField_Item { $field = new $fieldType($combinedFieldName,$fieldTitle); } else { $field = eval("return new " . $fieldType . ";"); - } $field->setExtraClass('col'.$i); $this->fields[] = $field; diff --git a/forms/Validator.php b/forms/Validator.php index 733534909..7a8492c82 100755 --- a/forms/Validator.php +++ b/forms/Validator.php @@ -39,6 +39,24 @@ abstract class Validator extends Object { ); } + function showError(){ + debug::show($this->errors); + } + + function getCombinedError(){ + if($this->errors) { + foreach($this->errors as $error){ + $ret['message'] .= $error['message']."
"; + $ret['messageType'] .= $error['messageType']."
"; + } + + return $ret; + } + } + function getError(){ + return $this->errors; + } + function requireField($fieldName, $data) { if(!$data[$fieldName]) $this->validationError($fieldName, "$fieldName is required", "required"); } diff --git a/javascript/Validator.js b/javascript/Validator.js index c536261d3..def732993 100755 --- a/javascript/Validator.js +++ b/javascript/Validator.js @@ -30,9 +30,17 @@ function findIndexOf(group,index){ } function clearErrorMessage(holderDiv){ - $$('span.message', holderDiv).each(function(el) { - Element.hide(el); - }); + //merged by nlou 23/08/2007, r#40674 + if(holderDiv.tagName == 'TD'){//for tablefield. + $$('span.message', holderDiv).each(function(el){ + Element.hide(el); + } + ); + }else{ + $$('span.message', holderDiv.parentNode).each(function(el) { + Element.hide(el); + }); + } } function clearAllErrorMessages(){ @@ -75,6 +83,13 @@ function require(fieldName,cachedError) { // Sets up radio and checkbox validation if(el.type == 'checkbox' || el.type == 'radio' ){ var set = el.checked; + }//merged by nlou 23/08/2007, r#40674 + else if(el.type == 'select-one'){ + if(el.value == ''||el.value == '0'){ + var set = ''; + }else{ + var set = el.value; + } }else{ var set = el.value; } @@ -168,6 +183,9 @@ function findParentLabel(el){ return findParentLabel(el.parentNode); } } + }//merged by nlou 23/08/2007, r#40674 + else if(el.className.indexOf('tablecolumn') != -1){ + return el.className.substring(0, el.className.indexOf('tablecolumn')-1); }else{ return findParentLabel(el.parentNode); } diff --git a/templates/TableField.ss b/templates/TableField.ss index 1ad1de581..2c5754c15 100755 --- a/templates/TableField.ss +++ b/templates/TableField.ss @@ -1,5 +1,10 @@
<% include TableListField_PageControls %> + <% if Message %> +

$Message

+ <% else %> + + <% end_if %> @@ -36,7 +41,7 @@ <% control Items %> <% control Fields %> - + <% end_control %> <% if Can(delete) %><% end_if %>
$Field$Field$ExtraDatadelete