From ea33272a0fb45456aacdc1cb8819c21edd4fdd63 Mon Sep 17 00:00:00 2001
From: Dan Chadwick <dan899@gmail.com>
Date: Fri, 24 Apr 2015 16:11:52 -0400
Subject: [PATCH] Issue #2471765 by DanChadwick: Edit existing submissions
 with date validation relative to completion date.

---
 components/date.inc                             |    5 ++-
 components/email.inc                            |    2 +-
 components/fieldset.inc                         |    2 +-
 components/file.inc                             |    2 +-
 components/grid.inc                             |    2 +-
 components/hidden.inc                           |    2 +-
 components/markup.inc                           |    2 +-
 components/number.inc                           |    2 +-
 components/pagebreak.inc                        |    4 +-
 components/select.inc                           |    2 +-
 components/textarea.inc                         |    2 +-
 components/textfield.inc                        |    2 +-
 components/time.inc                             |    2 +-
 views/webform_handler_field_submission_data.inc |    2 +-
 webform.api.php                                 |    6 ++++-
 webform.module                                  |   24 +++++++++++++++++++---
 16 files changed, 42 insertions(+), 21 deletions(-)

diff --git a/components/date.inc b/components/date.inc
index 0909dec..eb87ca2 100644
--- a/components/date.inc
+++ b/components/date.inc
@@ -165,7 +165,7 @@ function _webform_edit_date_validate($form, &$form_state) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_date($component, $value = NULL, $filter = TRUE) {
+function _webform_render_date($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
@@ -177,6 +177,7 @@ function _webform_render_date($component, $value = NULL, $filter = TRUE) {
     '#required' => $component['required'],
     '#start_date' => trim($component['extra']['start_date']),
     '#end_date' => trim($component['extra']['end_date']),
+    '#reference_timestamp' => $submission && $submission->completed ? $submission->completed : NULL,
     '#year_textfield' => $component['extra']['year_textfield'],
     '#default_value' => $filter ? webform_replace_tokens($component['value'], $node) : $component['value'],
     '#timezone' => $component['extra']['timezone'],
@@ -245,7 +246,7 @@ function webform_expand_date($element) {
   $timezone = $element['#timezone'] != 'user' ? NULL : 'user';
   foreach (array('start', 'end') as $start_end) {
     $element_field = &$element["#{$start_end}_date"];
-    $element_field = $element_field ? webform_strtodate('Y-m-d', $element_field, $timezone) : '';
+    $element_field = $element_field ? webform_strtodate('Y-m-d', $element_field, $timezone, $element['#reference_timestamp']) : '';
     if ($element_field) {
       $parts = explode('-', $element_field);
     }
diff --git a/components/email.inc b/components/email.inc
index 366a821..07eee20 100644
--- a/components/email.inc
+++ b/components/email.inc
@@ -140,7 +140,7 @@ function _webform_edit_email_validate($element, &$form_state) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_email($component, $value = NULL, $filter = TRUE) {
+function _webform_render_email($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   global $user;
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
diff --git a/components/fieldset.inc b/components/fieldset.inc
index 56e4ee2..8b43ae3 100644
--- a/components/fieldset.inc
+++ b/components/fieldset.inc
@@ -51,7 +51,7 @@ function _webform_edit_fieldset($component) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_fieldset($component, $value = NULL, $filter = TRUE) {
+function _webform_render_fieldset($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/components/file.inc b/components/file.inc
index 364a136..6ec752c 100644
--- a/components/file.inc
+++ b/components/file.inc
@@ -330,7 +330,7 @@ function theme_webform_edit_file_extensions($variables) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_file($component, $value = NULL, $filter = TRUE) {
+function _webform_render_file($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   // Cap the upload size according to the PHP limit.
diff --git a/components/grid.inc b/components/grid.inc
index 2ef65ff..da567c6 100644
--- a/components/grid.inc
+++ b/components/grid.inc
@@ -173,7 +173,7 @@ function _webform_edit_grid($component) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_grid($component, $value = NULL, $filter = TRUE) {
+function _webform_render_grid($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $questions = _webform_select_options_from_text($component['extra']['questions'], TRUE);
diff --git a/components/hidden.inc b/components/hidden.inc
index 4fef018..0740018 100644
--- a/components/hidden.inc
+++ b/components/hidden.inc
@@ -68,7 +68,7 @@ function _webform_edit_hidden($component) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_hidden($component, $value = NULL, $filter = TRUE) {
+function _webform_render_hidden($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $default_value = $filter ? webform_replace_tokens($component['value'], $node) : $component['value'];
diff --git a/components/markup.inc b/components/markup.inc
index 6c73db2..6ceefb2 100644
--- a/components/markup.inc
+++ b/components/markup.inc
@@ -79,7 +79,7 @@ function _webform_edit_markup_validate($form, &$form_state) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_markup($component, $value = NULL, $filter = TRUE) {
+function _webform_render_markup($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/components/number.inc b/components/number.inc
index a8c7d0b..f0ba3b6 100644
--- a/components/number.inc
+++ b/components/number.inc
@@ -272,7 +272,7 @@ function theme_webform_number($variables) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_number($component, $value = NULL, $filter = TRUE) {
+function _webform_render_number($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/components/pagebreak.inc b/components/pagebreak.inc
index 81f5e02..a02367d 100644
--- a/components/pagebreak.inc
+++ b/components/pagebreak.inc
@@ -66,7 +66,7 @@ function _webform_edit_pagebreak($component) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_pagebreak($component, $value = NULL, $filter = TRUE) {
+function _webform_render_pagebreak($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $element = array(
     '#type' => 'hidden',
     '#value' => $component['name'],
@@ -76,7 +76,7 @@ function _webform_render_pagebreak($component, $value = NULL, $filter = TRUE) {
 }
 
 /**
- * Implements _webform_render_component().
+ * Implements _webform_display_component().
  */
 function _webform_display_pagebreak($component, $value = NULL, $format = 'html') {
   $element = array(
diff --git a/components/select.inc b/components/select.inc
index aa8d68b..80e1bbd 100644
--- a/components/select.inc
+++ b/components/select.inc
@@ -314,7 +314,7 @@ function _webform_edit_validate_set_aslist($options, &$form_state) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_select($component, $value = NULL, $filter = TRUE) {
+function _webform_render_select($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/components/textarea.inc b/components/textarea.inc
index 545b597..b4d9948 100644
--- a/components/textarea.inc
+++ b/components/textarea.inc
@@ -106,7 +106,7 @@ function _webform_edit_textarea($component) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_textarea($component, $value = NULL, $filter = TRUE) {
+function _webform_render_textarea($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/components/textfield.inc b/components/textfield.inc
index 6d6f12d..9baee8a 100644
--- a/components/textfield.inc
+++ b/components/textfield.inc
@@ -131,7 +131,7 @@ function _webform_edit_textfield($component) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_textfield($component, $value = NULL, $filter = TRUE) {
+function _webform_render_textfield($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/components/time.inc b/components/time.inc
index 55679ea..f269494 100644
--- a/components/time.inc
+++ b/components/time.inc
@@ -137,7 +137,7 @@ function _webform_edit_time_validate($form, &$form_state) {
 /**
  * Implements _webform_render_component().
  */
-function _webform_render_time($component, $value = NULL, $filter = TRUE) {
+function _webform_render_time($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $node = isset($component['nid']) ? node_load($component['nid']) : NULL;
 
   $element = array(
diff --git a/views/webform_handler_field_submission_data.inc b/views/webform_handler_field_submission_data.inc
index 872aeb2..99a3054 100644
--- a/views/webform_handler_field_submission_data.inc
+++ b/views/webform_handler_field_submission_data.inc
@@ -202,7 +202,7 @@ class webform_handler_field_submission_data extends views_handler_field {
       }
 
       if ($this->options['format'] == 'html') {
-        $render = array();
+        $render = array('#submission' => $submission);
         _webform_client_form_add_component($webform, $component, NULL, $render, $render, $submission->data, 'html');
         $render = $render[$component['form_key']];
         // Remove display label.
diff --git a/webform.api.php b/webform.api.php
index f97b738..88e0a63 100644
--- a/webform.api.php
+++ b/webform.api.php
@@ -890,10 +890,14 @@ function _webform_edit_component($component) {
  *   Whether or not to filter the contents of descriptions and values when
  *   rendering the component. Values need to be unfiltered to be editable by
  *   Form Builder.
+ * @param $submission
+ *   The submission from which this component is being rendered. Usually not
+ *   needed. Used by _webform_render_date() to validate using the submission's
+ *   completion date.
  *
  * @see _webform_client_form_add_component()
  */
-function _webform_render_component($component, $value = NULL, $filter = TRUE) {
+function _webform_render_component($component, $value = NULL, $filter = TRUE, $submission = NULL) {
   $form_item = array(
     '#type' => 'textfield',
     '#title' => $filter ? webform_filter_xss($component['name']) : $component['name'],
diff --git a/webform.module b/webform.module
index 92c4bbd..c6f925e 100644
--- a/webform.module
+++ b/webform.module
@@ -2717,7 +2717,7 @@ function _webform_client_form_add_component($node, $component, $component_value,
   // version of the form (such as for Form Builder).
   elseif ($component['page_num'] == $page_num || $filter == FALSE) {
     // Add this user-defined field to the form (with all the values that are always available).
-    if ($element = webform_component_invoke($component['type'], 'render', $component, $component_value, $filter)) {
+    if ($element = webform_component_invoke($component['type'], 'render', $component, $component_value, $filter, $form['#submission'])) {
       // Set access based on the private property.
       $element += array('#access' => TRUE);
       $element['#access'] = $element['#access'] && $component_access;
@@ -4829,7 +4829,7 @@ function webform_date_format($type = NULL, $exclude = array()) {
 /**
  * Return a date in the desired format taking into consideration user timezones.
  */
-function webform_strtodate($format, $string, $timezone_name = NULL) {
+function webform_strtodate($format, $string, $timezone_name = NULL, $reference_timestamp = NULL) {
   global $user;
 
   // Adjust the time based on the user or site timezone.
@@ -4846,7 +4846,23 @@ function webform_strtodate($format, $string, $timezone_name = NULL) {
     // only supported for DateTime in PHP 5.3 and higher.
     try {
       @$timezone = new DateTimeZone($timezone_name);
-      @$datetime = new DateTime($string, $timezone);
+      if (isset($reference_timestamp)) {
+        // A reference for relative dates has been provided.
+        // 1) Convert the reference timestamp (in UTC) to a DateTime.
+        // 2) Set to time zone to the user or system timezone, recreating
+        //    the reference time in the appropriate time zone.
+        // 3) Set the time to midnight because when a non-referenced relative
+        //    date is created without a time, it is created at midnight (0:00).
+        // 4) Adjust to the specified relative (or absolute) time.
+
+        @$datetime = new DateTime('@' . $reference_timestamp);
+        @$datetime->setTimezone($timezone)
+                  ->setTime(0, 0, 0)
+                  ->modify($string);
+      }
+      else {
+        @$datetime = new DateTime($string, $timezone);
+      }
       return @$datetime->format($format);
     }
     catch (Exception $e) {
@@ -4854,7 +4870,7 @@ function webform_strtodate($format, $string, $timezone_name = NULL) {
     }
   }
   else {
-    return date($format, strtotime($string));
+    return date($format, isset($reference_timestamp) ? strtotime($string, $reference_timestamp) : strtotime($string));
   }
 }
 
-- 
1.7.8.msysgit.0

