Projet

Général

Profil

Révision a45e4bc1

Ajouté par Assos Assos il y a environ 9 ans

Update webform to 4.10

Voir les différences:

drupal7/sites/all/modules/webform/CHANGELOG.txt
1
Webform 2.x Changelog
2
---------------------
3

  
4
2.x to 3.0
5
----------
6
- Module directory structure moved around.
7
- Webform configuration moved to an entirely separate tab.
8
- E-mail templates are now editable by administrators.
9
- Conditional fields.
10
- Submissions may be saved as a draft and resumed later.
11
- Webform may now be attached to any content type.
12
- Public API for allowing other modules to provide components.
13
- Public API for interacting with submission save, insert, update, and delete.
14
- New rendering capabilities for HTML presentation of submissions and e-mails.
15
- Print module support.
16
- Basic Views module support.
17
- Popup calendar support on Date components (with Date Popup module).
18
- New Mollom module integration.
19

  
20
1.x to 2.0
21
----------
22
- Redirect POST option removed.
23
- Webform components moved to the "Form components" tab when editing.
24
- Webform node structure changed. All webform additions to the node are placed in $node->webform.
25
- Clone option added to components.
26
- Database storage improved to be more consistent and efficient.
27
- Additional e-mails may be sent by modifying the $node->webform['additional_emails'] variable in the Additional Validation field.
28
- The values of select and hidden fields may receive e-mails by using the option in Conditional e-mail recipients field.
29
- E-mail from name, from address, and from subject may be entered in a text field.
30
- The complete webform may be shown in the teaser view of a node.
31
- Submit button text may be changed.
32
- Theme function theme_webform_create_mailmessage() has been renamed to theme_webform_mail_message().
33
- $cid parameter added to theme_webform_mail_message() to create unique e-mails depending on a particular recipient or component.
34
- Theme function theme_webform_mail_headers added.
35
- Component descriptions are textareas rather than textfields.
36
- _webform_filtervalues() has been renamed to _webform_filter_values.
37

  
drupal7/sites/all/modules/webform/README.txt
1 1
Description
2 2
-----------
3 3
This module adds a webform content type to your Drupal site.
4
A webform can be a questionnaire, contact or request form. These can be used 
4
A webform can be a questionnaire, contact or request form. These can be used
5 5
by visitor to make contact or to enable a more complex survey than polls
6
provide. Submissions from a webform are saved in a database table and 
6
provide. Submissions from a webform are saved in a database table and
7 7
can optionally be mailed to e-mail addresses upon submission.
8 8

  
9 9
Requirements
10 10
------------
11 11
Drupal 7.x
12
See https://www.drupal.org/project/webform for additional requirements.
12 13

  
13 14
Installation
14 15
------------
......
23 24

  
24 25
Upgrading from previous versions
25 26
--------------------------------
26
Note that if you are upgrading from a Drupal 6 installation of Webform, you MUST
27
have been running Webform 3.x on your Drupal 6 site before upgrading to Drupal
28
7 and Webform 3.x. You cannot upgrade directly from Webform 6.x-2.x to Webform
29
7.x-3.x.
27
Note that you must be running the latest 3.x version of Webform (for either
28
Drupal 6 or Drupal 7) before upgrading to Webform 4.x.
30 29

  
31
1. Copy the entire webform directory the Drupal modules directory.
30
If you have contributed modules, custom modules, or theming on your Webforms,
31
please read over the documentation for upgrading your code for Webform 4.x at
32
https://drupal.org/node/1609324.
32 33

  
33
2. Login as the FIRST user or change the $access_check in update.php to FALSE
34
1. MAKE A DATABASE BACKUP. Upgrading to Webform 4.x makes a signficant number of
35
   database changes. If you encounter an error and need to downgrade, you must
36
   restore the previous database. You can make a database backup with your
37
   hosting provider, using the Backup and Migrate module, or from the command
38
   line.
34 39

  
35
3. Run update.php (at http://www.example.com/update.php)
40
2. Copy the entire webform directory the Drupal modules directory, replacing the
41
   old copy of Webform. DO NOT KEEP THE OLD COPY in the same directory or
42
   anywhere Drupal could possibily find it. Delete it from the server.
43

  
44
3. Login as an administrative user or change the $update_free_access in
45
   update.php to TRUE.
46

  
47
4. Run update.php (at http://www.example.com/update.php).
36 48

  
37 49
Support
38 50
-------
drupal7/sites/all/modules/webform/THEMING.txt
66 66
    <li><a href="<?php print url('node/'. $node->nid . '/submission/'. $sid)?>">View your submission</a></li>
67 67
    <li><a href="<?php print url('node/'. $node->nid . '/submission/'. $sid .'/edit')?>">Edit your submission</a></li>
68 68
  </ul>
69
  
69

  
70 70
  <?php /* End sample webform confirmation page */ ?>
71 71

  
72 72
- You may edit the webform-confirmation.tpl.php file in your theme directory,
......
111 111
use webform-submission-[node id here].tpl.php for individual nodes if desired.
112 112
Note that the contents of this template are used not only for display of
113 113
submissions in the Webform interface but also in e-mails when printing out
114
the %email_values token.
114
the [submission:values] token.
115 115

  
drupal7/sites/all/modules/webform/components/date.inc
15 15
    'pid' => 0,
16 16
    'weight' => 0,
17 17
    'value' => '',
18
    'mandatory' => 0,
18
    'required' => 0,
19 19
    'extra' => array(
20 20
      'timezone' => 'user',
21
      'exclude' => array(),
21 22
      'start_date' => '-2 years',
22 23
      'end_date' => '+2 years',
23 24
      'year_textfield' => 0,
......
25 26
      'title_display' => 0,
26 27
      'description' => '',
27 28
      'private' => FALSE,
29
      'analysis' => FALSE,
28 30
    ),
29 31
  );
30 32
}
......
73 75
    '#access' => variable_get('configurable_timezones', 1),
74 76
  );
75 77

  
78
  $form['extra']['exclude'] = array(
79
    '#type' => 'checkboxes',
80
    '#title' => t('Hide'),
81
    '#default_value' => $component['extra']['exclude'],
82
    '#options' => array(
83
      'day' => t('Day'),
84
      'month' => t('Month'),
85
      'year' => t('Year'),
86
    ),
87
    '#description' => t('A hidden day or month will be set to 1. A hidden year will be set to the year of the default value.'),
88
    '#weight' => 3,
89
  );
90

  
76 91
  $form['display']['datepicker'] = array(
77 92
    '#type' => 'checkbox',
78 93
    '#title' => t('Enable popup calendar'),
......
110 125
    '#parents' => array('extra', 'end_date'),
111 126
  );
112 127

  
128
  $form['#validate'] = array('_webform_edit_date_validate');
113 129
  return $form;
114 130
}
115 131

  
132
/**
133
 * Implements hook_form_id_validate.
134
 *
135
 * Warns user about hiding all the date fields and not using the date picker.
136
 */
137
function _webform_edit_date_validate($form, &$form_state) {
138
  // Reduce checkbox values to simple non-associative array of values.
139
  form_set_value($form['extra']['exclude'], array_filter(array_values($form_state['values']['extra']['exclude'])), $form_state);
140

  
141
  // Note that Drupal 7 doesn't support setting errors no checkboxes due to
142
  // browser issues. @see https://www.drupal.org/node/222380
143
  if (count($form_state['values']['extra']['exclude']) == 3) {
144
    form_set_error('extra][exclude', 'The day, month and year can\'t all be hidden.');
145
  }
146
  if ($form_state['values']['extra']['exclude'] == array('month')) {
147
    form_set_error('extra][exclude', 'You cannot hide just the month.');
148
  }
149

  
150
  // Validate that the start and end dates are valid. Don't validate the default
151
  // date because with token substitution, it might not be valid at component
152
  // definition time. Also note that validation was introduced in 7.x-4.8 and
153
  // previously-defined webform may have invalid start and end dates.
154
  foreach (array('start_date', 'end_date') as $field) {
155
    if (trim($form_state['values']['extra'][$field]) && !($date[$field] = webform_strtodate('c', $form_state['values']['extra'][$field]))) {
156
      form_set_error("extra][$field", t('The @field could not be interpreted in <a href="http://www.gnu.org/software/tar/manual/html_chapter/Date-input-formats.html">GNU Date Input Format</a>.',
157
                                                 array('@field' => $form['validation'][$field]['#title'])));
158
    }
159
  }
160
  if (!empty($date['start_date']) && !empty($date['end_date']) && $date['end_date'] < $date['start_date']) {
161
    form_set_error('extra][end_date', t('The End date must be on or after the Start date.'));
162
  }
163
}
164

  
116 165
/**
117 166
 * Implements _webform_render_component().
118 167
 */
119
function _webform_render_date($component, $value = NULL, $filter = TRUE) {
168
function _webform_render_date($component, $value = NULL, $filter = TRUE, $submission = NULL) {
120 169
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
121 170

  
122 171
  $element = array(
123 172
    '#type' => 'date',
124
    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
173
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
125 174
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
126 175
    '#weight' => $component['weight'],
127
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
128
    '#required' => $component['mandatory'],
176
    '#description' => $filter ? webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
177
    '#required' => $component['required'],
129 178
    '#start_date' => trim($component['extra']['start_date']),
130 179
    '#end_date' => trim($component['extra']['end_date']),
180
    '#reference_timestamp' => $submission && $submission->completed ? $submission->completed : NULL,
131 181
    '#year_textfield' => $component['extra']['year_textfield'],
132
    '#default_value' => $filter ? _webform_filter_values($component['value'], $node, NULL, NULL, FALSE) : $component['value'],
182
    '#default_value' => $filter ? webform_replace_tokens($component['value'], $node) : $component['value'],
133 183
    '#timezone' => $component['extra']['timezone'],
184
    '#exclude' => $component['extra']['exclude'],
134 185
    '#process' => array('webform_expand_date'),
135 186
    '#theme' => 'webform_date',
136 187
    '#theme_wrappers' => array('webform_element'),
......
160 211
 * Form API #process function for Webform date fields.
161 212
 */
162 213
function webform_expand_date($element) {
214
  $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
215
  
163 216
  // Accept a string or array value for #default_value.
164 217
  if (!empty($element['#default_value']) && is_string($element['#default_value'])) {
165
    $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
166 218
    $timestring = webform_strtodate('c', $element['#default_value'], $timezone);
167 219
    $element['#default_value'] = webform_date_array($timestring, 'date');
168 220
  }
......
190 242
  // Let Drupal do it's normal expansion.
191 243
  $element = form_process_date($element);
192 244

  
245
  // Convert relative dates to absolute and calculate the year, month and day.
246
  $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
247
  foreach (array('start', 'end') as $start_end) {
248
    $element_field = &$element["#{$start_end}_date"];
249
    $element_field = $element_field ? webform_strtodate('Y-m-d', $element_field, $timezone, $element['#reference_timestamp']) : '';
250
    if ($element_field) {
251
      $parts = explode('-', $element_field);
252
    }
253
    else {
254
      $parts = $start_end == 'start' ? array(webform_strtodate('Y', '-2 years'), 1, 1) : array(webform_strtodate('Y', '+2 years'), 12, 31);
255
      $element_field = '';
256
    }
257
    unset($element_field); // Drop PHP reference.
258
    $parts[3] = $parts[0] . '-' . $parts[1] . '-' . $parts[2];
259
    $range[$start_end] = array_combine(array('year', 'month', 'day', 'date'), $parts);
260
  }
261

  
262
  // The start date is not guaranteeed to be early than the end date for
263
  // historical reasons.
264
  if ($range['start']['date'] > $range['end']['date']) {
265
    $temp = $range['start'];
266
    $range['start'] = $range['end'];
267
    $range['end'] = $temp;
268
  }
269

  
270
  // Restrict the months and days when not all options are valid choices.
271
  if ($element['#start_date'] && $element['#end_date']) {
272
    $delta_months = ($range['end']['year'] * 12 + $range['end']['month']) - ($range['start']['year'] * 12 + $range['start']['month']);
273
    if ($delta_months < 11) {
274
      // There are 10 or fewer months between the start and end date. If there
275
      // were 11, then every month would be possible, and the menu select
276
      // should not be pruned.
277
      $month_options = &$element['month']['#options'];
278
      if ($range['start']['month'] <= $range['end']['month']) {
279
        $month_options = array_intersect_key($month_options, array_flip(range($range['start']['month'], $range['end']['month'])));
280
      }
281
      else {
282
        $month_options = array_intersect_key($month_options, array_flip(range($range['start']['month'], 12))) +
283
                         array_intersect_key($month_options, array_flip(range(1, $range['end']['month'])));
284
      }
285
      unset($month_options); // Drop PHP reference.
286
      if ($delta_months <= 1) {
287
        // The start and end date are either on the same month or consequtive
288
        // months. See if the days should be pruned.
289
        $day_options = &$element['day']['#options'];
290
        if ($range['start']['month'] == $range['end']['month']) {
291
          // Range is within the same month. The days are a simple range from
292
          // start day to end day.
293
          $day_options = array_intersect_key($day_options, array_flip(range($range['start']['day'], $range['end']['day'])));
294
        }
295
        elseif ($range['start']['day'] > $range['end']['day'] + 1) {
296
          // Range spans two months and at least one day would be omitted.
297
          $days_in_month = date('t', mktime(0, 0, 0, $range['start']['month'], 1, $range['start']['year']));
298
          $day_options = array_intersect_key($day_options, array_flip(range($range['start']['day'], $days_in_month))) +
299
                         array_intersect_key($day_options, array_flip(range(1, $range['end']['day'])));
300
        }
301
        unset($day_options); // Drop PHP reference.
302
      }
303
    }
304
  }
305

  
193 306
  // Set default values.
194 307
  foreach ($default_values as $type => $value) {
195 308
    switch ($type) {
196 309
      case 'month':
197 310
        $none = t('Month');
311
        $hidden_default = 1;
198 312
        break;
199 313
      case 'day':
200 314
        $none = t('Day');
315
        $hidden_default = 1;
201 316
        break;
202 317
      case 'year':
203 318
        $none = t('Year');
319
        $hidden_default = !empty($element['#default_value']['year']) ? $element['#default_value']['year'] : webform_strtodate('Y', 'today', $timezone);
204 320
        break;
205 321
    }
206 322
    unset($element[$type]['#value']);
207 323
    $element[$type]['#title'] = $none;
208 324
    $element[$type]['#title_display'] = 'invisible';
209
    $element[$type]['#default_value'] = isset($default_values[$type]) ? $default_values[$type] : NULL;
325
    $element[$type]['#default_value'] = $default_values[$type];
210 326
    $element[$type]['#options'] = array('' => $none) + $element[$type]['#options'];
211
  }
212

  
213
  // Convert relative dates to absolute ones.
214
  foreach (array('start_date', 'end_date') as $start_end) {
215
    $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
216
    $date = webform_strtodate('Y-m-d', $element['#' . $start_end], $timezone);
217
    $element['#' . $start_end] = $date ? $date : '';
327
    if (in_array($type, $element['#exclude'])) {
328
      $element[$type] += array(
329
        '#prefix' => '<div class="webform-date-field-wrapper element-invisible">',
330
        '#suffix' => '</div>',
331
      );
332
      $element[$type]['#default_value'] = $hidden_default;
333
    }
218 334
  }
219 335

  
220 336
  // Tweak the year field.
......
225 341
    unset($element['year']['#options']);
226 342
  }
227 343
  elseif ($element['#start_date'] || $element['#end_date']) {
228
    $start_year = $element['#start_date'] ? webform_strtodate('Y', $element['#start_date']) : webform_strtodate('Y', '-2 years');
229
    $end_year = $element['#end_date'] ? webform_strtodate('Y', $element['#end_date']) : webform_strtodate('Y', '+2 years');
230
    $element['year']['#options'] = array('' => t('Year')) + drupal_map_assoc(range($start_year, $end_year));
344
    $element['year']['#options'] = array('' => t('Year')) + drupal_map_assoc(range($range['start']['year'], $range['end']['year']));
231 345
  }
232 346

  
233 347
  return $element;
......
250 364
    $element['day']['#attributes']['class'][] = 'error';
251 365
  }
252 366

  
367
  // Add HTML5 required attribute, if needed.
368
  if ($element['#required']) {
369
    $element['year']['#attributes']['required'] = 'required';
370
    $element['month']['#attributes']['required'] = 'required';
371
    $element['day']['#attributes']['required'] = 'required';
372
  }
373

  
253 374
  $class = array('webform-container-inline');
254 375

  
255 376
  // Add the JavaScript calendar if available (provided by Date module package).
......
280 401
 * Element validation for Webform date fields.
281 402
 */
282 403
function webform_validate_date($element, $form_state) {
283
  // Check if the user filled the required fields.
284
  foreach (array('day', 'month', 'year') as $field_type) {
285
    if (!is_numeric($element[$field_type]['#value']) && $element['#required']) {
286
      form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
404
  if ($element['month']['#value'] !== '' || $element['day']['#value'] !== '' || $element['year']['#value'] !== '') {
405
    // Check that each part of the date has been filled in.
406
    foreach (array('day', 'month', 'year') as $field_type) {
407
      if (empty($element[$field_type]['#value'])) {
408
        form_error($element[$field_type], t('!part in !name is missing.', array('!name' => $element['#title'], '!part' => $element[$field_type]['#title'])));
409
        $missing_fields = TRUE;
410
      }
411
    }
412
    if (isset($missing_fields)) {
287 413
      return;
288 414
    }
289
  }
290 415

  
291
  if ($element['month']['#value'] !== '' || $element['day']['#value'] !== '' || $element['year']['#value'] !== '') {
292 416
    // Check for a valid date.
293
    if (!checkdate((int) $element['month']['#value'], (int) $element['day']['#value'], (int) $element['year']['#value'])) {
417
    if (!checkdate($element['month']['#value'], $element['day']['#value'], $element['year']['#value'])) {
294 418
      form_error($element, t('Entered !name is not a valid date.', array('!name' => $element['#title'])));
295 419
      return;
296 420
    }
......
299 423
    $timestamp = strtotime($element['year']['#value'] . '-' . $element['month']['#value'] . '-' . $element['day']['#value']);
300 424
    $format = webform_date_format('short');
301 425

  
302
    // Flip start and end if needed.
426
    // Flip start and end if needed. Prior to 7.x-4.8, it was possible to save
427
    // a date component with the end date earlier than the start date.
303 428
    $date1 = strtotime($element['#start_date']);
304 429
    $date2 = strtotime($element['#end_date']);
305 430
    if ($date1 !== FALSE && $date2 !== FALSE) {
......
312 437
    }
313 438

  
314 439
    // Check that the date is after the start date.
315
    if ($start_date !== FALSE) {
316
      if ($timestamp < $start_date) {
317
        form_error($element, t('The entered date must be @start_date or later.', array('@start_date' => date($format, $start_date))));
318
      }
440
    if ($start_date !== FALSE && $timestamp < $start_date) {
441
      form_error($element, t('The entered date must be @start_date or later.', array('@start_date' => date($format, $start_date))));
319 442
    }
320 443

  
321 444
    // Check that the date is before the end date.
322
    if ($end_date !== FALSE) {
323
      if ($timestamp > $end_date) {
324
        form_error($element, t('The entered date must be @end_date or earlier.', array('@end_date' => date($format, $end_date))));
325
      }
445
    if ($end_date !== FALSE && $timestamp > $end_date) {
446
      form_error($element, t('The entered date must be @end_date or earlier.', array('@end_date' => date($format, $end_date))));
326 447
    }
327 448
  }
449
  elseif ($element['#required']) {
450
    form_error($element, t('!name field is required.', array('!name' => $element['#title'])));
451
  }
328 452
}
329 453

  
330 454
/**
......
338 462
/**
339 463
 * Implements _webform_display_component().
340 464
 */
341
function _webform_display_date($component, $value, $format = 'html') {
465
function _webform_display_date($component, $value, $format = 'html', $submission = array()) {
342 466
  $value = webform_date_array(isset($value[0]) ? $value[0] : '', 'date');
343 467

  
344 468
  return array(
345 469
    '#title' => $component['name'],
470
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
346 471
    '#weight' => $component['weight'],
347 472
    '#theme' => 'webform_display_date',
348 473
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
349 474
    '#format' => $format,
475
    '#exclude' => $component['extra']['exclude'],
476

  
350 477
    '#value' => $value,
351 478
    '#translatable' => array('title'),
352 479
  );
......
360 487
  $output = ' ';
361 488
  if ($element['#value']['year'] && $element['#value']['month'] && $element['#value']['day']) {
362 489
    $timestamp = webform_strtotime($element['#value']['month'] . '/' . $element['#value']['day'] . '/' . $element['#value']['year']);
363
    $format = webform_date_format('medium');
490
    $format = webform_date_format(NULL, $element['#exclude']);
364 491
    $output = format_date($timestamp, 'custom', $format, 'UTC');
365 492
  }
366 493

  
......
370 497
/**
371 498
 * Implements _webform_analysis_component().
372 499
 */
373
function _webform_analysis_date($component, $sids = array()) {
500
function _webform_analysis_date($component, $sids = array(), $single = FALSE, $join = NULL) {
374 501
  $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
375 502
    ->fields('wsd', array('no', 'data'))
376
    ->condition('nid', $component['nid'])
377
    ->condition('cid', $component['cid'])
378
    ->orderBy('sid');
503
    ->condition('wsd.nid', $component['nid'])
504
    ->condition('wsd.cid', $component['cid'])
505
    ->orderBy('wsd.sid');
379 506

  
380 507
  if (count($sids)) {
381
    $query->condition('sid', $sids, 'IN');
508
    $query->condition('wsd.sid', $sids, 'IN');
509
  }
510

  
511
  if ($join) {
512
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
382 513
  }
383 514

  
384 515
  $result = $query->execute();
......
396 527
  $nonblanks = count($dates);
397 528
  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
398 529
  $rows[1] = array(t('User entered value'), $nonblanks);
399
  return $rows;
530

  
531
  return array(
532
    'table_rows' => $rows,
533
  );
400 534
}
401 535

  
402 536
/**
......
405 539
function _webform_table_date($component, $value) {
406 540
  if ($value[0]) {
407 541
    $timestamp = webform_strtotime($value[0]);
408
    $format = webform_date_format('short');
542
    $format = webform_date_format('short', $component['extra']['exclude']);
409 543
    return format_date($timestamp, 'custom', $format, 'UTC');
410 544
  }
411 545
  else {
......
420 554
  $header = array();
421 555
  $header[0] = '';
422 556
  $header[1] = '';
423
  $header[2] = $component['name'];
557
  $header[2] = $export_options['header_keys'] ? $component['form_key'] : $component['name'];
424 558
  return $header;
425 559
}
426 560

  
......
430 564
function _webform_csv_data_date($component, $export_options, $value) {
431 565
  if ($value[0]) {
432 566
    $timestamp = webform_strtotime($value[0]);
433
    $format = webform_date_format('short');
567
    if (!empty($export_options['iso8601_date'])) {
568
      $format = 'Y-m-d'; // ISO 8601 date: 2004-02-12
569
    }
570
    else {
571
      $format = webform_date_format('short');
572
    }
434 573
    return format_date($timestamp, 'custom', $format, 'UTC');
435 574
  }
436 575
  else {
drupal7/sites/all/modules/webform/components/email.inc
15 15
    'pid' => 0,
16 16
    'weight' => 0,
17 17
    'value' => '',
18
    'mandatory' => 0,
18
    'required' => 0,
19 19
    'extra' => array(
20
      'multiple' => 0,
21
      'format' => 'short',
20 22
      'width' => '',
21 23
      'unique' => 0,
22 24
      'disabled' => 0,
23 25
      'title_display' => 0,
24 26
      'description' => '',
27
      'placeholder' => '',
25 28
      'attributes' => array(),
26 29
      'private' => FALSE,
30
      'analysis' => FALSE,
27 31
    ),
28 32
  );
29 33
}
......
52 56
    '#type' => 'textfield',
53 57
    '#title' => t('Default value'),
54 58
    '#default_value' => $component['value'],
55
    '#description' => t('The default value of the field.') . theme('webform_token_help'),
59
    '#description' => t('The default value of the field.') . ' ' . theme('webform_token_help'),
56 60
    '#size' => 60,
57 61
    '#maxlength' => 127,
58 62
    '#weight' => 0,
59
    '#attributes' => ($component['value'] == '%useremail' && count(form_get_errors()) == 0) ? array('disabled' => TRUE) : array(),
63
    '#attributes' => ($component['value'] == '[current-user:mail]' && count(form_get_errors()) == 0) ? array('disabled' => TRUE) : array(),
60 64
    '#id' => 'email-value',
61 65
  );
62 66
  $form['user_email'] = array(
63 67
    '#type' => 'checkbox',
64 68
    '#title' => t('User email as default'),
65
    '#default_value' => $component['value'] == '%useremail' ? 1 : 0,
69
    '#default_value' => $component['value'] == '[current-user:mail]' ? 1 : 0,
66 70
    '#description' => t('Set the default value of this field to the user email, if he/she is logged in.'),
67
    '#attributes' => array('onclick' => 'getElementById("email-value").value = (this.checked ? "%useremail" : ""); getElementById("email-value").disabled = this.checked;'),
71
    '#attributes' => array('onclick' => 'getElementById("email-value").value = (this.checked ? "[current-user:mail]" : ""); getElementById("email-value").disabled = this.checked;'),
68 72
    '#weight' => 0,
69 73
    '#element_validate' => array('_webform_edit_email_validate'),
70 74
  );
75
  $form['extra']['multiple'] = array(
76
    '#type' => 'checkbox',
77
    '#title' => t('Multiple'),
78
    '#default_value' => $component['extra']['multiple'],
79
    '#description' => t('Allow multiple e-mail addresses, separated by commas.'),
80
    '#weight' => 0,
81
  );
82
  if (webform_variable_get('webform_email_address_format') == 'long') {
83
    $form['extra']['format'] = array(
84
      '#type' => 'radios',
85
      '#title' => t('Format'),
86
      '#options' => array(
87
        'long' => t('Allow long format: "Example Name" &lt;name@example.com&gt;'),
88
        'short' => t('Short format only: name@example.com'),
89
      ),
90
      '#default_value' => $component['extra']['format'],
91
      '#description' => t('Not all servers support the "long" format.'),
92
    );
93
  }
71 94
  $form['display']['width'] = array(
72 95
    '#type' => 'textfield',
73 96
    '#title' => t('Width'),
......
77 100
    '#maxlength' => 10,
78 101
    '#parents' => array('extra', 'width'),
79 102
  );
103
  $form['display']['placeholder'] = array(
104
    '#type' => 'textfield',
105
    '#title' => t('Placeholder'),
106
    '#default_value' => $component['extra']['placeholder'],
107
    '#description' => t('The placeholder will be shown in the field until the user starts entering a value.') . ' ' . t('Often used for example values, such as "john@example.com".'),
108
    '#parents' => array('extra', 'placeholder'),
109
  );
80 110
  $form['display']['disabled'] = array(
81 111
    '#type' => 'checkbox',
82 112
    '#title' => t('Disabled'),
......
103 133
 */
104 134
function _webform_edit_email_validate($element, &$form_state) {
105 135
  if ($form_state['values']['user_email']) {
106
    $form_state['values']['value'] = '%useremail';
136
    $form_state['values']['value'] = '[current-user:mail]';
107 137
  }
108 138
}
109 139

  
110 140
/**
111 141
 * Implements _webform_render_component().
112 142
 */
113
function _webform_render_email($component, $value = NULL, $filter = TRUE) {
143
function _webform_render_email($component, $value = NULL, $filter = TRUE, $submission = NULL) {
114 144
  global $user;
115 145
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
116 146

  
117 147
  $element = array(
118 148
    '#type' => 'webform_email',
119
    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
149
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
120 150
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
121
    '#default_value' => $filter ? _webform_filter_values($component['value'], $node) : $component['value'],
122
    '#required' => $component['mandatory'],
151
    '#default_value' => $filter ? webform_replace_tokens($component['value'], $node) : $component['value'],
152
    '#required' => $component['required'],
123 153
    '#weight' => $component['weight'],
124
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
154
    '#description' => $filter ? webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
125 155
    '#attributes' => $component['extra']['attributes'],
126 156
    '#element_validate'  => array('_webform_validate_email'),
127 157
    '#theme_wrappers' => array('webform_element'),
128 158
    '#translatable' => array('title', 'description'),
129 159
  );
130 160

  
161
  if ($component['required']) {
162
    $element['#attributes']['required'] = 'required';
163
  }
164

  
131 165
  // Add an e-mail class for identifying the difference from normal textfields.
132 166
  $element['#attributes']['class'][] = 'email';
133 167

  
......
136 170
    $element['#element_validate'][] = 'webform_validate_unique';
137 171
  }
138 172

  
139
  if (isset($value)) {
173
  if ($component['extra']['format'] == 'long') {
174
    // html5 email elements enforce short-form email validation in addition to
175
    // pattern validation. This means that long format email addresses must be
176
    // rendered as text.
177
    $element['#attributes']['type'] = 'text';
178
    
179
    // html5 patterns have implied delimters and start and end patterns.
180
    // The are also case sensitive, not global, and not multi-line.
181
    // See https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation
182
    // See http://stackoverflow.com/questions/19605773/html5-email-validation
183
    $address = '[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*';
184
    $name = '("[^<>"]*?"|[^<>",]*?)';
185
    $short_long = "($name *<$address>|$address)";
186
    $element['#attributes']['pattern'] = $component['extra']['multiple']
187
                                            ? "$short_long(, *$short_long)*"
188
                                            : $short_long;
189
  }
190
  elseif ($component['extra']['multiple']) {
191
    $element['#attributes']['multiple'] = 'multiple';
192
  }
193

  
194
  if (isset($value[0])) {
140 195
    $element['#default_value'] = $value[0];
141 196
  }
142 197

  
198
  if ($component['extra']['placeholder']) {
199
    $element['#attributes']['placeholder'] = $component['extra']['placeholder'];
200
  }
201

  
143 202
  if ($component['extra']['disabled']) {
144 203
    if ($filter) {
145 204
      $element['#attributes']['readonly'] = 'readonly';
......
193 252
 */
194 253
function _webform_validate_email($form_element, &$form_state) {
195 254
  $component = $form_element['#webform_component'];
196
  $value = trim($form_element['#value']);
197
  if ($value !== '' && !valid_email_address($value)) {
198
    form_error($form_element, t('%value is not a valid email address.', array('%value' => $value)));
199
  }
200
  else {
201
    form_set_value($form_element, $value, $form_state);
202
  }
255
  $format = webform_variable_get('webform_email_address_format') == 'long' ? $component['extra']['format'] : 'short';
256
  webform_email_validate($form_element['#value'],
257
                         implode('][', $form_element ['#parents']),
258
                         TRUE,  // Required validation is done elsewhere.
259
                         $component['extra']['multiple'],
260
                         FALSE, // No tokens are allowed in user input.
261
                         $format);
203 262
}
204 263

  
205 264
/**
206 265
 * Implements _webform_display_component().
207 266
 */
208
function _webform_display_email($component, $value, $format = 'html') {
267
function _webform_display_email($component, $value, $format = 'html', $submission = array()) {
209 268
  return array(
210 269
    '#title' => $component['name'],
270
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
211 271
    '#weight' => $component['weight'],
212 272
    '#theme' => 'webform_display_email',
213 273
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
......
229 289
/**
230 290
 * Implements _webform_analysis_component().
231 291
 */
232
function _webform_analysis_email($component, $sids = array()) {
292
function _webform_analysis_email($component, $sids = array(), $single = FALSE, $join = NULL) {
233 293
  $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
234 294
    ->fields('wsd', array('no', 'data'))
235
    ->condition('nid', $component['nid'])
236
    ->condition('cid', $component['cid']);
295
    ->condition('wsd.nid', $component['nid'])
296
    ->condition('wsd.cid', $component['cid']);
237 297

  
238 298
  if (count($sids)) {
239
    $query->condition('sid', $sids, 'IN');
299
    $query->condition('wsd.sid', $sids, 'IN');
300
  }
301

  
302
  if ($join) {
303
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
240 304
  }
241 305

  
242 306
  $nonblanks = 0;
......
254 318

  
255 319
  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
256 320
  $rows[1] = array(t('User entered value'), $nonblanks);
257
  $rows[2] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
258
  return $rows;
321

  
322
  $other[0] = array(t('Average submission length in words (ex blanks)'), ($nonblanks != 0 ? number_format($wordcount/$nonblanks, 2) : '0'));
323

  
324
  return array(
325
    'table_rows' => $rows,
326
    'other_data' => $other,
327
  );
328

  
259 329
}
260 330

  
261 331
/**
......
273 343
  $header = array();
274 344
  $header[0] = '';
275 345
  $header[1] = '';
276
  $header[2] = $component['name'];
346
  $header[2] = $export_options['header_keys'] ? $component['form_key'] : $component['name'];
277 347
  return $header;
278 348
}
279 349

  
drupal7/sites/all/modules/webform/components/fieldset.inc
51 51
/**
52 52
 * Implements _webform_render_component().
53 53
 */
54
function _webform_render_fieldset($component, $value = NULL, $filter = TRUE) {
54
function _webform_render_fieldset($component, $value = NULL, $filter = TRUE, $submission = NULL) {
55 55
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
56 56

  
57 57
  $element = array(
58 58
    '#type' => 'fieldset',
59
    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
59
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
60 60
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : NULL,
61 61
    '#weight' => $component['weight'],
62
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
62
    '#description' => $filter ? webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
63 63
    '#collapsible' => $component['extra']['collapsible'],
64 64
    '#collapsed' => $component['extra']['collapsed'],
65 65
    '#attributes' => array('class' => array('webform-component-fieldset')),
......
71 71
}
72 72

  
73 73
/**
74
 * Pre-render function to set a fieldset ID.
74
 * Pre-render function to set a unique fieldset class name.
75 75
 */
76 76
function webform_fieldset_prerender($element) {
77
  $element['#id'] = 'webform-component-' . str_replace('_', '-', implode('--', array_slice($element['#parents'], 1)));
77
  $element['#id'] = NULL;
78
  $element['#attributes']['class'][] = 'webform-component--' . str_replace('_', '-', implode('--', array_slice($element['#parents'], 1)));
78 79
  return $element;
79 80
}
80 81

  
81 82
/**
82 83
 * Implements _webform_display_component().
83 84
 */
84
function _webform_display_fieldset($component, $value, $format = 'html') {
85
function _webform_display_fieldset($component, $value, $format = 'html', $submission = array()) {
85 86
  if ($format == 'text') {
86 87
    $element = array(
87 88
      '#title' => $component['name'],
drupal7/sites/all/modules/webform/components/file.inc
12 12
  return array(
13 13
    'name' => '',
14 14
    'form_key' => NULL,
15
    'mandatory' => 0,
15
    'required' => 0,
16 16
    'pid' => 0,
17 17
    'weight' => 0,
18 18
    'extra' => array(
......
21 21
        'addextensions' => '',
22 22
        'size' => '2 MB',
23 23
      ),
24
      'rename' => '',
24 25
      'scheme' => 'public',
25 26
      'directory' => '',
26 27
      'progress_indicator' => 'throbber',
......
28 29
      'description' => '',
29 30
      'attributes' => array(),
30 31
      'private' => FALSE,
32
      'analysis' => FALSE,
31 33
    ),
32 34
  );
33 35
}
......
45 47
      'render element' => 'element',
46 48
      'file' => 'components/file.inc',
47 49
    ),
50
    'webform_managed_file' => array(
51
      'render element' => 'element',
52
      'file' => 'components/file.inc',
53
    ),
48 54
  );
49 55
}
50 56

  
......
77 83
        'js' => array(drupal_get_path('module', 'webform') . '/js/webform-admin.js'),
78 84
        'css' => array(drupal_get_path('module', 'webform') . '/css/webform-admin.css'),
79 85
      ),
86
      '#type' => 'webform_file_extensions',
80 87
      '#weight' => 2,
81 88
    );
82 89

  
......
99 106
      '#default_value' => array_intersect($current_types, $types),
100 107
    );
101 108

  
102
    $types = array('txt', 'rtf', 'html', 'odf', 'pdf', 'doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'xml');
109
    $types = array('txt', 'rtf', 'html', 'pdf', 'doc', 'docx', 'odt', 'ppt', 'pptx', 'odp', 'xls', 'xlsx', 'ods', 'xml');
103 110
    $form['validation']['extensions']['types']['documents'] = array(
104 111
      '#type' => 'checkboxes',
105 112
      '#title' => t('Documents'),
......
149 156
      '#type' => 'textfield',
150 157
      '#title' => t('Upload directory'),
151 158
      '#default_value' => $component['extra']['directory'],
152
      '#description' => t('You may optionally specify a sub-directory to store your files.'),
159
      '#description' => t('You may optionally specify a sub-directory to store your files.') . ' ' . theme('webform_token_help'),
153 160
      '#weight' => 5,
154 161
      '#field_prefix' => 'webform/',
155 162
    );
156 163

  
164
    $form['extra']['rename'] = array(
165
      '#type' => 'textfield',
166
      '#title' => t('Rename files'),
167
      '#default_value' => $component['extra']['rename'],
168
      '#description' => t('You may optionally use tokens to create a pattern used to rename files upon submission. Omit the extension; it will be added automatically.') . ' ' . theme('webform_token_help', array('groups' => array('node', 'submission'))),
169
      '#weight' => 6,
170
      '#element_validate' => array('_webform_edit_file_rename_validate'),
171
    );
172

  
157 173
    $form['display']['progress_indicator'] = array(
158 174
      '#type' => 'radios',
159 175
      '#title' => t('Progress indicator'),
......
185 201
    return $form;
186 202
}
187 203

  
204
/**
205
 * A Form API element validate function to ensure that the rename string is
206
 * either empty or contains at least one token.
207
 */
208
function _webform_edit_file_rename_validate($element, &$form_state, $form) {
209
  $rename = trim($form_state['values']['extra']['rename']);
210
  form_set_value($element, $rename, $form_state);
211
  if (strlen($rename) && !count(token_scan($rename))) {
212
    form_error($element, t('To create unique file names, use at least one token in the file name pattern.'));
213
  }
214
}
215

  
188 216
/**
189 217
 * A Form API element validate function to check filesize is valid.
190 218
 */
......
213 241
  $directory = $element['extra']['directory']['#value'];
214 242

  
215 243
  $destination_dir = file_stream_wrapper_uri_normalize($scheme . '://webform/' . $directory);
244
  $tokenized_dir = drupal_strtolower(webform_replace_tokens($destination_dir, $element['#node']));
216 245

  
217 246
  // Sanity check input to prevent use parent (../) directories.
218
  if (preg_match('/\.\.[\/\\\]/', $destination_dir . '/')) {
219
    form_error($element['extra']['directory'], t('The save directory %directory is not valid.', array('%directory' => $directory)));
247
  if (preg_match('/\.\.[\/\\\]/', $tokenized_dir . '/')) {
248
    form_error($element['extra']['directory'], t('The save directory %directory is not valid.', array('%directory' => $tokenized_dir)));
220 249
  }
221 250
  else {
222
    $destination_success = file_prepare_directory($destination_dir, FILE_CREATE_DIRECTORY);
223
    if (!$destination_success) {
224
      form_error($element['extra']['directory'], t('The save directory %directory could not be created. Check that the webform files directory is writable.', array('%directory' => $directory)));
251
    if (!file_prepare_directory($tokenized_dir, FILE_CREATE_DIRECTORY)) {
252
      form_error($element['extra']['directory'], t('The save directory %directory could not be created. Check that the webform files directory is writable.', array('%directory' => $tokenized_dir)));
225 253
    }
226 254
  }
227 255

  
......
241 269
    foreach (array_keys($element['types'][$category]['#value']) as $extension) {
242 270
      if ($element['types'][$category][$extension]['#value']) {
243 271
        $extensions[] = $extension;
272
        // jpeg is an exception. It is allowed anytime jpg is allowed.
273
        if ($extension == 'jpg') {
274
          $extensions[] = 'jpeg';
275
        }
244 276
      }
245 277
    }
246 278
  }
......
302 334
/**
303 335
 * Implements _webform_render_component().
304 336
 */
305
function _webform_render_file($component, $value = NULL, $filter = TRUE) {
337
function _webform_render_file($component, $value = NULL, $filter = TRUE, $submission = NULL) {
306 338
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
307 339

  
308 340
  // Cap the upload size according to the PHP limit.
......
314 346

  
315 347
  $element = array(
316 348
    '#type' => 'managed_file',
317
    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
349
    '#theme' => 'webform_managed_file',
350
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
318 351
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
319
    '#required' => $component['mandatory'],
352
    '#required' => $component['required'],
320 353
    '#default_value' => isset($value[0]) ? $value[0] : NULL,
321 354
    '#attributes' => $component['extra']['attributes'],
322 355
    '#upload_validators' => array(
......
324 357
      'file_validate_extensions' => array(implode(' ', $component['extra']['filtering']['types'])),
325 358
    ),
326 359
    '#pre_render' => array_merge(element_info_property('managed_file', '#pre_render'), array('webform_file_allow_access')),
327
    '#upload_location' => $component['extra']['scheme'] . '://webform/' . $component['extra']['directory'],
360
    '#upload_location' => $component['extra']['scheme'] . '://webform/' . ($filter
361
                                                                              ? drupal_strtolower(webform_replace_tokens($component['extra']['directory'], $node))
362
                                                                              : $component['extra']['directory']),
328 363
    '#progress_indicator' => $component['extra']['progress_indicator'],
329
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
364
    '#description' => $filter ? webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
330 365
    '#weight' => $component['weight'],
331 366
    '#theme_wrappers' => array('webform_element'),
332 367
    '#translatable' => array('title', 'description'),
333 368
  );
334 369

  
370
  if ($filter) {
371
    $element['#description'] = theme('file_upload_help', array('description' => $element['#description'], 'upload_validators' => $element['#upload_validators']));
372
  }
373

  
335 374
  return $element;
336 375
}
337 376

  
377
/**
378
 * Returns HTML for a webform managed file element.
379
 *
380
 * See #2495821 and #2497909. The core theme_file_managed_file creates a
381
 * wrapper around the element with the element's id, thereby creating 2 elements
382
 * with the same id.
383
 *
384
 * @param $variables
385
 *   An associative array containing:
386
 *   - element: A render element representing the file.
387
 *
388
 */
389
function theme_webform_managed_file($variables) {
390
  $element = $variables['element'];
391

  
392
  $attributes = array();
393

  
394
  // For webform use, do not add the id to the wrapper.
395
  //if (isset($element['#id'])) {
396
  //  $attributes['id'] = $element['#id'];
397
  //}
398

  
399
  if (!empty($element['#attributes']['class'])) {
400
    $attributes['class'] = (array) $element['#attributes']['class'];
401
  }
402
  $attributes['class'][] = 'form-managed-file';
403

  
404
  // This wrapper is required to apply JS behaviors and CSS styling.
405
  $output = '';
406
  $output .= '<div' . drupal_attributes($attributes) . '>';
407
  $output .= drupal_render_children($element);
408
  $output .= '</div>';
409
  return $output;
410
}
411

  
412

  
338 413
/**
339 414
 * Implements _webform_submit_component().
340 415
 */
341 416
function _webform_submit_file($component, $value) {
342
  if (is_array($value)) {
343
    return !empty($value['fid']) ? $value['fid'] : '';
344
  }
345
  else {
346
    return !empty($value) ? $value : '';
417
  $fid = is_array($value)
418
            ? (!empty($value['fid']) ? $value['fid'] : '')
419
            : (!empty($value) ? $value : '');
420
  // Extend access to this file, even if the submission has not been saved yet. This may happen when
421
  // previewing a private file which was selected but not explicitly uploaded, and then previewed.
422
  if ($fid) {
423
    $_SESSION['webform_files'][$fid] = $fid;
347 424
  }
425
  return $fid;
348 426
}
349 427

  
350 428
/**
......
369 447
/**
370 448
 * Implements _webform_display_component().
371 449
 */
372
function _webform_display_file($component, $value, $format = 'html') {
450
function _webform_display_file($component, $value, $format = 'html', $submission = array()) {
373 451
  $fid = isset($value[0]) ? $value[0] : NULL;
374 452
  return array(
375 453
    '#title' => $component['name'],
454
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
376 455
    '#value' => $fid ? webform_get_file($fid) : NULL,
377 456
    '#weight' => $component['weight'],
378 457
    '#theme' => 'webform_display_file',
......
417 496
/**
418 497
 * Implements _webform_analysis_component().
419 498
 */
420
function _webform_analysis_file($component, $sids = array()) {
499
function _webform_analysis_file($component, $sids = array(), $single = FALSE, $join = NULL) {
421 500
  $query = db_select('webform_submitted_data', 'wsd', array('fetch' => PDO::FETCH_ASSOC))
422 501
    ->fields('wsd', array('no', 'data'))
423
    ->condition('nid', $component['nid'])
424
    ->condition('cid', $component['cid']);
502
    ->condition('wsd.nid', $component['nid'])
503
    ->condition('wsd.cid', $component['cid']);
425 504

  
426 505
  if (count($sids)) {
427
    $query->condition('sid', $sids, 'IN');
506
    $query->condition('wsd.sid', $sids, 'IN');
507
  }
508

  
509
  if ($join) {
510
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
428 511
  }
429 512

  
430 513
  $nonblanks = 0;
......
443 526

  
444 527
  $rows[0] = array(t('Left Blank'), ($submissions - $nonblanks));
445 528
  $rows[1] = array(t('User uploaded file'), $nonblanks);
446
  $rows[2] = array(t('Average uploaded file size'), ($sizetotal != 0 ? (int) (($sizetotal/$nonblanks)/1024) . ' KB' : '0'));
447
  return $rows;
529
  $other[0] = array(t('Average uploaded file size'), ($sizetotal != 0 ? (int) (($sizetotal/$nonblanks)/1024) . ' KB' : '0'));
530
  return array(
531
    'table_rows' => $rows,
532
    'other_data' => $other,
533
  );
448 534
}
449 535

  
450 536
/**
......
467 553
  $header = array();
468 554
  // Two columns in header.
469 555
  $header[0] = array('', '');
470
  $header[1] = array($component['name'], '');
556
  $header[1] = array($export_options['header_keys'] ? $component['form_key'] : $component['name'], '');
471 557
  $header[2] = array(t('Name'), t('Filesize (KB)'));
472 558
  return $header;
473 559
}
......
530 616
  }
531 617
}
532 618

  
619
/**
620
 * Rename any files which are eligible for renaming, if this submission is being
621
 * submitted for the first time.
622
 */
623
function webform_file_rename($node, $submission) {
624
  if (isset($submission->file_usage)) {
625
    foreach ($submission->file_usage['renameable'] as $cid => $fids) {
626
      foreach ($fids as $fid) {
627
        webform_file_process_rename($node, $submission, $node->webform['components'][$cid], $fid);
628
      }
629
    }
630
  }
631
}
632

  
633

  
634
/**
635
 * Renames the uploaded file name using tokens.
636
 *
637
 * @param $node
638
 *   The webform node object.
639
 * @param $submission
640
 *   The webform submission object.
641
 * @param $component
642
 *   Component settings array for which fid is going to be processed.
643
 * @param $fid
644
 *   A file id to be processed.
645
 */
646
function webform_file_process_rename($node, $submission, $component, $fid) {
647
  $file = webform_get_file($fid);
648

  
649
  if ($file) {
650
    // Get the destination uri.
651
    $destination_dir = $component['extra']['scheme'] . '://webform/' . drupal_strtolower(webform_replace_tokens($component['extra']['directory'], $node));
652
    $destination_dir = file_stream_wrapper_uri_normalize($destination_dir);
653

  
654
    // Get the file extension.
655
    $info = pathinfo($file->uri);
656
    $extension = $info['extension'];
657

  
658
    // Prepare new file name without extension.
659
    $new_file_name = webform_replace_tokens($component['extra']['rename'], $node, $submission, NULL, TRUE);
660
    $new_file_name = trim($new_file_name);
661
    $new_file_name = _webform_transliterate($new_file_name);
662
    $new_file_name = str_replace('/', '_', $new_file_name);
663
    $new_file_name = preg_replace('/[^a-zA-Z0-9_\- ]/', '', $new_file_name);
664
    if (strlen($new_file_name)) {
665
      // Prepare the new uri with new filename.
666
      $destination = "$destination_dir/$new_file_name.$extension";
667

  
668
      // Compare the uri and Rename the file name.
669
      if ($file->uri != $destination) {
670
        file_move($file, $destination, FILE_EXISTS_RENAME);
671
      }
672
    }
673
  }
674
}
drupal7/sites/all/modules/webform/components/grid.inc
15 15
  return array(
16 16
    'name' => '',
17 17
    'form_key' => NULL,
18
    'mandatory' => 0,
18
    'required' => 0,
19 19
    'pid' => 0,
20 20
    'weight' => 0,
21
    'value' => '',
21 22
    'extra' => array(
22 23
      'options' => '',
23 24
      'questions' => '',
24 25
      'optrand' => 0,
25 26
      'qrand' => 0,
27
      'unique' => 0,
26 28
      'title_display' => 0,
27 29
      'custom_option_keys' => 0,
28 30
      'custom_question_keys' => 0,
31
      'sticky' => TRUE,
29 32
      'description' => '',
30 33
      'private' => FALSE,
34
      'analysis' => TRUE,
31 35
    ),
32 36
  );
33 37
}
......
67 71
    $form['options']['options'] = array(
68 72
      '#type' => 'options',
69 73
      '#options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
70
      '#optgroups' => FALSE,
71
      '#default_value' => FALSE,
72
      '#default_value_allowed' => FALSE,
74
      '#default_value' => $component['value'],
75
      '#default_value_allowed' => TRUE,
73 76
      '#optgroups' => FALSE,
74 77
      '#key_type' => 'mixed',
75 78
      '#key_type_toggle' => t('Customize option keys (Advanced)'),
76 79
      '#key_type_toggled' => $component['extra']['custom_option_keys'],
80
      '#default_value_pattern' => '^%.+\[.+\]$',
77 81
    );
78 82

  
79 83
    $form['questions'] = array(
......
90 94
      '#optgroups' => FALSE,
91 95
      '#default_value' => FALSE,
92 96
      '#default_value_allowed' => FALSE,
93
      '#optgroups' => FALSE,
94 97
      '#key_type' => 'mixed',
95 98
      '#key_type_toggle' => t('Customize question keys (Advanced)'),
96 99
      '#key_type_toggled' => $component['extra']['custom_question_keys'],
......
101 104
      '#type' => 'textarea',
102 105
      '#title' => t('Options'),
103 106
      '#default_value' => $component['extra']['options'],
104
      '#description' => t('Options to select across the top. One option per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . theme('webform_token_help'),
107
      '#description' => t('Options to select across the top. One option per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help'),
105 108
      '#cols' => 60,
106 109
      '#rows' => 5,
107 110
      '#weight' => -3,
......
113 116
      '#type' => 'textarea',
114 117
      '#title' => t('Questions'),
115 118
      '#default_value' => $component['extra']['questions'],
116
      '#description' => t('Questions list down the side of the grid. One question per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>. Use of only alphanumeric characters and underscores is recommended in keys.') . theme('webform_token_help'),
119
      '#description' => t('Questions list down the side of the grid. One question per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable question"</strong>. For a heading column on the right, append "|" and the right-side heading. Use of only alphanumeric characters and underscores is recommended in keys.') . ' ' . theme('webform_token_help'),
117 120
      '#cols' => 60,
118 121
      '#rows' => 5,
119 122
      '#weight' => -2,
......
121 124
      '#wysiwyg' => FALSE,
122 125
      '#element_validate' => array('_webform_edit_validate_select'),
123 126
    );
127
    $form['value'] = array(
128
      '#type' => 'textfield',
129
      '#title' => t('Default value'),
130
      '#default_value' => $component['value'],
131
      '#description' => t('The default option of the grid identified by its key.') . ' ' . theme('webform_token_help'),
132
      '#size' => 60,
133
      '#maxlength' => 1024,
134
      '#weight' => 1,
135
    );
124 136
  }
125 137

  
126 138
  $form['display']['optrand'] = array(
......
137 149
    '#description' => t('Randomize the order of the questions on the side when they are displayed in the form.'),
138 150
    '#parents' => array('extra', 'qrand')
139 151
  );
152
  $form['display']['sticky'] = array(
153
    '#type' => 'checkbox',
154
    '#title' => t('Sticky table header'),
155
    '#default_value' => $component['extra']['sticky'],
156
    '#description' => t('Use a sticky (non-scrolling) table header.'),
157
    '#parents' => array('extra', 'sticky')
158
  );
159

  
160
  $form['validation']['unique'] = array(
161
    '#type' => 'checkbox',
162
    '#title' => t('Unique'),
163
    '#return_value' => 1,
164
    '#description' => t('Check that all entered values for this field are unique. The same value is not allowed to be used twice.'),
165
    '#weight' => 1,
166
    '#default_value' => $component['extra']['unique'],
167
    '#parents' => array('extra', 'unique'),
168
  );
169

  
140 170
  return $form;
141 171
}
142 172

  
143 173
/**
144 174
 * Implements _webform_render_component().
145 175
 */
146
function _webform_render_grid($component, $value = NULL, $filter = TRUE) {
176
function _webform_render_grid($component, $value = NULL, $filter = TRUE, $submission = NULL) {
147 177
  $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
148 178

  
179
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
180
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
181
  if ($filter) {
182
    $questions = _webform_select_replace_tokens($questions, $node);
183
    $options = _webform_select_replace_tokens($options, $node);
184
  }
185

  
149 186
  $element = array(
150 187
    '#type' => 'webform_grid',
151
    '#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
188
    '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
152 189
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
153
    '#required' => $component['mandatory'],
190
    '#required' => $component['required'],
154 191
    '#weight' => $component['weight'],
155
    '#description' => $filter ? _webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
156
    '#grid_questions' => _webform_select_options_from_text($component['extra']['questions'], TRUE),
157
    '#grid_options' => _webform_select_options_from_text($component['extra']['options'], TRUE),
192
    '#description' => $filter ? webform_filter_descriptions($component['extra']['description'], $node) : $component['extra']['description'],
193
    '#grid_questions' => $questions,
194
    '#grid_options' => $options,
195
    '#default_value' => isset($value) || !strlen($component['value']) ? $value : array_fill_keys(array_keys($questions), $component['value']),
196
    '#grid_default' => $component['value'],
158 197
    '#optrand' => $component['extra']['optrand'],
159 198
    '#qrand' => $component['extra']['qrand'],
199
    '#sticky' => $component['extra']['sticky'],
160 200
    '#theme' => 'webform_grid',
161 201
    '#theme_wrappers' => array('webform_element'),
162 202
    '#process' => array('webform_expand_grid'),
163 203
    '#translatable' => array('title', 'description', 'grid_options', 'grid_questions'),
164 204
  );
165 205

  
166
  if ($value) {
167
    $element['#default_value'] = $value;
206
  // Enforce uniqueness.
207
  if ($component['extra']['unique']) {
208
    $element['#element_validate'][] = '_webform_edit_grid_unique_validate';
168 209
  }
169 210

  
170 211
  return $element;
......
199 240
        '#webform_validated' => FALSE,
200 241
        '#translatable' => array('title'),
201 242
      );
243

  
244
      // Add HTML5 required attribute, if needed.
245
      if ($element['#required']) {
246
        $element[$key]['#attributes']['required'] = 'required';
247
      }
202 248
    }
203 249
  }
204 250

  
......
218 264
/**
219 265
 * Implements _webform_display_component().
220 266
 */
221
function _webform_display_grid($component, $value, $format = 'html') {
267
function _webform_display_grid($component, $value, $format = 'html', $submission = array()) {
268
  $node = node_load($component['nid']);
222 269
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
270
  $questions = _webform_select_replace_tokens($questions, $node);
223 271
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
272
  $options = _webform_select_replace_tokens($options, $node);
224 273

  
225 274
  $element = array(
226 275
    '#title' => $component['name'],
276
    '#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : 'before',
227 277
    '#weight' => $component['weight'],
228 278
    '#format' => $format,
229 279
    '#grid_questions' => $questions,
230 280
    '#grid_options' => $options,
281
    '#sticky' => $component['extra']['sticky'],
231 282
    '#theme' => 'webform_display_grid',
232 283
    '#theme_wrappers' => $format == 'html' ? array('webform_element') : array('webform_element_text'),
233 284
    '#sorted' => TRUE,
......
257 308
  $format = $element['#format'];
258 309

  
259 310
  if ($format == 'html') {
311
    $right_titles = _webform_grid_right_titles($element);
260 312
    $rows = array();
261
    $header = array(array('data' => '', 'class' => array('webform-grid-question')));
313
    $title = array('data' => '', 'class' => array('webform-grid-question'));
314
    $header = array($title);
262 315
    foreach ($element['#grid_options'] as $option) {
263
      $header[] = array('data' => _webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
316
      $header[] = array('data' => webform_filter_xss($option), 'class' => array('checkbox', 'webform-grid-option'));
317
    }
318
    if ($right_titles) {
319
      $header[] = $title;
264 320
    }
265 321
    foreach ($element['#grid_questions'] as $question_key => $question) {
266 322
      $row = array();
267
      $row[] = array('data' => _webform_filter_xss($question), 'class' => array('webform-grid-question'));
323
      $questions = explode('|', $question, 2);
324
      $row[] = array('data' => webform_filter_xss($questions[0]), 'class' => array('webform-grid-question'));
268 325
      foreach ($element['#grid_options'] as $option_value => $option_label) {
269 326
        if (strcmp($element[$question_key]['#value'], $option_value) == 0) {
270 327
          $row[] = array('data' => '<strong>X</strong>', 'class' => array('checkbox', 'webform-grid-option'));
......
273 330
          $row[] = array('data' => '&nbsp;', 'class' => array('checkbox', 'webform-grid-option'));
274 331
        }
275 332
      }
333
      if ($right_titles) {
334
        $row[] = array('data' => isset($questions[1]) ? webform_filter_xss($questions[1]) : '', 'class' => array('webform-grid-question'));
335
      }
276 336
      $rows[] = $row;
277 337
    }
278 338

  
279 339
    $option_count = count($header) - 1;
280
    $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
340
    $output = theme('table', array('header' => $header, 'rows' => $rows, 'sticky' => $element['#sticky'], 'attributes' => array('class' => array('webform-grid', 'webform-grid-' . $option_count))));
281 341
  }
282 342
  else {
283 343
    $items = array();
284 344
    foreach (element_children($element) as $key) {
285
      $items[] = ' - ' . $element[$key]['#title'] . ': ' . (isset($element['#grid_options'][$element[$key]['#value']]) ? $element['#grid_options'][$element[$key]['#value']] : '');
345
      $items[] = ' - ' . _webform_grid_question_header($element[$key]['#title']) . ': ' .
346
                 (isset($element['#grid_options'][$element[$key]['#value']]) ? $element['#grid_options'][$element[$key]['#value']] : '');
286 347
    }
287 348
    $output = implode("\n", $items);
288 349
  }
......
293 354
/**
294 355
 * Implements _webform_analysis_component().
295 356
 */
296
function _webform_analysis_grid($component, $sids = array()) {
357
function _webform_analysis_grid($component, $sids = array(), $single = FALSE, $join = NULL) {
297 358
  // Generate the list of options and questions.
298
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
359
  $node = node_load($component['nid']);
299 360
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
361
  $questions = _webform_select_replace_tokens($questions, $node);
362
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
363
  $options = _webform_select_replace_tokens($options, $node);
300 364

  
301 365
  // Generate a lookup table of results.
302 366
  $query = db_select('webform_submitted_data', 'wsd')
303 367
    ->fields('wsd', array('no', 'data'))
304
    ->condition('nid', $component['nid'])
305
    ->condition('cid', $component['cid'])
306
    ->condition('data', '', '<>')
307
    ->groupBy('no')
308
    ->groupBy('data');
309
  $query->addExpression('COUNT(sid)', 'datacount');
368
    ->condition('wsd.nid', $component['nid'])
369
    ->condition('wsd.cid', $component['cid'])
370
    ->condition('wsd.data', '', '<>')
371
    ->groupBy('wsd.no')
372
    ->groupBy('wsd.data');
373
  $query->addExpression('COUNT(wsd.sid)', 'datacount');
310 374

  
311 375
  if (count($sids)) {
312
    $query->condition('sid', $sids, 'IN');
376
    $query->condition('wsd.sid', $sids, 'IN');
377
  }
378

  
379
  if ($join) {
380
    $query->innerJoin($join, 'ws2_', 'wsd.sid = ws2_.sid');
313 381
  }
314 382

  
315 383
  $result = $query->execute();
......
324 392

  
325 393
  // Add options as a header row.
326 394
  foreach ($options as $option) {
327
    $header[] = _webform_filter_xss($option);
395
    $header[] = webform_filter_xss($option);
328 396
  }
329 397

  
330 398
  // Add questions as each row.
331 399
  foreach ($questions as $qkey => $question) {
332
    $row = array(_webform_filter_xss($question));
400
    $row = array(webform_filter_xss($question));
333 401
    foreach ($options as $okey => $option) {
334 402
      $row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
335 403
    }
336 404
    $rows[] = $row;
337 405
  }
338
  $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('class' => array('webform-grid'))));
339

  
340 406

  
341
  return array(array(array('data' => $output, 'colspan' => 2)));
407
  return array(
408
    'table_header' => $header,
409
    'table_rows' => $rows,
410
  );
342 411
}
343 412

  
344 413
/**
345 414
 * Implements _webform_table_component().
346 415
 */
347 416
function _webform_table_grid($component, $value) {
417
  $node = node_load($component['nid']);
348 418
  $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
419
  $questions = _webform_select_replace_tokens($questions, $node);
349 420
  $options = _webform_select_options_from_text($component['extra']['options'], TRUE);
421
  $options = _webform_select_replace_tokens($options, $node);
... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.

Formats disponibles : Unified diff