From 05305fe22df0de52b4af9964bdffb6d94819ef86 Sat, 11 Jun 2011 09:56:43 +0200
From: Bram Goffings <bramgoffings@gmail.com>
Date: Sat, 11 Jun 2011 09:56:34 +0200
Subject: [PATCH] Added html5 range element



diff --git a/includes/common.inc b/includes/common.inc
index 4ec37dc..fafdde9 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -6558,6 +6558,9 @@
     'textfield' => array(
       'render element' => 'element',
     ),
+    'range' => array(
+      'render element' => 'element',
+    ),
     'form' => array(
       'render element' => 'element',
     ),
diff --git a/includes/form.inc b/includes/form.inc
index 8f2ee26..ee8c95f 100644
--- a/includes/form.inc
+++ b/includes/form.inc
@@ -3655,6 +3655,105 @@
 }
 
 /**
+ * Returns HTML for a range form element.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties of the element.
+ *     Properties used: #title, #value, #description, #size, #min, #max,
+ *     #required, #attributes, #step.
+ *
+ * @ingroup themeable
+ */
+function theme_range($variables) {
+  $element = $variables['element'];
+  $element['#attributes']['type'] = 'range';
+  element_set_attributes($element, array('id', 'name', 'value', 'step', 'min', 'max'));
+  _form_set_class($element, array('form-text', 'form-range'));
+
+  $output = '<input' . drupal_attributes($element['#attributes']) . ' />';
+
+  return $output;
+}
+
+/**
+ * Form element validation handler for #type 'number'.
+ *
+ * Note that #required is validated by _form_validate() already.
+ */
+function form_validate_number(&$element, &$form_state) {
+  $value = $element['#value'];
+  if(!$value)
+    return;
+
+  // Validate the #number property.
+  if (!is_numeric($value)) {
+    form_error($element, t('%name must be a number.', array('%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'])));
+  }
+
+  // Validate the #min property.
+  if(isset($element['#min'] && $value < $element['#min']) {
+      form_error($element, t('%name must be below or equal to %min.', array('%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%min' => $element['#min'])));
+  }
+
+  // Validate the #max property.
+  if(isset($element['#max'] && $value < $element['#max']) {
+      form_error($element, t('%name must be below or equal to %max.', array('%name' => empty($elements['#title']) ? $elements['#parents'][0] : $elements['#title'], '%max' => $element['#max'])));
+  }
+
+  // Validate the #step property.
+  if (isset($element['#step'])) {
+    if (isset($element['#min']) && _element_validate_step_mismatch($value, $element['#step'], $element['#min'])
+       // Message that this is not a valid number
+    }
+    elseif (_element_validate_step_mismatch($value, $element['#step']) {
+       // Message that this is not a valid number
+    }
+  }
+}
+
+/**
+ * Helper function for _element_validate_step().
+ *
+ * Checks if value is a valid step.
+ * This is based on the number/range verification methods of webkit.
+ *
+ * @see http://codesearch.google.com/#OAMlx_jo-ck/src/third_party/WebKit/Source/WebCore/html\numberInputType.cpp&type=cs&l=129
+ *
+ * @param $value
+ *   The value that needs to be checked.
+ * @param $step
+ *   The step scale factor for the widget.
+ * @param $min
+ *   The min value of the widget.
+ *
+ * @return
+ *   TRUE if value is invalid
+ *   FALSE if value is valid
+ */
+function _element_validate_step_mismatch($value, $step, $min = 0.0) {
+  $doubleValue = (double)$value;
+  $doubleValue = abs($doubleValue - $min);
+  $digits = 16; // DBL_MANT_DIG
+
+  // double's fractional part size is DBL_MANT_DIG-bit. If the current value
+  // is greater than step*2^DBL_MANT_DIG, the following computation for
+  // remainder makes no sense.
+  if ($doubleValue / pow(2.0, $digits) > $step) {
+    return false;
+  }
+  // The computation follows HTML5 4.10.7.2.10 `The step attribute' :
+  // ... that number subtracted from the step base is not an integral multiple
+  // of the allowed value step, the element is suffering from a step mismatch.
+  (double) $remainder = abs($doubleValue - $step * round($doubleValue / $step));
+  // Accepts erros in lower fractional part which IEEE 754 single-precision
+  // can't represent.
+  $computedAcceptableError = (double)($step / pow(2.0, $digits));
+
+  return $computedAcceptableError < $remainder && $remainder < ($step - $computedAcceptableError);
+}
+
+/**
  * Returns HTML for a form.
  *
  * @param $variables
diff --git a/modules/system/system.module b/modules/system/system.module
index 3ebc657..a4debc2 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -355,6 +355,15 @@
     '#theme' => 'textfield',
     '#theme_wrappers' => array('form_element'),
   );
+  $types['range'] = array(
+    '#input' => TRUE,
+    '#size' => 60,
+    '#maxlength' => 128,
+    '#process' => array('ajax_process_form'),
+    '#element_validate' => array('form_validate_number'),
+    '#theme' => 'range',
+    '#theme_wrappers' => array('form_element'),
+  );
   $types['machine_name'] = array(
     '#input' => TRUE,
     '#default_value' => NULL,
