2022-03-08 15:55:41 +01:00
|
|
|
<?php namespace ProcessWire;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Integer Inputfield
|
|
|
|
*
|
2022-11-05 18:32:48 +01:00
|
|
|
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
2022-03-08 15:55:41 +01:00
|
|
|
* https://processwire.com
|
|
|
|
*
|
|
|
|
* @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)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
class InputfieldInteger extends Inputfield {
|
|
|
|
|
|
|
|
public static function getModuleInfo() {
|
|
|
|
return array(
|
|
|
|
'title' => __('Integer', __FILE__), // Module Title
|
|
|
|
'summary' => __('Integer (positive or negative)', __FILE__), // Module Summary
|
|
|
|
'version' => 105,
|
|
|
|
'permanent' => true,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Module init
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function init() {
|
|
|
|
parent::init();
|
|
|
|
|
|
|
|
$this->attr('type', 'text');
|
|
|
|
$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();
|
|
|
|
|
|
|
|
if(empty($attrs['size'])) {
|
|
|
|
$attrs['class'] = (isset($attrs['class']) ? "$attrs[class] " : "") . 'InputfieldMaxWidth';
|
|
|
|
unset($attrs['size']);
|
|
|
|
}
|
|
|
|
|
|
|
|
if($attrs['type'] === 'text') {
|
|
|
|
// input[type=text] unset attributes not applicable
|
|
|
|
unset($attrs['step'], $attrs['min'], $attrs['max']);
|
|
|
|
} else {
|
|
|
|
// input[type=number] unset any that aren't applicable
|
|
|
|
foreach(array('min', 'max', 'step') as $name) {
|
2024-04-04 14:37:20 +02:00
|
|
|
if(isset($attrs[$name]) && !strlen((string) $attrs[$name])) unset($attrs[$name]);
|
2022-03-08 15:55:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 14:37:20 +02:00
|
|
|
if(!strlen("$attrs[value]")) {
|
|
|
|
if(strlen("$this->initValue")) {
|
2022-03-08 15:55:41 +01:00
|
|
|
$attrs['value'] = (int) $this->initValue; // Inputfield-only version
|
2024-04-04 14:37:20 +02:00
|
|
|
} else if(strlen("$this->defaultValue")) {
|
2022-03-08 15:55:41 +01:00
|
|
|
$attrs['value'] = (int) $this->defaultValue; // Fieldtype version
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$out = "<input " . $this->getAttributesString($attrs) . " />";
|
|
|
|
|
|
|
|
return $out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sanitize value
|
|
|
|
*
|
|
|
|
* @param string|int|float $value
|
|
|
|
* @return int
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
protected function sanitizeValue($value) {
|
|
|
|
if(is_int($value)) return $value;
|
2022-11-05 18:32:48 +01:00
|
|
|
$value = (string) $value;
|
2022-03-08 15:55:41 +01:00
|
|
|
$value = trim($value);
|
|
|
|
if(!strlen("$value")) return '';
|
|
|
|
$negative = substr($value, 0, 1) === '-';
|
|
|
|
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((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() {
|
|
|
|
$value = $this->val();
|
|
|
|
return strlen("$value") === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is current value in specified min/max range?
|
|
|
|
*
|
|
|
|
* @param int $value
|
|
|
|
* @return bool
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
protected function isInRange($value) {
|
|
|
|
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') {
|
|
|
|
$value = $this->sanitizeValue($value);
|
|
|
|
if(strlen("$value") && !$this->isInRange($value)) {
|
|
|
|
$min = $this->attr('min');
|
|
|
|
$max = $this->attr('max');
|
|
|
|
$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->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);
|
|
|
|
return parent::set($key, $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Inputfield configuration
|
|
|
|
*
|
|
|
|
* @return InputfieldWrapper
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public function getConfigInputfields() {
|
|
|
|
$inputfields = parent::getConfigInputfields();
|
|
|
|
$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'));
|
|
|
|
$f->addOption('number', $this->_('Number (HTML5)'));
|
|
|
|
$f->attr('value', $this->inputType);
|
|
|
|
$f->description = $this->_('Choosing the "Number" type enables some additional client-side validation in browsers that support it.');
|
|
|
|
$f->columnWidth = 50;
|
|
|
|
$inputfields->add($f);
|
|
|
|
|
|
|
|
/** @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.');
|
|
|
|
$f->notes = sprintf($this->_('The default value is %d.'), $f->attr('size'));
|
|
|
|
$f->columnWidth = 50;
|
|
|
|
$f->attr('value', $this->attr('size'));
|
|
|
|
$f->attr('min', 0);
|
|
|
|
$f->attr('type', 'number');
|
|
|
|
$inputfields->add($f);
|
|
|
|
|
|
|
|
/** @var InputfieldText $f */
|
|
|
|
$f = $modules->get('InputfieldText');
|
|
|
|
$f->attr('name', 'min');
|
|
|
|
$f->attr('value', $this->attr('min'));
|
|
|
|
$f->label = $this->_('Minimum Value');
|
|
|
|
$f->description = $this->_('The minimum allowed value for this field. Leave blank to ignore.');
|
|
|
|
$f->columnWidth = 50;
|
|
|
|
$inputfields->add($f);
|
|
|
|
|
|
|
|
$f = $modules->get('InputfieldText');
|
|
|
|
$f->attr('name', 'max');
|
|
|
|
$f->attr('value', $this->attr('max'));
|
|
|
|
$f->label = $this->_('Maximum Value');
|
|
|
|
$f->description = $this->_('The maximum allowed value for this field. Leave blank to ignore.');
|
|
|
|
$f->columnWidth = 50;
|
|
|
|
$inputfields->add($f);
|
|
|
|
|
|
|
|
if($this->hasFieldtype === false) {
|
|
|
|
$f = $modules->get('InputfieldText');
|
|
|
|
$f->attr('name', 'initValue');
|
|
|
|
$f->attr('value', $this->initValue);
|
|
|
|
$f->label = $this->_('Initial value');
|
|
|
|
$f->description = $this->_('Initial assigned value.');
|
|
|
|
$f->collapsed = Inputfield::collapsedBlank;
|
|
|
|
$inputfields->add($f);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $inputfields;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|