diff --git a/wire/modules/Fieldtype/FieldtypeFloat.module b/wire/modules/Fieldtype/FieldtypeFloat.module
index c650a8d0..fd571b6d 100644
--- a/wire/modules/Fieldtype/FieldtypeFloat.module
+++ b/wire/modules/Fieldtype/FieldtypeFloat.module
@@ -8,7 +8,7 @@
* For documentation about the fields used in this class, please see:
* /wire/core/Fieldtype.php
*
- * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
+ * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com
*
*/
@@ -19,90 +19,118 @@ class FieldtypeFloat extends Fieldtype {
return array(
'title' => __('Float', __FILE__),
'summary' => __('Field that stores a floating point (decimal) number', __FILE__),
- 'version' => 105,
+ 'version' => 106,
'permanent' => true,
- );
+ );
}
+ /**
+ * Get compatible Fieldtypes
+ *
+ * @param Field $field
+ * @return null|Fieldtypes
+ *
+ */
public function ___getCompatibleFieldtypes(Field $field) {
$fieldtypes = parent::___getCompatibleFieldtypes($field);
foreach($fieldtypes as $type) {
- if( !$type instanceof FieldtypeInteger &&
- !$type instanceof FieldtypeFloat &&
- $type != 'FieldtypeText') {
-
+ if(!$type instanceof FieldtypeInteger && !$type instanceof FieldtypeFloat && $type != 'FieldtypeText') {
$fieldtypes->remove($type);
}
}
return $fieldtypes;
}
+ /**
+ * Get blank value
+ *
+ * @param Page $page
+ * @param Field $field
+ * @return string
+ *
+ */
public function getBlankValue(Page $page, Field $field) {
return '';
}
+ /**
+ * Is given value considered empty to this Fieldtype?
+ *
+ * @param Field $field
+ * @param mixed $value
+ * @return bool
+ *
+ */
public function isEmptyValue(Field $field, $value) {
- if(($value === "0" || $value === 0 || $value === "0.0" || $value === 0.0) && $field->zeroNotEmpty) {
+ if($value === "0" || $value === 0 || $value === "0.0" || $value === 0.0) {
// when zeroNotEmpty option is set, we don't count a literal "0" is being a blank value
- return false;
+ if($field->get('zeroNotEmpty')) return false;
}
return empty($value);
}
+ /**
+ * Sanitize value
+ *
+ * @param Page $page
+ * @param Field $field
+ * @param float|int|string $value
+ * @return float|string
+ *
+ */
public function sanitizeValue(Page $page, Field $field, $value) {
if(!strlen("$value")) return '';
if(!is_float($value) && !is_int($value)) {
- $value = $this->wire('sanitizer')->float((string) $value, array('blankValue' => ''));
+ $value = $this->wire()->sanitizer->float((string) $value, array('blankValue' => ''));
}
- if(is_null($field->precision)) {
+ $precision = $field->get('precision');
+ if($precision === null || $precision === '') {
$value = (float) $value;
} else {
- $value = round((float) $value, $field->precision);
+ $value = round((float) $value, $precision);
}
return $value;
}
- /*
- public function formatValue(Page $page, Field $field, $value) {
- // @todo add support for number_format options
- return $value;
- }
- */
-
+ /**
+ * Get Inputfield for this Fieldtype
+ *
+ * @param Page $page
+ * @param Field $field
+ * @return Inputfield
+ *
+ */
public function getInputfield(Page $page, Field $field) {
- $inputfield = $this->modules->get('InputfieldFloat');
- $inputfield->class = $this->className();
- $inputfield->precision = $field->precision;
+ /** @var InputfieldFloat $inputfield */
+ $inputfield = $this->wire()->modules->get('InputfieldFloat');
+ $inputfield->addClass($this->className());
+ $inputfield->precision = $field->get('precision');
return $inputfield;
}
+ /**
+ * Sleep value for DB storage
+ *
+ * @param Page $page
+ * @param Field $field
+ * @param string|float|int
+ * @return string
+ *
+ */
public function ___sleepValue(Page $page, Field $field, $value) {
- $precision = $field->precision;
- if(is_null($precision)) $precision = self::getPrecision($value);
+ $precision = $field->get('precision');
+ if(is_null($precision) || $precision === '') $precision = self::getPrecision($value);
if(!is_string($value)) $value = number_format($value, $precision, '.', '');
-
- /*
-
- // handle commas vs. dots issue with other locales
- $info = localeconv();
-
- if(!empty($info['mon_thousands_sep'])) {
- if(strpos($value, $info["mon_thousands_sep"]) !== false) {
- $value = str_replace($info["mon_thousands_sep"] , "", $value);
- }
- }
-
- if(!empty($info['mon_decimal_point'])) {
- if($info["mon_decimal_point"] !== '.' && strpos($value, $info["mon_decimal_point"]) !== false) {
- $value = str_replace($info["mon_decimal_point"] , ".", $value);
- }
- }
-
- $value = floatval($value);
- */
return $value;
}
-
+
+ /**
+ * Get precision of given value
+ *
+ * @param string|float $value
+ * @return int
+ *
+ */
public static function getPrecision($value) {
$value = (float) $value;
$remainder = ceil($value) - $value;
@@ -111,31 +139,67 @@ class FieldtypeFloat extends Fieldtype {
return $precision;
}
+ /**
+ * Get DB schema for this Fieldtype
+ *
+ * @param Field $field
+ * @return array
+ *
+ */
public function getDatabaseSchema(Field $field) {
$schema = parent::getDatabaseSchema($field);
$schema['data'] = 'float NOT NULL';
return $schema;
}
+ /**
+ * Get field configuration
+ *
+ * @param Field $field
+ * @return InputfieldWrapper
+ *
+ */
public function ___getConfigInputfields(Field $field) {
$inputfields = parent::___getConfigInputfields($field);
-
- if(is_null($field->precision)) $field->precision = 2;
+ $precision = $field->get('precision');
+ if($precision === null) $precision = 2;
/** @var InputfieldInteger $f */
- $f = $this->modules->get('InputfieldInteger');
+ $f = $this->wire()->modules->get('InputfieldInteger');
$f->attr('name', 'precision');
$f->label = $this->_('Number of decimal digits to round to');
- $f->attr('value', $field->precision);
+ if($precision !== '') $f->val($precision);
$f->attr('size', 8);
$inputfields->append($f);
-
- $f = $this->wire('modules')->get('FieldtypeInteger')->___getConfigInputfields($field)->getChildByName('zeroNotEmpty');
+
+ /** @var FieldtypeInteger $ft */
+ $ft = $this->wire()->modules->get('FieldtypeInteger');
+ // use the same 'zeroNotEmpty' setting as FieldtypeInteger
+ $f = $ft->___getConfigInputfields($field)->getChildByName('zeroNotEmpty');
if($f) $inputfields->add($f);
return $inputfields;
}
+ /**
+ * Convert float string with commas to float value
+ *
+ * @param string $str
+ * @return float|string
+ * @deprecated Use $sanitizer->float($value, [ 'blankValue' = '' ]) instead
+ *
+ */
+ public static function strToFloat($str) {
+ return wire('sanitizer')->float($str, array('blankValue' => ''));
+ }
+
+ /*
+ public function formatValue(Page $page, Field $field, $value) {
+ // @todo add support for number_format options
+ return $value;
+ }
+ */
+
/*
public function getMatchQuery($query, $table, $subfield, $operator, $value) {
if(!is_int($value) && !is_float($value)) {
@@ -145,19 +209,6 @@ class FieldtypeFloat extends Fieldtype {
}
*/
- /**
- * Convert float string with commas to float value
- *
- * Most based on: http://php.net/manual/en/function.floatval.php#114486
- *
- * @param string $str
- * @return float|string
- * @deprecated
- *
- */
- public static function strToFloat($str) {
- return wire('sanitizer')->float($str, array('blankValue' => ''));
- }
}
diff --git a/wire/modules/Fieldtype/FieldtypeInteger.module b/wire/modules/Fieldtype/FieldtypeInteger.module
index b00a59ac..8a17b1dd 100644
--- a/wire/modules/Fieldtype/FieldtypeInteger.module
+++ b/wire/modules/Fieldtype/FieldtypeInteger.module
@@ -8,7 +8,7 @@
* For documentation about the fields used in this class, please see:
* /wire/core/Fieldtype.php
*
- * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
+ * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
* https://processwire.com
*
* @todo allow for more integer types (tiny, small, medium, big) and unsigned option
@@ -20,25 +20,37 @@ class FieldtypeInteger extends Fieldtype {
public static function getModuleInfo() {
return array(
'title' => 'Integer',
- 'version' => 101,
+ 'version' => 102,
'summary' => 'Field that stores an integer',
'permanent' => true,
- );
+ );
}
+ /**
+ * Get compatible Fieldtypes
+ *
+ * @param Field $field
+ * @return Fieldtypes
+ *
+ */
public function ___getCompatibleFieldtypes(Field $field) {
$fieldtypes = parent::___getCompatibleFieldtypes($field);
foreach($fieldtypes as $type) {
- if( !$type instanceof FieldtypeInteger &&
- !$type instanceof FieldtypeFloat &&
- $type != 'FieldtypeText') {
-
+ if(!$type instanceof FieldtypeInteger && !$type instanceof FieldtypeFloat && $type != 'FieldtypeText') {
$fieldtypes->remove($type);
}
}
return $fieldtypes;
}
-
+
+ /**
+ * Is given value considered empty by this Fieldtype?
+ *
+ * @param Field $field
+ * @param mixed $value
+ * @return bool
+ *
+ */
public function isEmptyValue(Field $field, $value) {
if(($value === "0" || $value === 0) && $field->get('zeroNotEmpty')) {
// when zeroNotEmpty option is set, we don't count a literal "0" is being a blank value
@@ -46,90 +58,154 @@ class FieldtypeInteger extends Fieldtype {
}
return empty($value);
}
-
+
+ /**
+ * Is value one that should be deleted rather than stored in the DB?
+ *
+ * @param Page $page
+ * @param Field $field
+ * @param mixed $value
+ * @return bool
+ *
+ */
public function isDeleteValue(Page $page, Field $field, $value) {
return $this->isEmptyValue($field, $value);
}
+ /**
+ * Get the blank value for this Fieldtype
+ *
+ * @param Page $page
+ * @param Field $field
+ * @return string
+ *
+ */
public function getBlankValue(Page $page, Field $field) {
return '';
}
-
+
+ /**
+ * Sanitize value to integer or blank string (for no value)
+ *
+ * @param Page $page
+ * @param Field $field
+ * @param int|string|mixed $value
+ * @return int|string
+ *
+ */
public function sanitizeValue(Page $page, Field $field, $value) {
if(is_string($value) && strlen($value) && !ctype_digit(ltrim($value, '-'))) {
- // string value with one or more non-digit characters
- $value = trim($value);
- // trim off common currency symbols
- $value = trim($value, '$€ ');
-
- if(ctype_digit("$value")) {
- // trimming reduced it to an int
-
- } else if(preg_match('/^(\de\d|0x\d+|\+\d+)/', $value)) {
- // likely a valid number, but in a non-native format to PW
- // examples: 1e123213, 0x1234, +123 (intval handles these)
- $value = intval($value);
-
- } else if(preg_match('/^[^-+\d.]+/', $value)) {
- // string starting with something we don't recognize, let PHP decide
- // example: bd#79
- $value = intval($value);
- if($value === 0) $value = ''; // blank rather than zero
-
- } else {
- // string value that looks like a number but has some other stuff in it
-
- // see if there are some definitely non-number chars in there, and truncate
- // the string to that point if we find any
- if(preg_match('/^(-?[\d,. ]+)([^\d,. ]+)/', $value, $matches)) {
- $value = $matches[1];
- }
-
- // check to see if we're dealing with a potential float val or thousands separators
- if(strpos($value, '.') !== false || strpos($value, ',') !== false || strpos($value, ' ') !== false) {
- // convert float values to rounded integers
- // also handles values with thousands separators
- $value = round(FieldtypeFloat::strToFloat($value));
-
- } else if(is_numeric($value)) {
- // let PHP decide how to convert it
- $value = intval($value);
-
- } else {
- // default: replace non numeric characters
- $negative = substr(trim($value), 0, 1) == '-';
- $value = preg_replace('/[^\d]/', '', $value);
- $value = strlen($value) ? (int) $value : '';
- if($negative && is_int($value)) $value = $value * -1;
- }
- }
+ $value = $this->sanitizeValueString($value);
+ } else {
+ $value = strlen("$value") ? (int) $value : '';
}
-
- $value = strlen("$value") ? (int) $value : '';
return $value;
}
+ /**
+ * Sanitize string to integer or blank string if empty
+ *
+ * @param string $value
+ * @return int|string
+ *
+ */
+ protected function sanitizeValueString($value) {
+
+ // string value with one or more non-digit characters
+ $value = trim($value);
+
+ // trim off common currency symbols
+ $value = trim($value, '$€ ');
+
+ if(ctype_digit("$value")) {
+ // trimming reduced it to an int
+
+ } else if(preg_match('/^(\de\d|0x\d+|\+\d+)/', $value)) {
+ // likely a valid number, but in a non-native format to PW
+ // examples: 1e123213, 0x1234, +123 (intval handles these)
+ $value = intval($value);
+
+ } else if(preg_match('/^[^-+\d.]+/', $value)) {
+ // string starting with something we don't recognize, let PHP decide
+ // example: bd#79
+ $value = intval($value);
+ if($value === 0) $value = ''; // blank rather than zero
+
+ } else {
+ // string value that looks like a number but has some other stuff in it
+
+ // see if there are some definitely non-number chars in there, and truncate
+ // the string to that point if we find any
+ if(preg_match('/^(-?[\d,. ]+)([^\d,. ]+)/', $value, $matches)) {
+ $value = $matches[1];
+ }
+
+ // check to see if we're dealing with a potential float val or thousands separators
+ if(strpos($value, '.') !== false || strpos($value, ',') !== false || strpos($value, ' ') !== false) {
+ // convert float values to rounded integers
+ // also handles values with thousands separators
+ $value = $this->wire()->sanitizer->float($value, array('blankValue' => ''));
+ if($value !== '') $value = round($value);
+
+ } else if(is_numeric($value)) {
+ // let PHP decide how to convert it
+ $value = intval($value);
+
+ } else {
+ // default: replace non numeric characters
+ $negative = substr(trim($value), 0, 1) == '-';
+ $value = preg_replace('/[^\d]/', '', $value);
+ $value = strlen($value) ? (int) $value : '';
+ if($negative && is_int($value)) $value = $value * -1;
+ }
+ }
+
+ return strlen("$value") ? (int) $value : '';
+ }
+
+ /**
+ * Get Inputfield for this Fieldtype
+ *
+ * @param Page $page
+ * @param Field $field
+ * @return Inputfield|InputfieldInteger
+ *
+ */
public function getInputfield(Page $page, Field $field) {
/** @var InputfieldInteger $inputfield */
- $inputfield = $this->modules->get('InputfieldInteger');
- $inputfield->class = $this->className();
+ $inputfield = $this->wire()->modules->get('InputfieldInteger');
+ $inputfield->addClass($this->className());
return $inputfield;
}
+ /**
+ * Get DB schema
+ *
+ * @param Field $field
+ * @return array
+ *
+ */
public function getDatabaseSchema(Field $field) {
$schema = parent::getDatabaseSchema($field);
$schema['data'] = 'int NOT NULL';
return $schema;
}
-
+
+ /**
+ * Get Inputfields to configure integer field
+ *
+ * @param Field $field
+ * @return InputfieldWrapper
+ *
+ */
public function ___getConfigInputfields(Field $field) {
$inputfields = parent::___getConfigInputfields($field);
/** @var InputfieldRadios $f */
- $f = $this->wire('modules')->get('InputfieldRadios');
+ $f = $this->wire()->modules->get('InputfieldRadios');
$f->label = $this->_('Are blank and 0 equivalent?');
$f->description = $this->_('This affects how ProcessWire matches pages during database find operations.') . ' ' .
$this->_('If 0 and blank are equivalent (the Yes option) then a search for **field=0** or **field=""** will produce the same results.') . ' ' .
@@ -142,7 +218,7 @@ class FieldtypeInteger extends Fieldtype {
$inputfields->add($f);
/** @var InputfieldInteger $f */
- $f = $this->wire('modules')->get('InputfieldInteger');
+ $f = $this->wire()->modules->get('InputfieldInteger');
$f->attr('name', 'defaultValue');
$f->label = $this->_('Default value');
$f->description = $this->_('This value is assigned as the default for this field on newly created pages. It does not affect existing pages.');
diff --git a/wire/modules/Inputfield/InputfieldFloat.module b/wire/modules/Inputfield/InputfieldFloat.module
index 4723b8f6..0302bd4b 100644
--- a/wire/modules/Inputfield/InputfieldFloat.module
+++ b/wire/modules/Inputfield/InputfieldFloat.module
@@ -2,8 +2,19 @@
/**
* Inputfield for floating point numbers
+ *
+ * ProcessWire 3.x, Copyright 2020 by Ryan Cramer
+ * https://processwire.com
*
* @property int $precision
+ * @property string $inputType Input type to use, one of "text" or "number"
+ * @property int|float $min
+ * @property int|float $max
+ * @property int|float|string $step
+ * @property int $size
+ * @property string $placeholder
+ * @property int|float $initValue Initial/default value (when used as independent Inputfield)
+ * @property int|float|string $defaultValue Initial/default value (when used with FieldtypeInteger)
*
*/
@@ -13,76 +24,130 @@ class InputfieldFloat extends InputfieldInteger {
return array(
'title' => __('Float', __FILE__), // Module Title
'summary' => __('Floating point number with precision', __FILE__), // Module Summary
- 'version' => 103,
+ 'version' => 104,
'permanent' => true,
- );
+ );
}
+ /**
+ * Construct
+ *
+ */
public function __construct() {
$this->set('precision', 2);
parent::__construct();
}
+ /**
+ * Module init
+ *
+ */
public function init() {
parent::init();
$this->attr('step', 'any'); // HTML5 attr required to support decimals with 'number' types
}
- protected function sanitizeValue($value) {
- if(!is_float($value) && !is_int($value)) {
- $value = FieldtypeFloat::strToFloat((string) $value);
- }
- $precision = $this->precision;
- if(is_null($precision)) $precision = FieldtypeFloat::getPrecision($value);
- return strlen("$value") ? round((float) $value, $precision) : '';
+ /**
+ * Get configured precision setting, or if given a value, precision of the value
+ *
+ * @param float|string|null $value
+ * @return int|string Returns integer of precision or blank string if none defined
+ *
+ */
+ protected function getPrecision($value = null) {
+ if($value !== null) return FieldtypeFloat::getPrecision($value);
+ $precision = $this->precision;
+ return $precision === null || $precision === '' ? '' : (int) $precision;
}
/**
- * Returns true if number is in valid range, false if not
- *
- * Overriding the function from InputfieldInteger to ensure float types (rather than int types) are used
+ * Sanitize value
*
- * @param float $value
- * @return bool
+ * @param float|string $value
+ * @return float|string
+ *
+ */
+ protected function sanitizeValue($value) {
+ if(!strlen("$value")) return '';
+ if(!is_float($value) && !is_int($value)) {
+ $value = $this->wire()->sanitizer->float($value, array('blankValue' => ''));
+ if(!strlen("$value")) return '';
+ }
+ $precision = $this->precision;
+ if($precision === null || $precision === '') {
+ $precision = FieldtypeFloat::getPrecision($value);
+ }
+ return round((float) $value, $precision);
+ }
+
+ /**
+ * Typecast value to float, override from InputfieldInteger
+ *
+ * @param string|int|float $value
+ * @return int
*
*/
- protected function isInRange($value) {
- $inRange = true;
- $min = $this->attr('min');
- $max = $this->attr('max');
- if(strlen("$value")) {
- if(strlen("$min") && ((float) $value) < ((float) $min)) {
- $inRange = false;
- }
- if(strlen("$max") && ((float) $value) > ((float) $max)) {
- $inRange = false;
- }
- }
- return $inRange;
+ protected function typeValue($value) {
+ return (float) $value;
}
/**
- * Override method from Inputfield to properly handle HTML5 number values
+ * Override method from Inputfield to convert local specific decimals for input[type=number]
*
* @param array $attributes
* @return string
*
*/
public function getAttributesString(array $attributes = null) {
- if($attributes && $attributes['type'] === 'number' && is_float($attributes['value'])) {
- if(strlen("$attributes[value]") && !ctype_digit(str_replace('.', '', $attributes['value']))) {
+ if($attributes && $attributes['type'] === 'number') {
+ $value = isset($attributes['value']) ? $attributes['value'] : null;
+ if(is_float($value) && strlen("$value") && !ctype_digit(str_replace('.', '', $value))) {
+ // float value is using a non "." as decimal point, needs conversion because
// the HTML5 number input type requires "." as the decimal
- $locale = localeconv();
- $decimal = $locale['decimal_point'];
- if($decimal !== '.' && strpos("$attributes[value]", $decimal) !== false) {
- $parts = explode($decimal, $attributes['value'], 2);
- if(count($parts) == 2) {
- $attributes['value'] = implode('.', $parts);
- }
- }
+ $attributes['value'] = $this->localeConvertValue($value);
}
}
return parent::getAttributesString($attributes);
}
+ /**
+ * Convert floats with non "." decimal points to use "." decimal point according to locale
+ *
+ * @param float|string $value
+ * @return string|float Returns string representation of float when value was converted
+ *
+ */
+ protected function localeConvertValue($value) {
+ if(!strlen("$value")) return $value;
+ if(ctype_digit(str_replace('.', '', $value))) return $value;
+ $locale = localeconv();
+ $decimal = $locale['decimal_point'];
+ if($decimal === '.' || strpos($value, $decimal) === false) return $value;
+ $parts = explode($decimal, $value, 2);
+ $value = implode('.', $parts);
+ return $value;
+ }
+
+ /**
+ * Inputfield config
+ *
+ * @return InputfieldWrapper
+ *
+ */
+ public function getConfigInputfields() {
+ $inputfields = parent::getConfigInputfields();
+ if($this->hasFieldtype === false) {
+ /** @var InputfieldInteger $f */
+ $f = $this->wire()->modules->get('InputfieldInteger');
+ $f->attr('name', 'precision');
+ $f->label = $this->_('Number of decimal digits to round to');
+ $f->attr('value', $this->precision);
+ $f->attr('size', 8);
+ $inputfields->add($f);
+ } else {
+ // precision is configured with FieldtypeFloat
+ }
+ return $inputfields;
+ }
+
}
diff --git a/wire/modules/Inputfield/InputfieldInteger.module b/wire/modules/Inputfield/InputfieldInteger.module
index 7656c2ae..375225b2 100644
--- a/wire/modules/Inputfield/InputfieldInteger.module
+++ b/wire/modules/Inputfield/InputfieldInteger.module
@@ -1,13 +1,19 @@
__('Integer', __FILE__), // Module Title
'summary' => __('Integer (positive or negative)', __FILE__), // Module Summary
- 'version' => 104,
+ 'version' => 105,
'permanent' => true,
- );
+ );
}
+ /**
+ * Module init
+ *
+ */
public function init() {
parent::init();
- $this->set('inputType', 'text');
+
$this->attr('type', 'text');
- $this->attr('min', ''); // blank means not set
- $this->attr('max', ''); // blank means not set
+ $this->attr('min', '');
+ $this->attr('max', '');
+ $this->attr('step', '');
$this->attr('size', '10');
+ $this->attr('placeholder', '');
+
+ $this->set('inputType', 'text');
$this->set('initValue', '');
$this->set('defaultValue', '');
}
+ /**
+ * Render Inputfield
+ *
+ * @return string
+ *
+ */
public function ___render() {
+
if(!$this->attr('type')) $this->attr('type', 'text');
+
$attrs = $this->getAttributes();
- $note = '';
if(empty($attrs['size'])) {
$attrs['class'] = (isset($attrs['class']) ? "$attrs[class] " : "") . 'InputfieldMaxWidth';
unset($attrs['size']);
}
- if(!strlen("$attrs[min]") && !strlen("$attrs[max]")) {
- // if both min+max are empty, then consider them non-applicable
- unset($attrs['min'], $attrs['max']);
+ if($attrs['type'] === 'text') {
+ // input[type=text] unset attributes not applicable
+ unset($attrs['step'], $attrs['min'], $attrs['max']);
} else {
- // unset any that aren't applicable
- if(strlen("$attrs[min]")) $note .= sprintf($this->_('Min: %d'), $attrs['min']);
- else unset($attrs['min']);
- if(strlen("$attrs[max]")) $note .= ($note ? ', ' : '') . sprintf($this->_('Max: %d'), $attrs['max']);
- else unset($attrs['max']);
+ // input[type=number] unset any that aren't applicable
+ foreach(array('min', 'max', 'step') as $name) {
+ if(!strlen((string) $attrs[$name])) unset($attrs[$name]);
+ }
}
- // these attributes not valid for 'text' type
- if($attrs['type'] == 'text') unset($attrs['step'], $attrs['min'], $attrs['max']);
-
- if($note) $note = " $note";
-
if(!strlen($attrs['value'])) {
if(strlen($this->initValue)) {
$attrs['value'] = (int) $this->initValue; // Inputfield-only version
@@ -67,76 +82,125 @@ class InputfieldInteger extends Inputfield {
}
}
- $out = "getAttributesString($attrs) . " />"; // . $note;
+ $out = "getAttributesString($attrs) . " />";
return $out;
}
+ /**
+ * Sanitize value
+ *
+ * @param string|int|float $value
+ * @return int
+ *
+ */
protected function sanitizeValue($value) {
+ if(is_int($value)) return $value;
$value = trim($value);
if(!strlen("$value")) return '';
$negative = substr($value, 0, 1) === '-';
- if($negative) $value = substr($value, 1);
- if(!ctype_digit("$value")) $value = preg_replace('/[^\d,.]/', '', $value); // remove non digits, like commas, etc.
+ if($negative) $value = substr($value, 1);
+ // remove non digits, except commas and periods
+ if(!ctype_digit("$value")) $value = preg_replace('/[^\d,.]/', '', $value);
if(!strlen("$value")) return '';
- if(strpos($value, '.') !== false || strpos($value, ',') !== false) $value = round($value);
+ if(strpos($value, '.') !== false || strpos($value, ',') !== false) $value = round((float) $value);
$value = (int) $value;
if($negative) $value = -1 * $value;
return $value;
}
+ /**
+ * Typecast value to integer
+ *
+ * @param string|int|float $value
+ * @return int
+ *
+ */
+ protected function typeValue($value) {
+ return (int) $value;
+ }
+
+ /**
+ * Is current value considered empty?
+ *
+ * @return bool
+ *
+ */
public function isEmpty() {
- return strlen("{$this->value}") === 0;
+ $value = $this->val();
+ return strlen("$value") === 0;
}
+ /**
+ * Is current value in specified min/max range?
+ *
+ * @param int $value
+ * @return bool
+ *
+ */
protected function isInRange($value) {
- $inRange = true;
- $min = $this->attr('min');
- $max = $this->attr('max');
- if(strlen("$value")) {
- if(strlen("$min") && ((int) $value) < ((int) $min)) {
- $inRange = false;
- }
- if(strlen("$max") && ((int) $value) > ((int) $max)) {
- $inRange = false;
- }
- }
- return $inRange;
+ if(!strlen("$value")) return true; // no value present yet
+ list($min, $max) = array($this->attr('min'), $this->attr('max'));
+ if(strlen("$min") && ($this->typeValue($value)) < ($this->typeValue($min))) return false;
+ if(strlen("$max") && ($this->typeValue($value)) > ($this->typeValue($max))) return false;
+ return true;
}
+ /**
+ * Set attribute
+ *
+ * @param array|string $key
+ * @param array|bool|int|string $value
+ * @return Inputfield
+ *
+ */
public function setAttribute($key, $value) {
- if($key == 'value') {
+ if($key === 'value') {
$value = $this->sanitizeValue($value);
if(strlen("$value") && !$this->isInRange($value)) {
$min = $this->attr('min');
$max = $this->attr('max');
- $any = $this->_('any');
+ $any = $this->_('any'); // referring to “any” minimum or maximum number
if(!strlen("$min")) $min = $any;
if(!strlen("$max")) $max = $any;
$this->error(sprintf($this->_('Specified value %3$s removed because it is out of bounds (min=%1$s, max=%2$s)'), $min, $max, $value));
- $value = $this->attr('value'); // restore previous value
+ $value = $this->val(); // restore previous value
+ }
+ } else if($key === 'min' || $key === 'max') {
+ if(strlen("$value")) {
+ $value = strpos("$value", '.') !== false ? (float) $value : (int) $value;
}
}
return parent::setAttribute($key, $value);
}
-
+
+ /**
+ * Set setting or attribute
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return Inputfield|WireData
+ *
+ */
public function set($key, $value) {
- if($key == 'inputType') {
- $this->attr('type', $value);
- } else if($key == 'min' || $key == 'max') {
- if(strlen("$value")) {
- $value = strpos($value, '.') !== false ? (float) $value : (int) $value;
- }
- }
+ if($key === 'inputType') $this->attr('type', $value);
return parent::set($key, $value);
}
+ /**
+ * Inputfield configuration
+ *
+ * @return InputfieldWrapper
+ *
+ */
public function getConfigInputfields() {
$inputfields = parent::getConfigInputfields();
-
- $f = $this->wire('modules')->get('InputfieldRadios');
+ $modules = $this->wire()->modules;
+
+ /** @var InputfieldRadios $f */
+ $f = $modules->get('InputfieldRadios');
$f->attr('name', 'inputType');
$f->label = $this->_('Numeric Input Type');
$f->addOption('text', $this->_('Text'));
@@ -145,8 +209,9 @@ class InputfieldInteger extends Inputfield {
$f->description = $this->_('Choosing the "Number" type enables some additional client-side validation in browsers that support it.');
$f->columnWidth = 50;
$inputfields->add($f);
-
- $f = $this->wire('modules')->get('InputfieldInteger');
+
+ /** @var InputfieldInteger $f */
+ $f = $modules->get('InputfieldInteger');
$f->attr('name', 'size');
$f->label = $this->_('Input Size');
$f->description = $this->_('Specify the size attribute for the input, or specify 0 for full width.');
@@ -157,7 +222,8 @@ class InputfieldInteger extends Inputfield {
$f->attr('type', 'number');
$inputfields->add($f);
- $f = $this->wire('modules')->get('InputfieldText');
+ /** @var InputfieldText $f */
+ $f = $modules->get('InputfieldText');
$f->attr('name', 'min');
$f->attr('value', $this->attr('min'));
$f->label = $this->_('Minimum Value');
@@ -165,7 +231,7 @@ class InputfieldInteger extends Inputfield {
$f->columnWidth = 50;
$inputfields->add($f);
- $f = $this->wire('modules')->get('InputfieldText');
+ $f = $modules->get('InputfieldText');
$f->attr('name', 'max');
$f->attr('value', $this->attr('max'));
$f->label = $this->_('Maximum Value');
@@ -174,7 +240,7 @@ class InputfieldInteger extends Inputfield {
$inputfields->add($f);
if($this->hasFieldtype === false) {
- $f = $this->wire('modules')->get('InputfieldText');
+ $f = $modules->get('InputfieldText');
$f->attr('name', 'initValue');
$f->attr('value', $this->initValue);
$f->label = $this->_('Initial value');