clientside_validation.module 20.8 KB
Newer Older
Peter Droogmans's avatar
Peter Droogmans committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
// $Id: 
/**
 * @file
 * Add client side validation to a webform.
 */

/**
 * Implementation of hook_form_alter().
 */
function clientside_validation_form_alter(&$form, &$form_state, $form_id) {
  if (strpos($form_id, 'webform_client_form') !== FALSE) {
    $form['#after_build'][] = 'clientside_validation_webform_after_build';
  } 
  else {
    switch ($form['#id']) {
      case 'node-form':
      case 'webform-component-edit-form':
        $form['#after_build'][] = 'clientside_validation_form_after_build';
        break;
      default:
        $form['#after_build'][] = 'clientside_validation_form_after_build';
        break;
    }
  }
}

/**
29
 * Webform.
Peter Droogmans's avatar
Peter Droogmans committed
30
31
32
 */
function clientside_validation_webform_after_build(&$form, &$form_state) {
  $js_rules = array();
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
  clientside_validation_webform_after_build_recurse($form['#id'], $form, $form_state, $js_rules);
    if ($webform_validation_rules = clientside_validation_webform_validation($form_state['values']['details']['nid'])) {
    dpm($webform_validation_rules);
    foreach ($webform_validation_rules as $webform_validation_rule) {
      switch ($webform_validation_rule['validator']) {
        case 'min_length':
          foreach ($webform_validation_rule['components'] as $component) {
          $message = t('!name field has a minimum length of !minl characters.', array('!name' => $component['name'], '!minl' => $webform_validation_rule['data']));
           _clientside_validation_set_minmaxlength('submitted[' . $component['form_key'] . ']', $component['name'], $webform_validation_rule['data'], '', $js_rules, $message);
          }
          break;
        case 'max_length':
          foreach ($webform_validation_rule['components'] as $component) {
            $message = t('!name field has a maximum length of !maxl characters.', array('!name' => $component['name'], '!maxl' => $webform_validation_rule['data']));
            _clientside_validation_set_minmaxlength('submitted[' . $component['form_key'] . ']', $component['name'], '',$webform_validation_rule['data'], $js_rules, $message);
Peter Droogmans's avatar
Peter Droogmans committed
48

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
          }
          break;
        case 'numeric':
          foreach ($webform_validation_rule['components'] as $component) {
            $range = explode('-', $webform_validation_rule['data']);
            if (!empty($range[0]) && $range[0] != '0') {
              if (!isset($range[1])) {
                $range[1] = $range[0];
                $range[0] = 0;
              }
              _clientside_validation_set_minmax('submitted[' . $component['form_key'] . ']', $component['name'], $range[0], $range[1], $js_rules);
            }
          }
          break;
        case 'equal':
          $others = $webform_validation_rule['components'];
          $firstone = array_shift($others);
          foreach ($others as $component) {
            _clientside_validation_set_equal('submitted[' . $component['form_key'] . ']', $component['name'], $firstone, $js_rules);
          }
          break;
        case 'unique':
          $all = $webform_validation_rule['components'];
          while (count($all) > 1) {
            $firstone = array_shift($all);
            foreach ($all as $component) {
              $message = (isset($webform_validation_rule['error_message']) && !empty($webform_validation_rule['error_message'])) ? $webform_validation_rule['error_message'] : '';
              _clientside_validation_set_not_equal('submitted[' . $component['form_key'] . ']', $component['name'], $firstone, $js_rules, $message);
            }
          }
          break;
        case 'specific_value':
          foreach ($webform_validation_rule['components'] as $component) {
            $value = explode(',', $webform_validation_rule['data']);
            $message = (isset($webform_validation_rule['error_message']) && !empty($webform_validation_rule['error_message'])) ? $webform_validation_rule['error_message'] : '';
            _clientside_validation_set_specific_value('submitted[' . $component['form_key'] . ']', $component['name'], $value, $js_rules, $message);
          }
          break;
        case 'select_min':
          foreach ($webform_validation_rule['components'] as $component) {
            _clientside_validation_set_minmaxlength ('submitted[' . $component['form_key'] . ']', $component['name'], $webform_validation_rule['data'], '', $js_rules);
          }
          break;
        case 'select_max':
          foreach ($webform_validation_rule['components'] as $component) {
            _clientside_validation_set_minmaxlength ('submitted[' . $component['form_key'] . ']', $component['name'], '', $webform_validation_rule['data'], $js_rules);
          }
          break;
        case 'select_exact':
          foreach ($webform_validation_rule['components'] as $component) {
            _clientside_validation_set_minmaxlength ('submitted[' . $component['form_key'] . ']', $component['name'], $webform_validation_rule['data'], $webform_validation_rule['data'], $js_rules);
          }
          break;
        case 'validEAN':
          foreach ($webform_validation_rule['components'] as $component) {
            $message = (isset($webform_validation_rule['error_message']) && !empty($webform_validation_rule['error_message'])) ? $webform_validation_rule['error_message'] : '';
            _clientside_validation_set_ean('submitted[' . $component['form_key'] . ']', $component['name'], $js_rules, $message);
          }
          break;
      }
    }
  }
Peter Droogmans's avatar
Peter Droogmans committed
111
112
113
114
115
116
117
118
119
120
121
122
  if (!empty($js_rules)) {
    $settings['clientsideValidation']['general'] = array (
      "errorClass" => "error",
      "wrapper" => "li",
    );
    $settings['clientsideValidation']['forms'][$form['#id']]['settings'] = array(
      "errorContainer" => "#formerrors-" . $form['#id'],
      "errorLabelContainer" => "#formerrors-" . $form['#id'] . " ul",
    );
    foreach($js_rules as $key => $rule) {
      $settings['clientsideValidation']['forms'][$form['#id']]['rules'][$key] = $rule;
    }
Peter Droogmans's avatar
Peter Droogmans committed
123
124
    drupal_add_js(drupal_get_path('module', 'clientside_validation') . '/jquery-validate/jquery.validate.js');
    drupal_add_js(drupal_get_path('module', 'clientside_validation') . '/clientside_validation.js');
Peter Droogmans's avatar
Peter Droogmans committed
125
126
127
128
129
130
131
132
133
134
135
136
    drupal_add_js($settings, 'setting');
  }
  return $form;
}

function clientside_validation_webform_after_build_recurse($form_id, &$form, &$form_state, &$js_rules) {
  if ($children = array_values(element_children($form))) {
    foreach ($children as $index => $item) {
      $element = &$form[$item];
      if (isset($element['#title'])) {
        if ($element['#required']) {
          if (isset($element['#webform_component']) && $element['#webform_component']['type'] == 'time' && isset($element['hour']['#name'])) {
137
138
139
140
            $message = t('Hour in !name field is required.', array('!name' => $element['#title']));
            _clientside_validation_set_required($element['hour']['#name'], $element['#title'], TRUE, $js_rules, $message);
            $message = t('Minute in !name field is required.', array('!name' => $element['#title']));
            _clientside_validation_set_required($element['minute']['#name'], $element['#title'], TRUE, $js_rules, $message);
Peter Droogmans's avatar
Peter Droogmans committed
141
142
          }
          else if (isset($element['#webform_component']) && $element['#webform_component']['type'] == 'date') {
143
144
145
146
147
148
            $message = t('Month in !name field is required.', array('!name' => $element['#title']));
            _clientside_validation_set_required($element['#name'] . '[month]', $element['#title'], TRUE, $js_rules, $message);
            $message = t('Day in !name field is required.', array('!name' => $element['#title']));
            _clientside_validation_set_required($element['#name'] . '[day]', $element['#title'], TRUE, $js_rules, $message);
            $message = t('Year in !name field is required.', array('!name' => $element['#title']));
            _clientside_validation_set_required($element['#name'] . '[year]', $element['#title'], TRUE, $js_rules, $message);
Peter Droogmans's avatar
Peter Droogmans committed
149
            if (is_numeric($element['#year_start']) && is_numeric($element['#year_end'])) {
150
151
152
              $message = t('The entered date needs to be between the years @start and @end.', array('@start' => $element['#year_start'], '@end' => $element['#year_end']));
              _clientside_validation_set_minmax($element['#name'] . '[year]', $element['#title'], $element['#year_start'], $element['#year_end'], $js_rules, $message);
            }
Peter Droogmans's avatar
Peter Droogmans committed
153
154
155
156
          }
          else if ($element['#type'] == 'checkboxes') {
            $count = 0;
            foreach ($element['#options'] as $key => $value) {
157
158
              _clientside_validation_set_checkboxgroup_minmax($element[$key]['#name'], $element['#title'], '#webform-component-' . end($element['#parents']), $count, $js_rules);
              $count++;
Peter Droogmans's avatar
Peter Droogmans committed
159
160
161
            }
          }
          else if ($element['#type'] == 'select' && $element['#multiple']) {
162
            _clientside_validation_set_required($element['#name'] . '[]', $element['#title'], TRUE, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
163
164
          }
          else if (isset($element['#type'])) {
165
            _clientside_validation_set_required($element['#name'], $element['#title'], TRUE, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
166
167
168
          }
        }
        if (isset($element['#webform_component']) && $element['#webform_component']['type'] == 'file' && $element['#webform_component']['mandatory'] == "1") {
169
           _clientside_validation_set_required($element['#name'], $element['#title'], TRUE, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
170
171
          if (isset($element['#webform_component']['extra']['filtering']['types'])) {
            $extensions = $element['#webform_component']['extra']['filtering']['types'];
172
            _clientside_validation_set_extensions($element['#name'], $extensions, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
173
174
          }
        }
Peter Droogmans's avatar
Peter Droogmans committed
175
        if (isset($element['#maxlength']) && $element['#maxlength']) {
176
177
          $message = t('!name field has a max length of !maxl characters.', array('!name' => $element['#title'], '!maxl' => $element['#maxlength']));
          _clientside_validation_set_minmaxlength($element['#name'], $element['#title'], '', $element['#maxlength'], $js_rules, $message);
Peter Droogmans's avatar
Peter Droogmans committed
178
        }
179
        
Peter Droogmans's avatar
Peter Droogmans committed
180
        if (isset($element['#webform_component']) && $element['#webform_component']['type'] == 'email') {
181
          _clientside_validation_set_email($element['#name'], $element['#title'], $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
182
183
184
185
186
187
188
        }
      }
      clientside_validation_webform_after_build_recurse($form_id, $element, $form_state, $js_rules);
    }
  }
}

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/**
 * Implements hook_webform_validation().
 */
function clientside_validation_webform_validation($nid) {
  static $webform_validation_rules;
  if (!isset($webform_validation_rules[$nid])) {
    if (module_exists('webform_validation')) {
      $webform_validation_rules[$nid] = webform_validation_get_node_rules($nid);
    }
    else {
      $webform_validation_rules[$nid] = NULL;
    }
  }
  return $webform_validation_rules[$nid];
}

Peter Droogmans's avatar
Peter Droogmans committed
205
206
207
208
209
/**
 * Regular form + CCK
 */
function clientside_validation_form_after_build(&$form, &$form_state) {
  static $js_rules = array();
210
  clientside_validation_form_after_build_recurse($form['#id'], $form, $form_state, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
211
212
213
214
215
216
217
218
219
220
221
222
  if (!empty($js_rules)) {
    $settings['clientsideValidation']['general'] = array (
      "errorClass" => "error",
      "wrapper" => "li",
    );
    $settings['clientsideValidation']['forms'][$form['#id']]['settings'] = array(
      "errorContainer" => "#formerrors-" . $form['#id'],
      "errorLabelContainer" => "#formerrors-" . $form['#id'] . " ul",
    );
    foreach($js_rules as $key => $rule) {
      $settings['clientsideValidation']['forms'][$form['#id']]['rules'][$key] = $rule;
    }
Peter Droogmans's avatar
Peter Droogmans committed
223
224
    drupal_add_js(drupal_get_path('module', 'clientside_validation') . '/jquery-validate/jquery.validate.js');
    drupal_add_js(drupal_get_path('module', 'clientside_validation') . '/clientside_validation.js');
Peter Droogmans's avatar
Peter Droogmans committed
225
226
227
228
229
230
231
232
233
234
    drupal_add_js($settings, 'setting');
  }
  
  return $form;
}

function clientside_validation_form_after_build_recurse($form_id, &$form, &$form_state, &$js_rules) {
  if ($children = array_values(element_children($form))) {
    foreach ($children as $index => $item) {
      $element = &$form[$item];
235
236
237
238
239
      $types = array(
        'textfield', 'textarea', 'select', 'radio', 'checkbox', 'password', 'file', 'radios', 'checkboxes',
      );
      if (isset($element['#type']) && in_array($element['#type'], $types)) {
        clientside_validation_regular ($form_id, $element, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
240
241
242
243
244
245
246
247
248
249
      }
      clientside_validation_form_after_build_recurse($form_id, $element, $form_state, $js_rules);
    }
  }
}

function clientside_validation_regular ($form_id, $element, &$js_rules) {
  static $multiples = array();
  if (isset($element['#name']) && !isset($js_rules[$element['#name']])) {
    $el_name = $element['#name'];
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
    $el_title = $el_name;
    if (isset($element['#title'])) {
      $el_title = $element['#title'];
    }
    $is_multiple = FALSE;
    if (isset($element['#multiple'])) {
      $is_multiple = $element['#multiple'];
    }
    switch ($element['#type']) {
      case 'textfield':
      case 'password':
      case 'textarea':
      case 'file':
        if ($is_multiple) {
          // Only first field is required
          if (!isset($multiples[$form_id][$el_name])) {
            _clientside_validation_set_required ($el_name, $el_title, $element['#required'], $js_rules);
            $multiples[$form_id][$el_name] = 1;
          }
Peter Droogmans's avatar
Peter Droogmans committed
269
        }
270
271
272
273
274
        else {
          _clientside_validation_set_required ($el_name, $el_title, $element['#required'], $js_rules);
        }
        if (isset($element['max_length']) && $element['max_length'] > 0) {
          _clientside_validation_set_minmaxlength ($el_name, $el_title, '', $element['max_length'], $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
275
276
        }
        break;
277
278
279
280
281
282
283
      case 'select':
        if ($is_multiple) {
          $el_name .= '[]';
          if(!isset($element['#minlength'])){
            $element['#minlength'] = 0;
          }
          _clientside_validation_set_minmaxlength ($el_name, $el_title, $element['#minlength'], $is_multiple, $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
284
        }
285
        _clientside_validation_set_required ($el_name, $el_title, $element['#required'], $js_rules);
Peter Droogmans's avatar
Peter Droogmans committed
286
        break;
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
      case 'radio':
      case 'radios':
        _clientside_validation_set_required ($el_name, $el_title, $element['#required'], $js_rules);
        break;
      case 'checkbox':
      case 'checkboxes':
        $is_multiple = (isset($element['#options']) && count($element['#options']>1));
        if ($is_multiple) {
          // We don't have a parent element to connect to, so no go, outer div has only a class
          // The checkboxes element has the unique name, but this isn't added to the outer div
          $count = 0;
          foreach ($element['#options'] as $key => $value) {
            $id = '#edit-' . str_replace('_', '-', $element['#parents'][0]);
            _clientside_validation_set_checkboxgroup_minmax($element[$key]['#name'], $element['#title'], $id, $count, $js_rules);
            $count++;
          }
        }
        else {
          _clientside_validation_set_required ($el_name, $el_title, $element['#required'], $js_rules);
        }
Peter Droogmans's avatar
Peter Droogmans committed
307
308
309
310
311
        break;
    }
  }
}

312
313
314
315
/**
 * Set validation rule for required fields.
 */
function _clientside_validation_set_required ($name, $title, $required, &$js_rules, $message = '') {
Peter Droogmans's avatar
Peter Droogmans committed
316
317
  if ($required) {
    $js_rules[$name]['required'] = TRUE;
318
    $js_rules[$name]['messages']['required'] = (empty($message)) ? t('!name field is required.', array('!name' => $title)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
319
320
321
  }
}

322
323
324
/**
 * Set validation rule for number fields.
 */
Peter Droogmans's avatar
Peter Droogmans committed
325
326
327
328
329
function _clientside_validation_set_number ($name, $title, $decimalpoint, &$js_rules) {
  $js_rules[$name]['digits_negative'] = TRUE;
  $js_rules[$name]['messages']['digits_negative'] = t('!name field accepts only numbers.', array('!name' => $title));
}

330
331
332
/**
 * Set validation rule for decimal fields.
 */
Peter Droogmans's avatar
Peter Droogmans committed
333
334
335
336
337
338
339
340
341
342
343
function _clientside_validation_set_number_decimal ($name, $title, $decimalpoint, &$js_rules) {
  if ($decimalpoint == '.') {
    $js_rules[$name]['number'] = TRUE;
    $js_rules[$name]['messages']['number'] = t('!name field accepts only numbers (use a \'.\' as decimal point).', array('!name' => $title));
  }
  else {
    $js_rules[$name]['numberDE'] = TRUE;
    $js_rules[$name]['messages']['numberDE'] = t('!name field accepts only numbers (use a \',\' as decimal point).', array('!name' => $title));
  }
}

344
345
346
347
/**
 * Set validation rule for fields with a minimum and/or a maximum value.
 */
function _clientside_validation_set_minmax ($name, $title, $min, $max, &$js_rules, $message = '') {
Peter Droogmans's avatar
Peter Droogmans committed
348
349
  if (isset($min) && $min != '' && isset($max) && $max != '') {
    $js_rules[$name]['range'] = array($min, $max);
350
    $js_rules[$name]['messages']['range'] = (empty($message)) ? t('!name field has to be between !min and !max.', array('!name' => $title, '!min' => $min, '!max' => $max)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
351
352
353
  }
  else if (isset($min) && $min != '') {
    $js_rules[$name]['min'] = $min;
354
    $js_rules[$name]['messages']['min'] = (empty($message)) ? t('!name field has to be greater than !min.', array('!name' => $title, '!min' => $min)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
355
356
357
  }
  else if (isset($max) && $max != '') {
    $js_rules[$name]['max'] = $max;
358
    $js_rules[$name]['messages']['max'] = (empty($message)) ? t('!name field has to be smaller than !max.', array('!name' => $title, '!max' => $max)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
359
360
361
  }
}

362
363
364
365
/**
 * Set validation rule for fields with a minimum and/or maximum length.
 */
function _clientside_validation_set_minmaxlength ($name, $title, $min, $max, &$js_rules, $message = '') {
Peter Droogmans's avatar
Peter Droogmans committed
366
367
  if (isset($min) && $min != '' && isset($max) && $max != '') {
    $js_rules[$name]['rangelength'] = array($min, $max);
368
    $js_rules[$name]['messages']['rangelength'] = (empty($message)) ? t('!name field has to have between !min and !max values.', array('!name' => $title, '!min' => $min, '!max' => $max)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
369
370
371
  }
  else if (isset($min) && $min != '') {
    $js_rules[$name]['minlength'] = $min;
372
    $js_rules[$name]['messages']['minlength'] = (empty($message)) ? t('!name field has to have minimal !min values.', array('!name' => $title, '!min' => $min)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
373
374
375
  }
  else if (isset($max) && $max != '') {
    $js_rules[$name]['maxlength'] = $max;
376
    $js_rules[$name]['messages']['maxlength'] = (empty($message)) ? t('!name field has to have maximum !max values.', array('!name' => $title, '!max' => $max)) : $message;
Peter Droogmans's avatar
Peter Droogmans committed
377
378
379
  }
}

380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
/**
 * Set validation rule for required fields that must equal a value from an other field.
 */
function _clientside_validation_set_equal($name, $title, $value, &$js_rules){
  $js_rules[$name]['equalTo'] = ':input[name=\'submitted[' . $value['form_key'] . ']\']';
  $js_rules[$name]['messages']['equalTo'] = t('!name field has to be equal to !firstone.', array('!name' => $title, '!firstone' => $value['name']));
}

/**
 * Set validation rule for fields that can not be equal to a value from an other field.
 */
function _clientside_validation_set_not_equal($name, $title, $value, &$js_rules, $message = ''){
  $js_rules[$name]['notEqualTo'] = ':input[name=\'submitted[' . $value['form_key'] . ']\']';
  $message = empty($message) ? t('!name field has to different from !firstone.', array('!name' => $title, '!firstone' => $value['name'])) : $message;
  $js_rules[$name]['messages']['notEqualTo'] = $message;
}

/**
 * Set validation rule for fields that must be equal to a specific value.
 */
function _clientside_validation_set_specific_value($name, $title, $value, &$js_rules, $message = ''){
  $js_rules[$name]['oneOf'] = $value;
  $message = empty($message) ? t('!name field has to different from !firstone.', array('!name' => $title, '!firstone' => $value['name'])) : $message;
  $js_rules[$name]['messages']['oneOf'] = $message;
}

/**
 * Set validation rule for ean number fields.
 */
function _clientside_validation_set_ean($name, $title, &$js_rules, $message = ''){
  $message = empty($message) ? t('!name field is not a valid EAN number.', array('!name' => $title)) : $message;
  $js_rules[$name]['validEAN'] = TRUE;
Peter Droogmans's avatar
Peter Droogmans committed
412
413
}

414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
/**
 * Set validation rule for file fields that must have a certain extension.
 */
function _clientside_validation_set_extensions($name, $extensions, &$js_rules){
  $extension_list = preg_replace('#,(?![^,]+,)#', ' or', implode(', ', $extensions));
  $js_rules[$name]['accept'] = implode('|', $extensions);
  $js_rules[$name]['messages']['accept'] = t("Only files with a %exts extension are allowed.", array('%exts' => $extension_list));
}

/**
 * Set validation rule for checkboxes.
 */
function _clientside_validation_set_checkboxgroup_minmax($name, $title, $id, $count, &$js_rules, $min = 1, $max = 99){
  $js_rules[$name]['checkboxgroupminmax'] = array($min, $max, $id);
  if ($count == 0) {
    $js_rules[$name]['messages']['checkboxgroupminmax'] = t('!name field is required.', array('!name' => $title));
  }
  else {
    $js_rules[$name]['messages']['checkboxgroupminmax'] = false;
  }
}

/**
 * Set validation rule for email fields.
 */
function _clientside_validation_set_email($name, $title, &$js_rules){
  $js_rules[$name]['email'] = TRUE;
  $js_rules[$name]['messages']['email'] = t('The value in !name is not a valid email address.', array('!name' => $title));
}

function clientside_validation_drupal_json_encode($var) {
  return str_replace(array('<', '>', '&'), array('\u003c', '\u003e', '\u0026'), json_encode($var));
}