egroupware/etemplate/inc/class.etemplate_widget_textbox.inc.php
Ralf Becker 63a7af621d allow to submit partial content by passing a container(-widget) to etemplate2.submit()
- not send content is not validated and therefore not passed to server-side callback (currently only implemented for text-, select- and checkbox)
- new method et2_grid.getRow(_widget) to return a fake row container to pass it etemplate2.submit() --> implemented a real row-container for et2_grid
- new output_mode=4 for etemplate_new::exec() to force a json response, like form was submitted from client-side
--> allows to use full server-side validation for ajax like calls submitting only partial content
2015-03-20 02:12:33 +00:00

196 lines
6.7 KiB
PHP

<?php
/**
* EGroupware - eTemplate serverside textbox widget
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
* @subpackage api
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker@outdoor-training.de>
* @copyright 2002-13 by RalfBecker@outdoor-training.de
* @version $Id$
*/
/**
* eTemplate textbox widget with following sub-types:
* - textbox with optional multiline="true" and rows="123"
* - integer or int
* - float
* - hidden
* - colorpicker
* - passwd (passwords are never send back to client, instead a number of asterisks is send and replaced again!)
* sub-types are either passed to constructor or set via 'type' attribute!
*/
class etemplate_widget_textbox extends etemplate_widget
{
/**
* Constructor
*
* @param string|XMLReader $xml string with xml or XMLReader positioned on the element to construct
* @throws egw_exception_wrong_parameter
*/
public function __construct($xml)
{
parent::__construct($xml);
// normalize types
if ($this->type !== 'textbox')
{
if ($this->type == 'int') $this->type = 'integer';
$this->attrs['type'] = $this->type;
$this->type = 'textbox';
}
}
/**
* Parse and set extra attributes from xml in template object
*
* Reimplemented to handle legacy read-only by setting size < 0
*
* @param string|XMLReader $xml
* @param boolean $cloned=true true: object does NOT need to be cloned, false: to set attribute, set them in cloned object
* @return etemplate_widget_template current object or clone, if any attribute was set
*/
public function set_attrs($xml, $cloned=true)
{
parent::set_attrs($xml, $cloned);
// Legacy handling only
// A negative size triggered the HTML readonly attibute, but not etemplate readonly,
// so you got an input element, but it was not editable.
if ($this->attrs['size'] < 0)
{
$this->setElementAttribute($this->id, 'size', abs($this->attrs['size']));
self::$request->readonlys[$this->id] = false;
$this->setElementAttribute($this->id, 'readonly', true);
trigger_error("Using a negative size to set textbox readonly. " .$this, E_USER_DEPRECATED);
}
return $this;
}
/**
* Set up what we know on the server side.
*
* @param string $cname
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
*/
public function beforeSendToClient($cname, array $expand=null)
{
// to NOT transmit passwords back to client, we need to store (non-empty) value in preserv
if ($this->attrs['type'] == 'passwd' || $this->type == 'passwd')
{
$form_name = self::form_name($cname, $this->id, $expand);
$value =& self::get_array(self::$request->content, $form_name);
if (!empty($value))
{
$preserv =& self::get_array(self::$request->preserv, $form_name, true);
if (true) $preserv = (string)$value;
$value = str_repeat('*', strlen($preserv));
}
}
}
/**
* Validate input
*
* Following attributes get checked:
* - needed: value must NOT be empty
* - min, max: int and float widget only
* - maxlength: maximum length of string (longer strings get truncated to allowed size)
* - validator: perl regular expression incl. delimiters (set by default for int, float and colorpicker)
* - int and float get casted to their type
*
* @param string $cname current namespace
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
* @param array $content
* @param array &$validated=array() validated content
* @param array $expand=array values for keys 'c', 'row', 'c_', 'row_', 'cont'
*/
public function validate($cname, array $expand, array $content, &$validated=array())
{
$form_name = self::form_name($cname, $this->id, $expand);
if (!$this->is_readonly($cname, $form_name))
{
if (!isset($this->attrs['validator']))
{
switch($this->type)
{
case 'int':
case 'integer':
$this->attrs['validator'] = '/^-?[0-9]*$/';
break;
case 'float':
$this->attrs['validator'] = '/^-?[0-9]*[,.]?[0-9]*$/';
break;
case 'colorpicker':
$this->attrs['validator'] = '/^(#[0-9a-f]{6}|)$/i';
break;
}
}
$value = $value_in = self::get_array($content, $form_name);
// passwords are not transmitted back to client (just asterisks)
// therefore we need to replace it again with preserved value
if (($this->attrs['type'] == 'passwd' || $this->type == 'passwd'))
{
$preserv = self::get_array(self::$request->preserv, $form_name);
if ($value == str_repeat('*', strlen($preserv)))
{
$value = $preserv;
}
}
if ((string)$value === '' && $this->attrs['needed'])
{
self::set_validation_error($form_name,lang('Field must not be empty !!!'),'');
}
if ((int) $this->attrs['maxlength'] > 0 && mb_strlen($value) > (int) $this->attrs['maxlength'])
{
$value = mb_substr($value,0,(int) $this->attrs['maxlength']);
}
if ($this->attrs['validator'] && !preg_match($this->attrs['validator'],$value))
{
switch($this->type)
{
case 'integer':
self::set_validation_error($form_name,lang("'%1' is not a valid integer !!!",$value),'');
break;
case 'float':
self::set_validation_error($form_name,lang("'%1' is not a valid floatingpoint number !!!",$value),'');
break;
default:
self::set_validation_error($form_name,lang("'%1' has an invalid format !!!",$value)/*." !preg_match('$this->attrs[validator]', '$value')"*/,'');
break;
}
}
elseif ($this->type == 'integer' || $this->type == 'float') // cast int and float and check range
{
if ((string)$value !== '' || $this->attrs['needed']) // empty values are Ok if needed is not set
{
$value = $this->type == 'integer' ? (int) $value : (float) str_replace(',','.',$value); // allow for german (and maybe other) format
if (!empty($this->attrs['min']) && $value < $this->attrs['min'])
{
self::set_validation_error($form_name,lang("Value has to be at least '%1' !!!",$this->attrs['min']),'');
$value = $this->type == 'integer' ? (int) $this->attrs['min'] : (float) $this->attrs['min'];
}
if (!empty($this->attrs['max']) && $value > $this->attrs['max'])
{
self::set_validation_error($form_name,lang("Value has to be at maximum '%1' !!!",$this->attrs['max']),'');
$value = $this->type == 'integer' ? (int) $this->attrs['max'] : (float) $this->attrs['max'];
}
}
}
if (isset($value))
{
self::set_array($validated, $form_name, $value);
//error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value));
}
}
}
}
etemplate_widget::registerWidget('etemplate_widget_textbox', array('textbox','text','int','integer','float','passwd','hidden','colorpicker','hidden'));