From 0097281af1a63ba04d93e49061ce33b8ce1cff4a Mon Sep 17 00:00:00 2001
From: "Eric J. Duran" <eric.duran7@gmail.com>
Date: Sat, 21 Apr 2012 13:06:26 -0400
Subject: [PATCH] Issue #1541838 by ericduran: Added Update number element to
 match what is not in 8.x core.

---
 elements.module    |   91 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 elements.theme.inc |    2 +-
 2 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/elements.module b/elements.module
index 06259d8..73774cf 100644
--- a/elements.module
+++ b/elements.module
@@ -43,10 +43,15 @@ function elements_element_info() {
   );
   $types['numberfield'] = array(
     '#input' => TRUE,
+    '#size' => 30,
+    '#step' => 1,
+    '#maxlength' => 128,
     '#process' => array('ajax_process_form'),
+    '#element_validate' => array('form_validate_number'),
     '#theme' => 'numberfield',
     '#theme_wrappers' => array('form_element'),
   );
+  $types['number'] = $types['numberfield'];
   $types['rangefield'] = array(
     '#input' => TRUE,
     '#process' => array('ajax_process_form'),
@@ -179,3 +184,89 @@ function elements_validate_url(&$element, &$form_state) {
     form_error($element, t('The URL %url is not valid.', array('%url' => $element['#value'])));
   }
 }
+
+/**
+ * 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;
+  }
+
+  $name = empty($element['#title']) ? $element['#parents'][0] : $element['#title'];
+
+  // Ensure the input is numeric.
+  if (!is_numeric($value)) {
+    form_error($element, t('%name must be a number.', array('%name' => $name)));
+    return;
+  }
+
+  // Ensure that the input is greater than the #min property, if set.
+  if (isset($element['#min']) && $value < $element['#min']) {
+    form_error($element, t('%name must be higher or equal to %min.', array('%name' => $name, '%min' => $element['#min'])));
+  }
+
+  // Ensure that the input is less than the #max property, if set.
+  if (isset($element['#max']) && $value > $element['#max']) {
+    form_error($element, t('%name must be below or equal to %max.', array('%name' => $name, '%max' => $element['#max'])));
+  }
+
+  if (isset($element['#step']) && strtolower($element['#step']) != 'any') {
+    // Check that the input is an allowed multiple of #step (offset by #min if
+    // #min is set).
+    $offset = isset($element['#min']) ? $element['#min'] : 0.0;
+
+    if (!valid_number_step($value, $element['#step'], $offset)) {
+      form_error($element, t('%name is not a valid number.', array('%name' => $name)));
+    }
+  }
+}
+
+/**
+ * Verifies that a number is a multiple of a given step.
+ *
+ * The implementation assumes it is dealing with IEEE 754 double precision
+ * floating point numbers that are used by PHP on most systems.
+ *
+ * This is based on the number/range verification methods of webkit.
+ *
+ * @param $value
+ *   The value that needs to be checked.
+ * @param $step
+ *   The step scale factor. Must be positive.
+ * @param $offset
+ *   (optional) An offset, to which the difference must be a multiple of the
+ *   given step.
+ *
+ * @return bool
+ *   TRUE if no step mismatch has occured, or FALSE otherwise.
+ *
+ * @see http://opensource.apple.com/source/WebCore/WebCore-1298/html/NumberInputType.cpp
+ */
+function valid_number_step($value, $step, $offset = 0.0) {
+  $double_value = (double) abs($value - $offset);
+
+  // The fractional part of a double has 53 bits. The greatest number that could
+  // be represented with that is 2^53. If the given value is even bigger than
+  // $step * 2^53, then dividing by $step will result in a very small remainder.
+  // Since that remainder can't even be represented with a single precision
+  // float the following computation of the remainder makes no sense and we can
+  // safely ignore it instead.
+  if ($double_value / pow(2.0, 53) > $step) {
+    return TRUE;
+  }
+
+  // Now compute that remainder of a division by $step.
+  $remainder = (double) abs($double_value - $step * round($double_value / $step));
+
+  // $remainder is a double precision floating point number. Remainders that
+  // can't be represented with single precision floats are acceptable. The
+  // fractional part of a float has 24 bits. That means remainders smaller than
+  // $step * 2^-24 are acceptable.
+  $computed_acceptable_error = (double)($step / pow(2.0, 24));
+
+  return $computed_acceptable_error >= $remainder || $remainder >= ($step - $computed_acceptable_error);
+}
diff --git a/elements.theme.inc b/elements.theme.inc
index 7405c36..a1390c6 100644
--- a/elements.theme.inc
+++ b/elements.theme.inc
@@ -114,7 +114,7 @@ function theme_numberfield($variables) {
   $element = $variables['element'];
   $element['#attributes']['type'] = 'number';
   element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength', 'placeholder', 'min', 'max', 'step'));
-  _form_set_class($element, array('form-text', 'form-number'));
+  _form_set_class($element, array('form-number'));
 
   $output = '<input' . drupal_attributes($element['#attributes']) . ' />';
 
-- 
1.7.7.5 (Apple Git-26)

