From bea17a2bd1c0fa051f79d60e07620c5052f9bdb9 Mon Sep 17 00:00:00 2001
From: agoradesign <agoradesign@1183886.no-reply.drupal.org>
Date: Tue, 28 Apr 2015 10:17:46 -0400
Subject: [PATCH] Issue #1783628 by agoradesign, DanChadwick: Add html5
 required attribute to webform components.

---
 components/date.inc      |    7 +++++++
 components/email.inc     |    4 ++++
 components/grid.inc      |    5 +++++
 components/number.inc    |    4 ++++
 components/select.inc    |    5 +++++
 components/textarea.inc  |    4 ++++
 components/textfield.inc |    4 ++++
 components/time.inc      |   10 ++++++++++
 js/webform.js            |    4 ++++
 webform.module           |    9 +++++++++
 10 files changed, 56 insertions(+), 0 deletions(-)

diff --git a/components/date.inc b/components/date.inc
index eb87ca2..f84c2f2 100644
--- a/components/date.inc
+++ b/components/date.inc
@@ -364,6 +364,13 @@ function theme_webform_date($variables) {
     $element['day']['#attributes']['class'][] = 'error';
   }
 
+  // Add HTML5 required attribute, if needed.
+  if ($element['#required']) {
+    $element['year']['#attributes']['required'] = 'required';
+    $element['month']['#attributes']['required'] = 'required';
+    $element['day']['#attributes']['required'] = 'required';
+  }
+
   $class = array('webform-container-inline');
 
   // Add the JavaScript calendar if available (provided by Date module package).
diff --git a/components/email.inc b/components/email.inc
index 07eee20..d407792 100644
--- a/components/email.inc
+++ b/components/email.inc
@@ -158,6 +158,10 @@ function _webform_render_email($component, $value = NULL, $filter = TRUE, $submi
     '#translatable' => array('title', 'description'),
   );
 
+  if ($component['required']) {
+    $element['#attributes']['required'] = 'required';
+  }
+
   // Add an e-mail class for identifying the difference from normal textfields.
   $element['#attributes']['class'][] = 'email';
 
diff --git a/components/grid.inc b/components/grid.inc
index da567c6..3e5bab8 100644
--- a/components/grid.inc
+++ b/components/grid.inc
@@ -240,6 +240,11 @@ function webform_expand_grid($element) {
         '#webform_validated' => FALSE,
         '#translatable' => array('title'),
       );
+
+      // Add HTML5 required attribute, if needed.
+      if ($element['#required']) {
+        $element[$key]['#attributes']['required'] = 'required';
+      }
     }
   }
 
diff --git a/components/number.inc b/components/number.inc
index f0ba3b6..9fe0bb5 100644
--- a/components/number.inc
+++ b/components/number.inc
@@ -297,6 +297,10 @@ function _webform_render_number($component, $value = NULL, $filter = TRUE, $subm
     '#translatable' => array('title', 'description', 'field_prefix', 'field_suffix'),
   );
 
+  if ($component['required']) {
+    $element['#attributes']['required'] = 'required';
+  }
+
   // Set the decimal count to zero for integers.
   if ($element['#integer'] && $element['#decimals'] === '') {
     $element['#decimals'] = 0;
diff --git a/components/select.inc b/components/select.inc
index 80e1bbd..af6c69e 100644
--- a/components/select.inc
+++ b/components/select.inc
@@ -328,6 +328,11 @@ function _webform_render_select($component, $value = NULL, $filter = TRUE, $subm
     '#translatable' => array('title', 'description', 'options'),
   );
 
+  // Add HTML5 required attribute, if needed and possible (not working on multiple checkboxes).
+  if ($component['required'] && ($component['extra']['aslist'] || !$component['extra']['multiple'])) {
+    $element['#attributes']['required'] = 'required';
+  }
+
   // Convert the user-entered options list into an array.
   $default_value = $filter ? webform_replace_tokens($component['value'], $node) : $component['value'];
   $options = _webform_select_options($component, !$component['extra']['aslist'], $filter);
diff --git a/components/textarea.inc b/components/textarea.inc
index b4d9948..41d0f57 100644
--- a/components/textarea.inc
+++ b/components/textarea.inc
@@ -125,6 +125,10 @@ function _webform_render_textarea($component, $value = NULL, $filter = TRUE, $su
     '#translatable' => array('title', 'description'),
   );
 
+  if ($component['required']) {
+    $element['#attributes']['required'] = 'required';
+  }
+
   if ($component['extra']['placeholder']) {
     $element['#attributes']['placeholder'] = $component['extra']['placeholder'];
   }
diff --git a/components/textfield.inc b/components/textfield.inc
index 9baee8a..7ada5fc 100644
--- a/components/textfield.inc
+++ b/components/textfield.inc
@@ -149,6 +149,10 @@ function _webform_render_textfield($component, $value = NULL, $filter = TRUE, $s
     '#translatable' => array('title', 'description', 'field_prefix', 'field_suffix'),
   );
 
+  if ($component['required']) {
+    $element['#attributes']['required'] = 'required';
+  }
+
   if ($component['extra']['placeholder']) {
     $element['#attributes']['placeholder'] = $component['extra']['placeholder'];
   }
diff --git a/components/time.inc b/components/time.inc
index 9f9a0f7..786dae5 100644
--- a/components/time.inc
+++ b/components/time.inc
@@ -287,6 +287,16 @@ function theme_webform_time($variables) {
     $element['minute']['#attributes']['class'][] = 'error';
   }
 
+  // Add HTML5 required attribute, if needed.
+  if ($element['#required']) {
+    $element['hour']['#attributes']['required'] = 'required';
+    $element['minute']['#attributes']['required'] = 'required';
+    if (!empty($element['ampm'])) {
+      $element['ampm']['am']['#attributes']['required'] = 'required';
+      $element['ampm']['pm']['#attributes']['required'] = 'required';
+    }
+  }
+
   $output = '<div class="webform-container-inline">' . drupal_render($element['hour']) . drupal_render($element['minute']) . drupal_render($element['ampm']) . '</div>';
 
   return $output;
diff --git a/js/webform.js b/js/webform.js
index edbab24..887c821 100644
--- a/js/webform.js
+++ b/js/webform.js
@@ -178,8 +178,12 @@ Drupal.webform.doConditions = function($form, settings) {
         case 'require':
           var $requiredSpan = $target.find('.form-required, .form-optional').first();
           if (actionResult != $requiredSpan.hasClass('form-required')) {
+            var $targetInputElements = $target.find("input:text,textarea,input[type='email'],select,input:radio,input:file");
             // Rather than hide the required tag, remove it so that other jQuery can respond via Drupal behaviors.
             Drupal.detachBehaviors($requiredSpan);
+            $targetInputElements
+              .webformProp('required', actionResult)
+              .toggleClass('required', actionResult);
             if (actionResult) {
               $requiredSpan.replaceWith('<span class="form-required" title="' + Drupal.t('This field is required.') + '">*</span>');
             }
diff --git a/webform.module b/webform.module
index 640c999..5936c26 100644
--- a/webform.module
+++ b/webform.module
@@ -2936,6 +2936,15 @@ function _webform_client_form_validate(&$elements, &$form_state, $form_id = NULL
     $required = $sorter->componentRequired($cid, $page_num);
     if (isset($required)) {
       $elements['#required'] = $required;
+
+      // Some components, e.g. grids, have nested sub-elements. Extend required
+      // to any sub-components.
+      foreach (element_children($elements) as $key) {
+        if (isset($elements[$key]) && $elements[$key] && !isset($elements[$key]['#webform_component'])) {
+          // Child is *not* a component.
+          $elements[$key]['#required'] = $required;
+        }
+      }
     }
   }
 
-- 
1.7.8.msysgit.0

