diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index a0a4562b1..dc117f0ad 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -195,11 +195,6 @@ class LeftAndMain extends Controller implements PermissionProvider { // Audit logging hook if(empty($_REQUEST['executeForm']) && !$this->isAjax()) $this->extend('accessedCMS'); - // Requirements - - // Suppress behaviour/prototype validation instructions in CMS, not compatible with ajax loading of forms. - Validator::set_javascript_validation_handler('none'); - // Set the members html editor config HtmlEditorConfig::set_active(Member::currentUser()->getHtmlEditorConfigForCMS()); @@ -264,7 +259,6 @@ class LeftAndMain extends Controller implements PermissionProvider { SAPPHIRE_DIR . '/javascript/DateField.js', SAPPHIRE_DIR . '/javascript/HtmlEditorField.js', SAPPHIRE_DIR . '/javascript/TabSet.js', - SAPPHIRE_DIR . '/javascript/Validator.js', SAPPHIRE_DIR . '/javascript/i18n.js', SAPPHIRE_ADMIN_DIR . '/javascript/ssui.core.js', SAPPHIRE_DIR . '/javascript/GridField.js', @@ -913,7 +907,6 @@ class LeftAndMain extends Controller implements PermissionProvider { // The clientside (mainly LeftAndMain*.js) rely on ajax responses // which can be evaluated as javascript, hence we need // to override any global changes to the validation handler. - $validator->setJavascriptValidationHandler('prototype'); $form->setValidator($validator); } else { $form->unsetValidator(); diff --git a/admin/code/ModelAdmin.php b/admin/code/ModelAdmin.php index c2f833e12..c30c496d7 100644 --- a/admin/code/ModelAdmin.php +++ b/admin/code/ModelAdmin.php @@ -392,18 +392,20 @@ class ModelAdmin_CollectionController extends Controller { * @return Form */ public function SearchForm() { - $context = singleton($this->modelClass)->getDefaultSearchContext(); + $SNG_model = singleton($this->modelClass); + $context = $SNG_model->getDefaultSearchContext(); $fields = $context->getSearchFields(); $columnSelectionField = $this->ColumnSelectionField(); $fields->push($columnSelectionField); - $validator = new RequiredFields(); - $validator->setJavascriptValidationHandler('none'); - + + $validator = ($SNG_model->hasMethod('getCMSValidator')) ? $SNG_model->getCMSValidator() : new RequiredFields(); + $clearAction = new ResetFormAction('clearsearch', _t('ModelAdmin.CLEAR_SEARCH','Clear Search')); + $form = new Form($this, "SearchForm", $fields, new FieldList( new FormAction('search', _t('MemberTableField.SEARCH', 'Search')), - $clearAction = new ResetFormAction('clearsearch', _t('ModelAdmin.CLEAR_SEARCH','Clear Search')) + $clearAction ), $validator ); @@ -423,26 +425,28 @@ class ModelAdmin_CollectionController extends Controller { */ public function CreateForm() { $modelName = $this->modelClass; + $SNG_model = singleton($modelName); if($this->hasMethod('alternatePermissionCheck')) { if(!$this->alternatePermissionCheck()) return false; } else { - if(!singleton($modelName)->canCreate(Member::currentUser())) return false; + if(!$SNG_model->canCreate(Member::currentUser())) return false; } - - $buttonLabel = sprintf(_t('ModelAdmin.CREATEBUTTON', "Create '%s'", PR_MEDIUM, "Create a new instance from a model class"), singleton($modelName)->i18n_singular_name()); + + $buttonLabel = sprintf(_t('ModelAdmin.CREATEBUTTON', "Create '%s'", PR_MEDIUM, "Create a new instance from a model class"), $SNG_model->i18n_singular_name()); + + $validator = ($SNG_model->hasMethod('getCMSValidator')) ? $SNG_model->getCMSValidator() : new RequiredFields(); + $createButton = FormAction::create('add', $buttonLabel)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'); $form = new Form($this, "CreateForm", - new FieldList(), - new FieldList( - $createButton = FormAction::create('add', $buttonLabel) - ->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept') - ), - $validator = new RequiredFields() - ); + new FieldList(), + new FieldList($createButton), + $validator + ); + $createButton->dontEscape = true; - $validator->setJavascriptValidationHandler('none'); $form->setHTMLID("Form_CreateForm_" . $this->modelClass); + return $form; } @@ -498,15 +502,11 @@ class ModelAdmin_CollectionController extends Controller { new FormAction('import', _t('ModelAdmin.IMPORT', 'Import from CSV')) ); - $validator = new RequiredFields(); - $validator->setJavascriptValidationHandler('none'); - $form = new Form( $this, "ImportForm", $fields, - $actions, - $validator + $actions ); $form->setHTMLID("Form_ImportForm_" . $this->modelClass); return $form; @@ -802,10 +802,8 @@ class ModelAdmin_CollectionController extends Controller { $fields = $newRecord->getCMSFields(); } - $validator = ($newRecord->hasMethod('getCMSValidator')) ? $newRecord->getCMSValidator() : null; - if(!$validator) $validator = new RequiredFields(); - $validator->setJavascriptValidationHandler('none'); - + $validator = ($newRecord->hasMethod('getCMSValidator')) ? $newRecord->getCMSValidator() : new RequiredFields(); + $actions = new FieldList ( FormAction::create("doCreate", _t('ModelAdmin.ADDBUTTON', "Add")) ->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept') @@ -922,7 +920,6 @@ class ModelAdmin_RecordController extends Controller { } $validator = ($this->currentRecord->hasMethod('getCMSValidator')) ? $this->currentRecord->getCMSValidator() : new RequiredFields(); - $validator->setJavascriptValidationHandler('none'); $actions = $this->currentRecord->getCMSActions(); if($this->currentRecord->canEdit(Member::currentUser())){ diff --git a/docs/en/changelogs/3.0.0.md b/docs/en/changelogs/3.0.0.md index ed49257a6..7c5f15155 100644 --- a/docs/en/changelogs/3.0.0.md +++ b/docs/en/changelogs/3.0.0.md @@ -73,6 +73,45 @@ not when simply using the CMS or developing other CMS functionality. If you want to extend the CMS stylesheets for your own projects without SCSS, please create a new CSS file and link it into the CMS via `[api:LeftAndMain::require_css()]`. +### Built-in Javascript validation removed ### + +Built-in client-side form validation using behaviour.js has been removed, and is no longer supported. + +Server-side validation remains. Developers are encouraged to use custom Javascript validation on their +forms if requiring client-side validation. + +These classes/files have been removed: + + Validator.js + CustomRequiredFields.php + +These functions are now deprecated and will throw a notice if used: + + Validator::set_javascript_validation_handler() + Validator::get_javascript_validator_handler() + Validator::setJavascriptValidationHandler() + +These functions have been removed: + + Validator::javascript() (abstract function) + Validator::includeJavascriptValidation() + FormField::jsValidation() + AjaxUniqueTextField::jsValidation() + ConfirmedPasswordField::jsValidation() + CreditCardField::jsValidation() + CurrencyField::jsValidation() + CustomRequiredFields::javascript() + DateField::jsValidation() + DatetimeField::jsValidation() + EmailField::jsValidation() + FieldGroup::jsValidation() + FormField::jsValidation() + NumericField::jsValidation() + PhoneNumberField::jsValidation() + RequiredFields::javascript() + TableField::jsValidation() + TimeField::jsValidation() + ### FormField consistently adds classes to HTML elements ### The [api:FormField] API has been refactored to use SilverStripe templates diff --git a/forms/AjaxUniqueTextField.php b/forms/AjaxUniqueTextField.php index b8b73d627..f8a2ad592 100644 --- a/forms/AjaxUniqueTextField.php +++ b/forms/AjaxUniqueTextField.php @@ -34,8 +34,6 @@ class AjaxUniqueTextField extends TextField { Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); Requirements::javascript(SAPPHIRE_DIR . "/javascript/UniqueFields.js"); - $this->jsValidation(); - $url = Convert::raw2att( $this->validateURL ); if($this->restrictedRegex) @@ -54,63 +52,7 @@ class AjaxUniqueTextField extends TextField { return $this->createTag('input', $attributes); } - function jsValidation() { - $formID = $this->form->FormName(); - $id = $this->id(); - $url = Director::absoluteBaseURL() . $this->validateURL; - - if($this->restrictedRegex) { - $jsCheckFunc = <<restrictedRegex}/); -if(match) { - Element.addClassName(this, 'invalid'); - return false; -} - -return true; -JS; - } else { - $jsCheckFunc = "return true;"; - } - - $jsFunc = <<name}=' + encodeURIComponent(this.value), - method: 'get', - success: function(response) { - if(response.responseText == 'ok') - Element.removeClassName(self, 'inuse'); - else { - Element.addClassName(self, 'inuse'); - } - }, - error: function(response) { - - } - }); - } - }, - - checkValid: function() { - $jsCheckFunc - } - } -}); -JS; - Requirements::customScript($jsFunc, 'func_validateAjaxUniqueTextField'); - - //return "\$('$formID').validateCurrency('$this->name');"; - - } - function validate( $validator ) { - $result = DB::query(sprintf( "SELECT COUNT(*) FROM \"%s\" WHERE \"%s\" = '%s'", $this->restrictedTable, diff --git a/forms/ConfirmedPasswordField.php b/forms/ConfirmedPasswordField.php index 164ad7f50..0e51215f5 100644 --- a/forms/ConfirmedPasswordField.php +++ b/forms/ConfirmedPasswordField.php @@ -203,97 +203,6 @@ class ConfirmedPasswordField extends FormField { return $this; } - - function jsValidation() { - $formID = $this->form->FormName(); - $jsTests = ''; - - $jsTests .= " - // if fields are hidden, reset values and don't validate - var containers = $$('.showOnClickContainer', $('#'+fieldName)); - if(containers.length && !Element.visible(containers[0])) { - passEl.value = null; - confEl.value = null; - return true; - } - "; - - $error1 = _t('ConfirmedPasswordField.HAVETOMATCH', 'Passwords have to match.'); - $jsTests .= " - if(passEl.value != confEl.value) { - validationError(confEl, \"$error1\", \"error\"); - return false; - } - "; - - $error2 = _t('ConfirmedPasswordField.NOEMPTY', 'Passwords can\'t be empty.'); - if(!$this->canBeEmpty) { - $jsTests .= " - if(!passEl.value || !confEl.value) { - validationError(confEl, \"$error2\", \"error\"); - return false; - } - "; - } - - if(($this->minLength || $this->maxLength)) { - if($this->minLength && $this->maxLength) { - $limit = "{{$this->minLength},{$this->maxLength}}"; - $errorMsg = sprintf(_t('ConfirmedPasswordField.BETWEEN', 'Passwords must be %s to %s characters long.'), $this->minLength, $this->maxLength); - } elseif($this->minLength) { - $limit = "{{$this->minLength}}.*"; - $errorMsg = sprintf(_t('ConfirmedPasswordField.ATLEAST', 'Passwords must be at least %s characters long.'), $this->minLength); - } elseif($this->maxLength) { - $limit = "{0,{$this->maxLength}}"; - $errorMsg = sprintf(_t('ConfirmedPasswordField.MAXIMUM', 'Passwords must be at most %s characters long.'), $this->maxLength); - } - $limitRegex = '/^.' . $limit . '$/'; - $jsTests .= " - if(passEl.value && !passEl.value.match({$limitRegex})) { - validationError(confEl, \"{$errorMsg}\", \"error\"); - return false; - } - "; - } - - $error3 = _t('ConfirmedPasswordField.LEASTONE', 'Passwords must have at least one digit and one alphanumeric character.'); - if($this->requireStrongPassword) { - $jsTests .= " - if(!passEl.value.match(/^(([a-zA-Z]+\d+)|(\d+[a-zA-Z]+))[a-zA-Z0-9]*$/)) { - validationError( - confEl, - \"$error3\", - \"error\" - ); - return false; - } - "; - } - - $jsFunc =<<name');"; - return <<name') - $('$formID').validateConfirmedPassword('$this->name'); -}else{ - $('$formID').validateConfirmedPassword('$this->name'); -} -JS; - } /** * Determines if the field was actually diff --git a/forms/CreditCardField.php b/forms/CreditCardField.php index 809b6318a..2af91fef6 100644 --- a/forms/CreditCardField.php +++ b/forms/CreditCardField.php @@ -35,62 +35,6 @@ class CreditCardField extends TextField { else return $this->value; } - function jsValidation() { - $formID = $this->form->FormName(); - $error1 = _t('CreditCardField.VALIDATIONJS1', 'Please ensure you have entered the'); - $error2 = _t('CreditCardField.VALIDATIONJS2', 'credit card number correctly.'); - $first = _t('CreditCardField.FIRST', 'first'); - $second = _t('CreditCardField.SECOND', 'second'); - $third = _t('CreditCardField.THIRD', 'third'); - $fourth = _t('CreditCardField.FOURTH', 'fourth'); - $jsFunc =<<name');"; - } - function validate($validator){ // If the field is empty then don't return an invalidation message if(!trim(implode("", $this->value))) return true; diff --git a/forms/CurrencyField.php b/forms/CurrencyField.php index ee0b45da8..7298c8798 100644 --- a/forms/CurrencyField.php +++ b/forms/CurrencyField.php @@ -47,37 +47,6 @@ class CurrencyField extends TextField { return new CurrencyField_Readonly($this); */ } - - /** - * @see http://regexlib.com/REDetails.aspx?regexp_id=126 - */ - function jsValidation() { - $formID = $this->form->FormName(); - $error = _t('CurrencyField.VALIDATIONJS', 'Please enter a valid currency.'); - $jsFunc =<< 0 && !value.match(/^\s*(-?\\\$?|\\\$-?)?(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?\s*\$/)) { - validationError(el,"$error","validation",false); - return false; - } - return true; - } - } -}); -JS; - - Requirements::customScript($jsFunc, 'func_validateCurrency_' .$formID); - - return <<name'); -JS; - } function validate($validator) { if(!empty ($this->value) && !preg_match('/^\s*(\-?\$?|\$\-?)?(\d{1,3}(\,\d{3})*|(\d+))(\.\d{2})?\s*$/', $this->value)) { diff --git a/forms/CustomRequiredFields.php b/forms/CustomRequiredFields.php deleted file mode 100644 index 77e3af5ce..000000000 --- a/forms/CustomRequiredFields.php +++ /dev/null @@ -1,148 +0,0 @@ -requireField('FieldName') is the php equivalent) - * - * An example for creating required fields only if payment type is CreditCard: - * - * - * new CustomRequiredFields( - * array( - * "PaymentMethod", - * array( - * "js" => " - * for( var i = 0; i <= this.elements.PaymentMethod.length -1; i++){ - * if(this.elements.PaymentMethod[i].value == 'CC' && this.elements.PaymentMethod[i].checked == true){ - * require('CardHolderName'); - * require('CreditCardNumber'); - * require('DateExpiry'); - * } - * } - * - * ", - * "php" => 'if($data[PaymentMethod] == "CC") { - * $this->requireField($field,"$field is required","required"); - * $this->requireField("CardHolderName", $data); - * $this->requireField("CreditCardNumber", $data); - * $this->requireField("DateExpiry", $data); - * }', - * ) - * ) - * ); - * - * - * And example for confirming mobile number and email address: - * - * - * $js = << $js, 'php' => 'return true;'), array('js' => $js2, 'php'=>'return true;'))); - * - * - * @package forms - * @subpackage validators - */ -class CustomRequiredFields extends RequiredFields{ - protected $required; - - /** - * Pass each field to be validated as a seperate argument - * @param $required array The list of required fields - */ - function __construct($required) { - $this->required = $required; - } - - /** - * Creates the client side validation from form fields - * which is generated at the header of each page - */ - function javascript() { - $code = ''; - $fields = $this->form->Fields(); - foreach($fields as $field){ - //if the field type has some special specific specification for validation of itself - $valid = $field->jsValidation(); - if($valid){ - $code .= $valid; - } - } - if(is_array($this->required)){ - - foreach($this->required as $field) { - if(is_array($field) && isset($field['js'])){ - $code .= $field['js'] . "\n"; - }else if($fields->dataFieldByName($field)) { - $code .= " require('$field');\n"; - //Tabs for output tabbing :-) - } - } - }else{ - USER_ERROR("CustomRequiredFields::requiredfields is not set / not an array",E_USER_WARNING); - } - return $code; - } - - /** - * Creates the server side validation from form fields - * which is executed on form submission - */ - function php($data) { - $fields = $this->form->Fields(); - $valid = true; - foreach($fields as $field) { - $valid = ($field->validate($this) && $valid); - } - if($this->required){ - foreach($this->required as $key => $fieldName) { - if(is_string($fieldName)) $formField = $fields->dataFieldByName($fieldName); - if(is_array($fieldName) && isset($fieldName['php'])){ - eval($fieldName['php']); - }else if($formField) { - // if an error is found, the form is returned. - if(!strlen($data[$fieldName]) || preg_match('/^\s*$/', $data[$fieldName])) { - $this->validationError( - $fieldName, - sprintf(_t('Form.FIELDISREQUIRED', "%s is required."), - $formField->Title()), - "required" - ); - return false; - } - } - } - } - return $valid; - } - - /** - * allows you too add more required fields to this object after construction. - */ - function appendRequiredFields($requiredFields){ - $this->required = array_merge($this->required,$requiredFields->getRequired()); - } -} - diff --git a/forms/DateField.php b/forms/DateField.php index 1582f70f4..cc4c49615 100644 --- a/forms/DateField.php +++ b/forms/DateField.php @@ -251,104 +251,6 @@ class DateField extends TextField { return $field; } - - function jsValidation() { - // JavaScript validation of locales other than en_NZ are not supported at the moment... - if($this->getLocale() != 'en_NZ') return; - - $formID = $this->form->FormName(); - - if(Validator::get_javascript_validator_handler() == 'none') return true; - - if($this->getConfig('dmyfields')) { - $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format.'); - // Remove hardcoded date formats from translated strings - $error = preg_replace('/\(.*\)/', '', $error); - $error .= ' (' . $this->getConfig('dateformat') .')'; - - $jsFunc =<< 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/([0-9][0-9]){1,2}\$/)) { - validationError(_CURRENT_FORM.elements[fieldName+'[day]'],"$error","validation",false); - - return false; - } - - return true; - } - } -}); -JS; - Requirements :: customScript($jsFunc, 'func_validateDMYDate_'.$formID); - - return <<name') - \$('$formID').validateDMYDate('$this->name'); - }else{ - \$('$formID').validateDMYDate('$this->name'); - } - } -JS; - } else { - $error = _t('DateField.VALIDATIONJS', 'Please enter a valid date format (DD/MM/YYYY).'); - $jsFunc =<< 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/([0-9][0-9]){1,2}\$/)) { - validationError(_CURRENT_FORM.elements[fieldName+'[day]'],"$error","validation",false); - return false; - } - } else { - // single field validation - if(value && value.length > 0 && !value.match(/^[0-9]{1,2}\/[0-9]{1,2}\/[0-90-9]{2,4}\$/)) { - validationError(el,"$error","validation",false); - return false; - } - } - - return true; - } - } -}); -JS; - Requirements :: customScript($jsFunc, 'func_validateDate_'.$formID); - - return <<name') - \$('$formID').validateDate('$this->name'); - }else{ - \$('$formID').validateDate('$this->name'); - } -} -JS; - } - } /** * Validate an array with expected keys 'day', 'month' and 'year. @@ -538,10 +440,6 @@ class DateField_Disabled extends DateField { return "date_disabled readonly"; } - function jsValidation() { - return null; - } - function validate($validator) { return true; } diff --git a/forms/DatetimeField.php b/forms/DatetimeField.php index ee477fccf..6fd774ba4 100644 --- a/forms/DatetimeField.php +++ b/forms/DatetimeField.php @@ -269,10 +269,6 @@ class DatetimeField extends FormField { return ($dateValid && $timeValid); } - function jsValidation() { - return $this->dateField->jsValidation() . $this->timeField->jsValidation(); - } - function performReadonlyTransformation() { $field = new DatetimeField_Readonly($this->name, $this->title, $this->dataValue()); $field->setForm($this->form); @@ -314,10 +310,6 @@ class DatetimeField_Readonly extends DatetimeField { return "id() . "\">$val"; } - function jsValidation() { - return null; - } - function validate($validator) { return true; } diff --git a/forms/EmailField.php b/forms/EmailField.php index 3a9a65a2e..94a6bb13e 100644 --- a/forms/EmailField.php +++ b/forms/EmailField.php @@ -10,40 +10,6 @@ class EmailField extends TextField { return 'email text'; } - function jsValidation() { - $formID = $this->form->FormName(); - $error = _t('EmailField.VALIDATIONJS', 'Please enter an email address.'); - $jsFunc =<<name');"; - return <<name') - $('$formID').validateEmailField('$this->name'); -}else{ - $('$formID').validateEmailField('$this->name'); -} -JS; - } - /** * Validates for RFC 2822 compliant email adresses. * diff --git a/forms/FieldGroup.php b/forms/FieldGroup.php index 14dfc6478..f16f1ed32 100644 --- a/forms/FieldGroup.php +++ b/forms/FieldGroup.php @@ -169,21 +169,6 @@ HTML; } } - /** - * This allows fields within this fieldgroup to still allow them to get valuated. - */ - function jsValidation(){ - $fs = $this->FieldList(); - $validationCode = ''; - - foreach($fs as $subfield) { - if($value = $subfield->jsValidation()) { - $validationCode .= $value; - } - } - return $validationCode; - } - function php($data){ return; } diff --git a/forms/Form.php b/forms/Form.php index 5e7c21183..df1ee2d7f 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -127,14 +127,6 @@ class Form extends RequestHandler { */ protected $securityToken = null; - /** - * HACK This is a temporary hack to allow multiple calls to includeJavascriptValidation on - * the validator (if one is present). - * - * @var boolean - */ - public $jsValidationIncluded = false; - /** * @var array $extraClasses List of additional CSS classes for the form tag. */ @@ -324,23 +316,19 @@ class Form extends RequestHandler { if(!$this->validate()) { if(Director::is_ajax()) { // Special case for legacy Validator.js implementation (assumes eval'ed javascript collected through FormResponse) - if($this->validator->getJavascriptValidationHandler() == 'prototype') { - return FormResponse::respond(); + $acceptType = $request->getHeader('Accept'); + if(strpos($acceptType, 'application/json') !== FALSE) { + // Send validation errors back as JSON with a flag at the start + $response = new SS_HTTPResponse(Convert::array2json($this->validator->getErrors())); + $response->addHeader('Content-Type', 'application/json'); } else { - $acceptType = $request->getHeader('Accept'); - if(strpos($acceptType, 'application/json') !== FALSE) { - // Send validation errors back as JSON with a flag at the start - $response = new SS_HTTPResponse(Convert::array2json($this->validator->getErrors())); - $response->addHeader('Content-Type', 'application/json'); - } else { - $this->setupFormErrors(); - // Send the newly rendered form tag as HTML - $response = new SS_HTTPResponse($this->forTemplate()); - $response->addHeader('Content-Type', 'text/html'); - } - - return $response; + $this->setupFormErrors(); + // Send the newly rendered form tag as HTML + $response = new SS_HTTPResponse($this->forTemplate()); + $response->addHeader('Content-Type', 'text/html'); } + + return $response; } else { if($this->getRedirectToFormOnValidationError()) { if($pageURL = $request->getHeader('Referer')) { @@ -697,9 +685,6 @@ class Form extends RequestHandler { // Forms shouldn't be cached, cos their error messages won't be shown HTTP::set_cache_age(0); - // workaround to include javascript validation - if($this->validator && !$this->jsValidationIncluded) $this->validator->includeJavascriptValidation(); - $attrs = $this->getAttributes(); // Remove empty @@ -1259,10 +1244,6 @@ class Form extends RequestHandler { * the attributes of the form. These fields can be used to send the form to Ajax. */ function formHtmlContent() { - // Call FormAttributes to force inclusion of custom client-side validation of fields - // because it won't be included by the template - if($this->validator && !$this->jsValidationIncluded) $this->validator->includeJavascriptValidation(); - $this->IncludeFormTag = false; $content = $this->forTemplate(); $this->IncludeFormTag = true; diff --git a/forms/FormField.php b/forms/FormField.php index 44e79aabb..c8cb87d74 100644 --- a/forms/FormField.php +++ b/forms/FormField.php @@ -663,15 +663,6 @@ class FormField extends RequestHandler { else return "<$tag$preparedAttributes />"; } - /** - * javascript handler Functions for each field type by default - * formfield doesnt have a validation function - * - * @todo shouldn't this be an abstract method? - */ - function jsValidation() { - } - /** * Validation Functions for each field type by default * formfield doesnt have a validation function diff --git a/forms/NumericField.php b/forms/NumericField.php index eeef22501..0683dd454 100644 --- a/forms/NumericField.php +++ b/forms/NumericField.php @@ -18,40 +18,6 @@ class NumericField extends TextField{ return 'numeric text'; } - function jsValidation() { - $formID = $this->form->FormName(); - $error = _t('NumericField.VALIDATIONJS', 'is not a number, only numbers can be accepted for this field'); - $jsFunc =<<name');"; - return <<name') - $('$formID').validateNumericField('$this->name'); -}else{ - $('$formID').validateNumericField('$this->name'); -} -JS; - } - /** PHP Validation **/ function validate($validator){ if($this->value && !is_numeric(trim($this->value))){ diff --git a/forms/PhoneNumberField.php b/forms/PhoneNumberField.php index 135d23644..c15fb73f0 100644 --- a/forms/PhoneNumberField.php +++ b/forms/PhoneNumberField.php @@ -124,51 +124,6 @@ class PhoneNumberField extends FormField { $record->$fieldName = $completeNumber; } - /** - * @todo Very basic validation at the moment - */ - function jsValidation() { - $formID = $this->form->FormName(); - - $jsFunc =<<name');"; - } - /** * @todo Very basic validation at the moment */ diff --git a/forms/RequiredFields.php b/forms/RequiredFields.php index 990563469..307efc267 100644 --- a/forms/RequiredFields.php +++ b/forms/RequiredFields.php @@ -53,39 +53,6 @@ class RequiredFields extends Validator { return $result; } - function javascript() { - $js = ""; - $fields = $this->form->Fields(); - $dataFields = $this->form->Fields()->dataFields(); - if($dataFields) { - foreach($dataFields as $field) { - // if the field type has some special specific specification for validation of itself - $validationFunc = $field->jsValidation(); - if($validationFunc) $js .= $validationFunc . "\n"; - } - } - $useLabels = $this->useLabels ? 'true' : 'false'; - - if($this->required) { - foreach($this->required as $field) { - if($fields->dataFieldByName($field)) { - //$js .= "\t\t\t\t\trequire('$field', false, $useLabels);\n"; - $js .= <<Items(); - if($items) foreach($items as $item) { - foreach($item->Fields() as $field) { - //if the field type has some special specific specification for validation of itself - $js .= $field->jsValidation($this->form->class."_".$this->form->Name()); - } - } - - // TODO Implement custom requiredFields - $items = $this->sourceItems(); - if($items && $this->requiredFields && $items->count()) { - foreach ($this->requiredFields as $field) { - foreach($items as $item){ - $cellName = $this->getName().'['.$item->ID.']['.$field.']'; - $js .= "\n"; - if($fields->dataFieldByName($cellName)) { - $js .= <<id() . "\">$val"; } - function jsValidation() { - return null; - } - function validate($validator) { return true; } diff --git a/forms/Validator.php b/forms/Validator.php index 850ebf9d6..9c5a2e26a 100644 --- a/forms/Validator.php +++ b/forms/Validator.php @@ -24,62 +24,26 @@ abstract class Validator extends Object { * @var array $errors */ protected $errors; - + /** - * Static for default value of $this->javascriptValidationHandler. - * Set with Validator::set_javascript_validation_handler(); - * @var string - */ - protected static $javascript_validation_handler = "prototype"; - - /** - * Handler for javascript validation. Can be "prototype" or "none". - * @var string - */ - protected $javascriptValidationHandler = null; - - /** - * Call this function to set the javascript validation handler for all valdiation on your site. - * This could be called from _config.php to set site-wide javascript validation, or from Controller::init() - * to affect only the front-end site. - * Use instance method {@link setJavascriptValidationHandler()} to - * only set handler for a specific form instance. - * - * @param $handler A string representing the handler to use: 'prototype' or 'none'. - * @todo Add 'jquery' as a handler option. + * @deprecated 3.0 Use custom javascript validation instead */ public static function set_javascript_validation_handler($handler) { - if($handler == 'prototype' || $handler == 'none') { - self::$javascript_validation_handler = $handler; - } else { - user_error("Validator::setJavascriptValidationHandler() passed bad handler '$handler'", E_USER_WARNING); - } - } - - /** - * Returns global validation handler used for all forms by default, - * unless overwritten by {@link setJavascriptValidationHandler()}. - * - * @return string - */ - public static function get_javascript_validator_handler() { - return self::$javascript_validation_handler; + Deprecation::notice('3.0', 'Use custom javascript validation instead.'); } /** - * Set JavaScript validation for this validator. - * Use static method {@link set_javascript_validation_handler()} - * to set handlers globally. - * - * @param string $handler + * @deprecated 3.0 Use custom javascript validation instead + */ + public static function get_javascript_validator_handler() { + Deprecation::notice('3.0', 'Use custom javascript validation instead.'); + } + + /** + * @deprecated 3.0 Use custom javascript validation instead */ public function setJavascriptValidationHandler($handler) { - if($handler == 'prototype' || $handler == 'none') { - $this->javascriptValidationHandler = $handler; - } else { - user_error("Validator::setJavascriptValidationHandler() passed bad handler '$handler'", E_USER_WARNING); - } - return $this; + Deprecation::notice('3.0', 'Use custom javascript validation instead.'); } /** @@ -89,9 +53,9 @@ abstract class Validator extends Object { * @return string */ public function getJavascriptValidationHandler() { - return ($this->javascriptValidationHandler) ? $this->javascriptValidationHandler : self::$javascript_validation_handler; + Deprecation::notice('3.0', 'Use custom javascript validation instead.'); } - + /** * @param Form $form */ @@ -106,7 +70,6 @@ abstract class Validator extends Object { function validate(){ $this->errors = null; $this->php($this->form->getData()); - return $this->errors; } @@ -149,78 +112,6 @@ abstract class Validator extends Object { }else if(!strlen($data[$fieldName])) $this->validationError($fieldName, "$fieldName is required.", "required"); } - function includeJavascriptValidation() { - if($this->getJavascriptValidationHandler() == 'prototype') { - Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/prototype/prototype.js"); - Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/behaviour/behaviour.js"); - Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang'); - Requirements::javascript(SAPPHIRE_DIR . "/javascript/Validator.js"); - - $code = $this->javascript(); - $formID = $this->form->FormName(); - $js = <<form) $this->form->jsValidationIncluded = true; - } - } - /** * Returns true if the named field is "required". * Used by FormField to return a value for FormField::Required(), to do things like show *s on the form template. @@ -230,8 +121,6 @@ JS; return false; } - abstract function javascript(); - abstract function php($data); } diff --git a/javascript/Validator.js b/javascript/Validator.js deleted file mode 100644 index 971f9f710..000000000 --- a/javascript/Validator.js +++ /dev/null @@ -1,316 +0,0 @@ -// Shortcut-function (until we update to Prototye v1.5) -if(typeof $$ != "Function") $$ = document.getElementsBySelector; - -var _CURRENT_FORM; -var _FIRST_ERRORED_FIELD = null; -var _VALIDATIONS_REF = new Array(); - -function initialiseForm(form, fromAnOnBlur) { - _CURRENT_FORM = form; - _FIRST_ERRORED_FIELD = null; - - if(fromAnOnBlur) { - limitValidationErrorsTo(fromAnOnBlur); - } else { - clearValidationErrorLimit(); - } - - _HAS_HAD_FORM_ERROR = false; - clearValidationErrorCache(); -} - -function hasHadFormError() { - return _HAS_HAD_FORM_ERROR || !_ERROR_CACHE; -} - -function focusOnFirstErroredField() { - try { - _FIRST_ERRORED_FIELD.focus(); - } catch(er) { - } -} - -/** - * Returns group with the correct classname - */ -function findIndexOf(group,index) { - var i; - for(i = 0; i < group.length; i++) { - if(group[i].className.indexOf(index) > -1) { - return group[i]; - } - } - return null; -} - -function clearErrorMessage(holderDiv){ - //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); - }); - } - $$('div.validationError', holderDiv.parentNode).each(function(el) { - Element.removeClassName(el,'validationError'); - }); -} - -function clearAllErrorMessages() { - $$('span.message').each(function(el) { - Element.hide(el); - }); - $$('div.validationError').each(function(el) { - Element.removeClassName(el,'validationError'); - }); -} - -function require(fieldName,cachedError) { - el = _CURRENT_FORM.elements[fieldName]; - - // see if the field is an optionset - if(el == null) { - - var descendants = _CURRENT_FORM.getElementsByTagName('*'); - - el = document.getElementById(fieldName); - - if(el == null) - return true; - - if(Element.hasClassName(el, 'optionset')) { - el.type = 'optionset'; - - var options = el.getElementsByTagName('input'); - - for(var i = 0; i < options.length; i++) { - if(options[i].checked) - if(el.value != null) - el.value += ',' + options[i].value; - else - el.value = options[i].value; - } - } - - } - - - if(el != null) { - // 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; - } - - var baseEl; - var fieldHolder = el; - - // Sometimes require events are triggered of - // associative elements like labels ;-p - if(el.type) { - if(el.parentNode.className.indexOf('form') != -1) set = true; - baseEl = el; - - } else { - if(_CURRENT_FORM.elements[fieldName]) { - //Some elements are nested and need to be "got" - var i, hasValue = false; - if(_CURRENT_FORM.elements[fieldName].length > 1) { - for(i=0; i < el.length; i++) { - if(el[i].checked && el[i].value) { - hasValue = true; - break; - } - } - - if(hasValue) set = true; - else set = ""; - baseEl = el[0].parentNode.parentNode; - - } else { - set = ""; - baseEl = el.parentNode; - } - - } else { - set = true; - } - } - - // This checks to see if the input has a value, and the field is not a readonly. - if( ( typeof set == 'undefined' || (typeof(set) == 'string' && set.match(/^\s*$/)) ) ) { - //fieldgroup validation - var fieldLabel = findParentLabel(baseEl); - - // Some fields do-not have labels, in - // which case we need a blank one - if(fieldLabel == null || fieldLabel == "") { - fieldlabel = "this field"; - } - - var errorMessage = ss.i18n.sprintf(ss.i18n._t('VALIDATOR.FIELDREQUIRED', 'Please fill out "%s", it is required.'), fieldLabel); - if(baseEl.requiredErrorMsg) errorMessage = baseEl.requiredErrorMsg; - else if(_CURRENT_FORM.requiredErrorMsg) errorMessage = _CURRENT_FORM.requiredErrorMsg; - - validationError(baseEl, errorMessage.replace('$FieldLabel', fieldLabel),"required",cachedError); - return false; - - } else { - if(!hasHadFormError()) { - if(baseEl) fieldHolder = baseEl.parentNode; - clearErrorMessage(fieldHolder); - } - return true; - } - } - - return true; -} - -/** - * Returns the label of the blockset which contains the classname left - */ -function findParentLabel(el) { - // If the el's type is HTML then were at the uppermost parent, so return - // null. its handled by the validator function anyway :-) - if(el) { - if(el.className == "undefined") { - return null; - } else { - if(el.className) { - if(el.className.indexOf('field') == 0) { - labels = el.getElementsByTagName('label'); - if(labels){ - var left = findIndexOf(labels,'left'); - var right = findIndexOf(labels,'right'); - if(left) { - return strip_tags(left.innerHTML); - } else if(right) { - return strip_tags(right.innerHTML); - } else { - 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); - } - } else { - // Try to find a label with a for value of this field. - if(el.id) { - var labels = $$('label[for=' + el.id + ']'); - if(labels && labels.length > 0) return labels[0].innerHTML; - } - - return findParentLabel(el.parentNode); - } - } - } - // backup - return "this"; -} - -/** - * Adds a validation error to an element - */ -function validationError(field,message, messageClass, cacheError) { - if(typeof(field) == 'string') { - field = document.getElementById(field); - } - - if(cacheError) { - _ERROR_CACHE[_ERROR_CACHE.length] = { - "field": field, - "message": message, - "messageClass": messageClass - } - return; - } - - // The validation function should only be called if you've just left a field, - // or the field is being validated on final submission - if(_LIMIT_VALIDATION_ERRORS && _LIMIT_VALIDATION_ERRORS != field) { - // clearErrorMessage(field.parentNode); - return; - } - - _HAS_HAD_FORM_ERROR = true; - - // See if the tag has a reference to the validationMessage (quicker than the one below) - var validationMessage = (typeof(_VALIDATIONS_REF[field.id]) != 'undefined')? _VALIDATIONS_REF[field.id] : null; - - // Cycle through the elements to see if it has a span - // (for a validation or required messages) - if(!validationMessage) { - - //Get the parent holder of the element - var FieldHolder = field.parentNode; - var allSpans = FieldHolder.getElementsByTagName('span'); - validationMessage = findIndexOf(allSpans,'message'); - } - - // If we didn't find it, create it - if(!validationMessage) { - validationMessage = document.createElement('span'); - FieldHolder.appendChild(validationMessage); - } - - // Keep a reference to it - _VALIDATIONS_REF[field.id] = validationMessage; - - // Keep a reference to the first errored field - if(field && !_FIRST_ERRORED_FIELD) _FIRST_ERRORED_FIELD = field; - - // Set the attributes - validationMessage.className = "message " + messageClass; - validationMessage.innerHTML = message; - validationMessage.style.display = "block"; - - // Set Classname on holder - var holder = document.getParentOfElement(field,'div','field'); - Element.addClassName(holder, 'validationError'); -} - -/** - * Set a limitation so that only validation errors for the given element will actually be shown - */ - -var _LIMIT_VALIDATION_ERRORS = null; -function limitValidationErrorsTo(field) { - _LIMIT_VALIDATION_ERRORS = field; -} - -function clearValidationErrorLimit() { - _LIMIT_VALIDATION_ERRORS = null; -} - -function clearValidationErrorCache() { - _ERROR_CACHE = new Array(); -} - -function showCachedValidationErrors() { - for(i = 0; i < _ERROR_CACHE.length; i++) { - validationError(_ERROR_CACHE[i]["field"], - _ERROR_CACHE[i]["message"], - _ERROR_CACHE[i]["messageClass"], - false); - } -} - -function strip_tags(text) { - return text.replace(/<[^>]+>/g,''); -} \ No newline at end of file diff --git a/security/Member.php b/security/Member.php index d945bf8d0..0d199bede 100644 --- a/security/Member.php +++ b/security/Member.php @@ -1772,27 +1772,4 @@ class Member_Validator extends RequiredFields { return $valid; } - - /** - * Check if the submitted member data is valid (client-side) - * - * @param array $data Submitted data - * @return bool Returns TRUE if the submitted data is valid, otherwise - * FALSE. - */ - function javascript() { - $js = parent::javascript(); - - // Execute the validators on the extensions - if($this->extension_instances) { - foreach($this->extension_instances as $extension) { - if(method_exists($extension, 'hasMethod') && $extension->hasMethod('updateJavascript')) { - $extension->updateJavascript($js, $this->form); - } - } - } - - return $js; - } - -} \ No newline at end of file +} diff --git a/security/MemberLoginForm.php b/security/MemberLoginForm.php index b0850e52b..9675b7c4a 100644 --- a/security/MemberLoginForm.php +++ b/security/MemberLoginForm.php @@ -90,16 +90,13 @@ class MemberLoginForm extends LoginForm { parent::__construct($controller, $name, $fields, $actions); // Focus on the email input when the page is loaded - // Only include this if other form JS validation is enabled - if($this->getValidator()->getJavascriptValidationHandler() != 'none') { - Requirements::customScript(<<